Geant4  10.01
UTriangularFacet.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * This Software is part of the AIDA Unified Solids Library package *
4 // * See: https://aidasoft.web.cern.ch/USolids *
5 // ********************************************************************
6 //
7 // $Id:$
8 //
9 // --------------------------------------------------------------------
10 //
11 // UTriangularFacet
12 //
13 // 22.08.12 Marek Gayer
14 // Created from original implementation in Geant4
15 // --------------------------------------------------------------------
16 
17 #include <sstream>
18 #include <algorithm>
19 
20 #include "UVector2.hh"
21 #include "UTessellatedSolid.hh"
22 #include "VUSolid.hh"
23 #include "UUtils.hh"
24 #include "UTriangularFacet.hh"
25 
26 using namespace std;
27 
29 //
30 // Definition of triangular facet using absolute vectors to vertices.
31 // From this for first vector is retained to define the facet location and
32 // two relative vectors (E0 and E1) define the sides and orientation of
33 // the outward surface normal.
34 //
35 UTriangularFacet::UTriangularFacet(const UVector3& vt0, const UVector3& vt1, const UVector3& vt2, UFacetVertexType vertexType)
36  : fSqrDist(0.)
37 {
38  fVertices = new vector<UVector3>(3);
39 
40  SetVertex(0, vt0);
41  if (vertexType == UABSOLUTE)
42  {
43  SetVertex(1, vt1);
44  SetVertex(2, vt2);
45  fE1 = vt1 - vt0;
46  fE2 = vt2 - vt0;
47  }
48  else
49  {
50  SetVertex(1, vt0 + vt1);
51  SetVertex(2, vt0 + vt2);
52  fE1 = vt1;
53  fE2 = vt2;
54  }
55 
56  for (int i = 0; i < 3; ++i) fIndices[i] = -1;
57 
58  double eMag1 = fE1.Mag();
59  double eMag2 = fE2.Mag();
60  double eMag3 = (fE2 - fE1).Mag();
61 
62  if (eMag1 <= kCarTolerance || eMag2 <= kCarTolerance || eMag3 <= kCarTolerance)
63  {
64  ostringstream message;
65  message << "Length of sides of facet are too small." << endl
66  << "P[0] = " << GetVertex(0) << endl
67  << "P[1] = " << GetVertex(1) << endl
68  << "P[2] = " << GetVertex(2) << endl
69  << "Side lengths = P[0]->P[1]" << eMag1 << endl
70  << "Side lengths = P[0]->P[2]" << eMag2 << endl
71  << "Side lengths = P[1]->P[2]" << eMag3;
72  UUtils::Exception("UTriangularFacet::UTriangularFacet()", "GeomSolids1001", Warning, 1, message.str().c_str());
73  fIsDefined = false;
75  fA = fB = fC = 0.0;
76  fDet = 0.0;
77  fArea = fRadius = 0.0;
78  }
79  else
80  {
81  fIsDefined = true;
83  fA = fE1.Mag2();
84  fB = fE1.Dot(fE2);
85  fC = fE2.Mag2();
86  fDet = fabs(fA * fC - fB * fB);
87 
88  // sMin = -0.5*kCarTolerance/sqrt(fA);
89  // sMax = 1.0 - sMin;
90  // tMin = -0.5*kCarTolerance/sqrt(fC);
91  // UVector3 vtmp = 0.25 * (fE1 + fE2);
92 
93  fArea = 0.5 * (fE1.Cross(fE2)).Mag();
94  double lambda0 = (fA - fB) * fC / (8.0 * fArea * fArea);
95  double lambda1 = (fC - fB) * fA / (8.0 * fArea * fArea);
96  UVector3 p0 = GetVertex(0);
97  fCircumcentre = p0 + lambda0 * fE1 + lambda1 * fE2;
98  double radiusSqr = (fCircumcentre - p0).Mag2();
99  fRadius = sqrt(radiusSqr);
100  }
101 }
102 
103 
105  : fSqrDist(0.)
106 {
107  fVertices = new vector<UVector3>(3);
108  UVector3 zero(0, 0, 0);
109  SetVertex(0, zero);
110  SetVertex(1, zero);
111  SetVertex(2, zero);
112  for (int i = 0; i < 3; ++i) fIndices[i] = -1;
113  fIsDefined = false;
114  fSurfaceNormal.Set(0);
115  fA = fB = fC = 0;
116  fE1 = zero;
117  fE2 = zero;
118  fDet = 0.0;
119  fArea = fRadius = 0;
120 }
121 
123 {
124  SetVertices(NULL);
125 }
126 
127 
129 {
130  char* p = (char*) &rhs;
131  copy(p, p + sizeof(*this), (char*)this);
132 
133  if (fIndices[0] < 0 && fVertices)
134  {
135  fVertices = new vector<UVector3>(3);
136  for (int i = 0; i < 3; ++i)(*fVertices)[i] = (*rhs.fVertices)[i];
137  }
138  fIsDefined = rhs.fIsDefined;
140  fA = rhs.fA; fB = rhs.fB; fC = rhs.fC;
141  fE1 = rhs.fE1;
142  fE2 = rhs.fE2;
143  fDet = rhs.fDet;
144  fArea = rhs.fArea;
145  fRadius = rhs.fRadius;
146  fSqrDist = rhs.fSqrDist;
147 }
148 
150 {
151  CopyFrom(rhs);
152 }
153 
155 {
156  SetVertices(NULL);
157 
158  if (this != &rhs)
159  CopyFrom(rhs);
160 
161  return *this;
162 }
163 
165 //
166 // GetClone
167 //
168 // Simple member function to generate fA duplicate of the triangular facet.
169 //
171 {
173  return fc;
174 }
175 
177 //
178 // GetFlippedFacet
179 //
180 // Member function to generate an identical facet, but with the normal vector
181 // pointing at 180 degrees.
182 //
184 {
186  return flipped;
187 }
188 
190 //
191 // Distance (UVector3)
192 //
193 // Determines the vector between p and the closest point on the facet to p.
194 // This is based on the algorithm published in "Geometric Tools for Computer
195 // Graphics," Philip J Scheider and David H Eberly, Elsevier Science (USA),
196 // 2003. at the time of writing, the algorithm is also available in fA
197 // technical note "Distance between point and triangle in 3D," by David Eberly
198 // at http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
199 //
200 // The by-product is the square-distance fSqrDist, which is retained
201 // in case needed by the other "Distance" member functions.
202 //
204 {
205  UVector3 D = GetVertex(0) - p;
206  double d = fE1.Dot(D);
207  double e = fE2.Dot(D);
208  double f = D.Mag2();
209  double q = fB * e - fC * d;
210  double t = fB * d - fA * e;
211  fSqrDist = 0.;
212 
213  if (q + t <= fDet)
214  {
215  if (q < 0.0)
216  {
217  if (t < 0.0)
218  {
219  //
220  // We are in region 4.
221  //
222  if (d < 0.0)
223  {
224  t = 0.0;
225  if (-d >= fA)
226  {
227  q = 1.0;
228  fSqrDist = fA + 2.0 * d + f;
229  }
230  else
231  {
232  q = -d / fA;
233  fSqrDist = d * q + f;
234  }
235  }
236  else
237  {
238  q = 0.0;
239  if (e >= 0.0)
240  {
241  t = 0.0;
242  fSqrDist = f;
243  }
244  else if (-e >= fC)
245  {
246  t = 1.0;
247  fSqrDist = fC + 2.0 * e + f;
248  }
249  else
250  {
251  t = -e / fC;
252  fSqrDist = e * t + f;
253  }
254  }
255  }
256  else
257  {
258  //
259  // We are in region 3.
260  //
261  q = 0.0;
262  if (e >= 0.0)
263  {
264  t = 0.0;
265  fSqrDist = f;
266  }
267  else if (-e >= fC)
268  {
269  t = 1.0;
270  fSqrDist = fC + 2.0 * e + f;
271  }
272  else
273  {
274  t = -e / fC;
275  fSqrDist = e * t + f;
276  }
277  }
278  }
279  else if (t < 0.0)
280  {
281  //
282  // We are in region 5.
283  //
284  t = 0.0;
285  if (d >= 0.0)
286  {
287  q = 0.0;
288  fSqrDist = f;
289  }
290  else if (-d >= fA)
291  {
292  q = 1.0;
293  fSqrDist = fA + 2.0 * d + f;
294  }
295  else
296  {
297  q = -d / fA;
298  fSqrDist = d * q + f;
299  }
300  }
301  else
302  {
303  //
304  // We are in region 0.
305  //
306  q = q / fDet;
307  t = t / fDet;
308  fSqrDist = q * (fA * q + fB * t + 2.0 * d) + t * (fB * q + fC * t + 2.0 * e) + f;
309  }
310  }
311  else
312  {
313  if (q < 0.0)
314  {
315  //
316  // We are in region 2.
317  //
318  double tmp0 = fB + d;
319  double tmp1 = fC + e;
320  if (tmp1 > tmp0)
321  {
322  double numer = tmp1 - tmp0;
323  double denom = fA - 2.0 * fB + fC;
324  if (numer >= denom)
325  {
326  q = 1.0;
327  t = 0.0;
328  fSqrDist = fA + 2.0 * d + f;
329  }
330  else
331  {
332  q = numer / denom;
333  t = 1.0 - q;
334  fSqrDist = q * (fA * q + fB * t + 2.0 * d) + t * (fB * q + fC * t + 2.0 * e) + f;
335  }
336  }
337  else
338  {
339  q = 0.0;
340  if (tmp1 <= 0.0)
341  {
342  t = 1.0;
343  fSqrDist = fC + 2.0 * e + f;
344  }
345  else if (e >= 0.0)
346  {
347  t = 0.0;
348  fSqrDist = f;
349  }
350  else
351  {
352  t = -e / fC;
353  fSqrDist = e * t + f;
354  }
355  }
356  }
357  else if (t < 0.0)
358  {
359  //
360  // We are in region 6.
361  //
362  double tmp0 = fB + e;
363  double tmp1 = fA + d;
364  if (tmp1 > tmp0)
365  {
366  double numer = tmp1 - tmp0;
367  double denom = fA - 2.0 * fB + fC;
368  if (numer >= denom)
369  {
370  t = 1.0;
371  q = 0.0;
372  fSqrDist = fC + 2.0 * e + f;
373  }
374  else
375  {
376  t = numer / denom;
377  q = 1.0 - t;
378  fSqrDist = q * (fA * q + fB * t + 2.0 * d) + t * (fB * q + fC * t + 2.0 * e) + f;
379  }
380  }
381  else
382  {
383  t = 0.0;
384  if (tmp1 <= 0.0)
385  {
386  q = 1.0;
387  fSqrDist = fA + 2.0 * d + f;
388  }
389  else if (d >= 0.0)
390  {
391  q = 0.0;
392  fSqrDist = f;
393  }
394  else
395  {
396  q = -d / fA;
397  fSqrDist = d * q + f;
398  }
399  }
400  }
401  else
402  //
403  // We are in region 1.
404  //
405  {
406  double numer = fC + e - fB - d;
407  if (numer <= 0.0)
408  {
409  q = 0.0;
410  t = 1.0;
411  fSqrDist = fC + 2.0 * e + f;
412  }
413  else
414  {
415  double denom = fA - 2.0 * fB + fC;
416  if (numer >= denom)
417  {
418  q = 1.0;
419  t = 0.0;
420  fSqrDist = fA + 2.0 * d + f;
421  }
422  else
423  {
424  q = numer / denom;
425  t = 1.0 - q;
426  fSqrDist = q * (fA * q + fB * t + 2.0 * d) + t * (fB * q + fC * t + 2.0 * e) + f;
427  }
428  }
429  }
430  }
431  //
432  //
433  // Do fA check for rounding errors in the distance-squared. It appears that
434  // the conventional methods for calculating fSqrDist breaks down when very near
435  // to or at the surface (as required by transport). We'll therefore also use
436  // the magnitude-squared of the vector displacement. (Note that I've also
437  // tried to get around this problem by using the existing equations for
438  //
439  // fSqrDist = function(fA,fB,fC,d,q,t)
440  //
441  // and use fA more accurate addition process which minimises errors and
442  // breakdown of cummutitivity [where (A+B)+C != A+(B+C)] but this still
443  // doesn't work.
444  // Calculation from u = D + q*fE1 + t*fE2 is less efficient, but appears
445  // more robust.
446  //
447  if (fSqrDist < 0.0) fSqrDist = 0.;
448  UVector3 u = D + q * fE1 + t * fE2;
449  double u2 = u.Mag2();
450  //
451  // The following (part of the roundoff error check) is from Oliver Merle'q
452  // updates.
453  //
454  if (fSqrDist > u2) fSqrDist = u2;
455 
456  return u;
457 }
458 
460 //
461 // Distance (UVector3, double)
462 //
463 // Determines the closest distance between point p and the facet. This makes
464 // use of UVector3 UTriangularFacet::Distance, which stores the
465 // square of the distance in variable fSqrDist. If approximate methods show
466 // the distance is to be greater than minDist, then forget about further
467 // computation and return fA very large number.
468 //
469 double UTriangularFacet::Distance(const UVector3& p, const double minDist)
470 {
471  //
472  // Start with quicky test to determine if the surface of the sphere enclosing
473  // the triangle is any closer to p than minDist. If not, then don't bother
474  // about more accurate test.
475  //
476  double dist = UUtils::kInfinity;
477  if ((p - fCircumcentre).Mag() - fRadius < minDist)
478  {
479  //
480  // It's possible that the triangle is closer than minDist, so do more accurate
481  // assessment.
482  //
483  dist = Distance(p).Mag();
484  // dist = sqrt(fSqrDist);
485  }
486  return dist;
487 }
488 
490 //
491 // Distance (UVector3, double, bool)
492 //
493 // Determine the distance to point p. UUtils::kInfinity is returned if either:
494 // (1) outgoing is TRUE and the dot product of the normal vector to the facet
495 // and the displacement vector from p to the triangle is negative.
496 // (2) outgoing is FALSE and the dot product of the normal vector to the facet
497 // and the displacement vector from p to the triangle is positive.
498 // If approximate methods show the distance is to be greater than minDist, then
499 // forget about further computation and return fA very large number.
500 //
501 // This method has been heavily modified thanks to the valuable comments and
502 // corrections of Rickard Holmberg.
503 //
504 double UTriangularFacet::Distance(const UVector3& p, const double minDist, const bool outgoing)
505 {
506  //
507  // Start with quicky test to determine if the surface of the sphere enclosing
508  // the triangle is any closer to p than minDist. If not, then don't bother
509  // about more accurate test.
510  //
511  double dist = UUtils::kInfinity;
512  if ((p - fCircumcentre).Mag() - fRadius < minDist)
513  {
514  //
515  // It's possible that the triangle is closer than minDist, so do more accurate
516  // assessment.
517  //
518  UVector3 v = Distance(p);
519  double dist1 = sqrt(fSqrDist);
520  double dir = v.Dot(fSurfaceNormal);
521  bool wrongSide = (dir > 0.0 && !outgoing) || (dir < 0.0 && outgoing);
522  if (dist1 <= kCarTolerance)
523  {
524  //
525  // Point p is very close to triangle. Check if it's on the wrong side, in
526  // which case return distance of 0.0 otherwise .
527  //
528  if (wrongSide) dist = 0.0;
529  else dist = dist1;
530  }
531  else if (!wrongSide) dist = dist1;
532  }
533  return dist;
534 }
535 
537 //
538 // Extent
539 //
540 // Calculates the furthest the triangle extends in fA particular direction
541 // defined by the vector axis.
542 //
544 {
545  double ss = GetVertex(0).Dot(axis);
546  double sp = GetVertex(1).Dot(axis);
547  if (sp > ss) ss = sp;
548  sp = GetVertex(2).Dot(axis);
549  if (sp > ss) ss = sp;
550  return ss;
551 }
552 
554 //
555 // Intersect
556 //
557 // Member function to find the next intersection when going from p in the
558 // direction of v. If:
559 // (1) "outgoing" is TRUE, only consider the face if we are going out through
560 // the face.
561 // (2) "outgoing" is FALSE, only consider the face if we are going in through
562 // the face.
563 // Member functions returns TRUE if there is an intersection, FALSE otherwise.
564 // Sets the distance (distance along w), distFromSurface (orthogonal distance)
565 // and normal.
566 //
567 // Also considers intersections that happen with negative distance for small
568 // distances of distFromSurface = 0.5*kCarTolerance in the wrong direction.
569 // This is to detect kSurface without doing fA full Inside(p) in
570 // UTessellatedSolid::Distance(p,v) calculation.
571 //
572 // This member function is thanks the valuable work of Rickard Holmberg. PT.
573 // However, "gotos" are the Work of the Devil have been exorcised with
574 // extreme prejudice!!
575 //
576 // IMPORTANT NOTE: These calculations are predicated on v being fA unit
577 // vector. If UTessellatedSolid or other classes call this member function
578 // with |v| != 1 then there will be errors.
579 //
580 bool UTriangularFacet::Intersect(const UVector3& p, const UVector3& v, bool outgoing, double& distance, double& distFromSurface, UVector3& normal)
581 {
582  //
583  // Check whether the direction of the facet is consistent with the vector v
584  // and the need to be outgoing or ingoing. If inconsistent, disregard and
585  // return false.
586  //
587  double w = v.Dot(fSurfaceNormal);
588  if ((outgoing && w < -dirTolerance) || (!outgoing && w > dirTolerance))
589  {
590  distance = UUtils::kInfinity;
591  distFromSurface = UUtils::kInfinity;
592  normal.Set(0);
593  return false;
594  }
595  //
596  // Calculate the orthogonal distance from p to the surface containing the
597  // triangle. Then determine if we're on the right or wrong side of the
598  // surface (at fA distance greater than kCarTolerance to be consistent with
599  // "outgoing".
600  //
601  const UVector3& p0 = GetVertex(0);
602  UVector3 D = p0 - p;
603  distFromSurface = D.Dot(fSurfaceNormal);
604  bool wrongSide = (outgoing && distFromSurface < -0.5 * kCarTolerance) ||
605  (!outgoing && distFromSurface > 0.5 * kCarTolerance);
606  if (wrongSide)
607  {
608  distance = UUtils::kInfinity;
609  distFromSurface = UUtils::kInfinity;
610  normal.Set(0);
611  return false;
612  }
613 
614  wrongSide = (outgoing && distFromSurface < 0.0) || (!outgoing && distFromSurface > 0.0);
615  if (wrongSide)
616  {
617  //
618  // We're slightly on the wrong side of the surface. Check if we're close
619  // enough using fA precise distance calculation.
620  //
621  //UVector3 u = Distance(p);
623  {
624  //
625  // We're very close. Therefore return fA small negative number to pretend
626  // we intersect.
627  //
628  // distance = -0.5*kCarTolerance
629  distance = 0.0;
630  normal = fSurfaceNormal;
631  return true;
632  }
633  else
634  {
635  //
636  // We're close to the surface containing the triangle, but sufficiently
637  // far from the triangle, and on the wrong side compared to the directions
638  // of the surface normal and v. There is no intersection.
639  //
640  distance = UUtils::kInfinity;
641  distFromSurface = UUtils::kInfinity;
642  normal.Set(0);
643  return false;
644  }
645  }
646  if (w < dirTolerance && w > -dirTolerance)
647  {
648  //
649  // The ray is within the plane of the triangle. Project the problem into 2D
650  // in the plane of the triangle. First try to create orthogonal unit vectors
651  // mu and nu, where mu is fE1/|fE1|. This is kinda like
652  // the original algorithm due to Rickard Holmberg, but with better mathematical
653  // justification than the original method ... however, beware Rickard's was less
654  // time-consuming.
655  //
656  // Note that vprime is not fA unit vector. We need to keep it unnormalised
657  // since the values of distance along vprime (s0 and s1) for intersection with
658  // the triangle will be used to determine if we cut the plane at the same
659  // time.
660  //
661  UVector3 mu = fE1.Unit();
662  UVector3 nu = fSurfaceNormal.Cross(mu);
663  UVector2 pprime(p.Dot(mu), p.Dot(nu));
664  UVector2 vprime(v.Dot(mu), v.Dot(nu));
665  UVector2 P0prime(p0.Dot(mu), p0.Dot(nu));
666  UVector2 E0prime(fE1.Mag(), 0.0);
667  UVector2 E1prime(fE2.Dot(mu), fE2.Dot(nu));
668  UVector2 loc[2];
669  if (UTessellatedGeometryAlgorithms::IntersectLineAndTriangle2D(pprime, vprime, P0prime, E0prime, E1prime, loc))
670  {
671  //
672  // There is an intersection between the line and triangle in 2D. Now check
673  // which part of the line intersects with the plane containing the triangle
674  // in 3D.
675  //
676  double vprimemag = vprime.mag();
677  double s0 = (loc[0] - pprime).mag() / vprimemag;
678  double s1 = (loc[1] - pprime).mag() / vprimemag;
679  double normDist0 = fSurfaceNormal.Dot(s0 * v) - distFromSurface;
680  double normDist1 = fSurfaceNormal.Dot(s1 * v) - distFromSurface;
681 
682  if ((normDist0 < 0.0 && normDist1 < 0.0) || (normDist0 > 0.0 && normDist1 > 0.0) ||
683  (normDist0 == 0.0 && normDist1 == 0.0))
684  {
685  distance = UUtils::kInfinity;
686  distFromSurface = UUtils::kInfinity;
687  normal.Set(0);
688  return false;
689  }
690  else
691  {
692  double dnormDist = normDist1 - normDist0;
693  if (fabs(dnormDist) < DBL_EPSILON)
694  {
695  distance = s0;
696  normal = fSurfaceNormal;
697  if (!outgoing) distFromSurface = -distFromSurface;
698  return true;
699  }
700  else
701  {
702  distance = s0 - normDist0 * (s1 - s0) / dnormDist;
703  normal = fSurfaceNormal;
704  if (!outgoing) distFromSurface = -distFromSurface;
705  return true;
706  }
707  }
708 
709  // UVector3 dloc = loc1 - loc0;
710  // UVector3 dlocXv = dloc.cross(v);
711  // double dlocXvmag = dlocXv.mag();
712  // if (dloc.mag() <= 0.5*kCarTolerance || dlocXvmag <= DBL_EPSILON)
713  // {
714  // distance = loc0.mag();
715  // normal = fSurfaceNormal;
716  // if (!outgoing) distFromSurface = -distFromSurface;
717  // return true;
718  // }
719 
720  // UVector3 loc0Xv = loc0.cross(v);
721  // UVector3 loc1Xv = loc1.cross(v);
722  // double sameDir = -loc0Xv.dot(loc1Xv);
723  // if (sameDir < 0.0)
724  // {
725  // distance = UUtils::kInfinity;
726  // distFromSurface = UUtils::kInfinity;
727  // normal = UVector3(0.0,0.0,0.0);
728  // return false;
729  // }
730  // else
731  // {
732  // distance = loc0.mag() + loc0Xv.mag() * dloc.mag()/dlocXvmag;
733  // normal = fSurfaceNormal;
734  // if (!outgoing) distFromSurface = -distFromSurface;
735  // return true;
736  // }
737  }
738  else
739  {
740  distance = UUtils::kInfinity;
741  distFromSurface = UUtils::kInfinity;
742  normal.Set(0);
743  return false;
744  }
745  }
746  //
747  //
748  // Use conventional algorithm to determine the whether there is an
749  // intersection. This involves determining the point of intersection of the
750  // line with the plane containing the triangle, and then calculating if the
751  // point is within the triangle.
752  //
753  distance = distFromSurface / w;
754  UVector3 pp = p + v * distance;
755  UVector3 DD = p0 - pp;
756  double d = fE1.Dot(DD);
757  double e = fE2.Dot(DD);
758  double ss = fB * e - fC * d;
759  double t = fB * d - fA * e;
760 
761  double sTolerance = (fabs(fB) + fabs(fC) + fabs(d) + fabs(e)) * kCarTolerance;
762  double tTolerance = (fabs(fA) + fabs(fB) + fabs(d) + fabs(e)) * kCarTolerance;
763  double detTolerance = (fabs(fA) + fabs(fC) + 2 * fabs(fB)) * kCarTolerance;
764 
765  //if (ss < 0.0 || t < 0.0 || ss+t > fDet)
766  if (ss < -sTolerance || t < -tTolerance || (ss + t - fDet) > detTolerance)
767  {
768  //
769  // The intersection is outside of the triangle.
770  //
771  distance = distFromSurface = UUtils::kInfinity;
772  normal.Set(0);
773  return false;
774  }
775  else
776  {
777  //
778  // There is an intersection. Now we only need to set the surface normal.
779  //
780  normal = fSurfaceNormal;
781  if (!outgoing) distFromSurface = -distFromSurface;
782  return true;
783  }
784 }
785 
787 //
788 // GetPointOnFace
789 //```
790 // Auxiliary method for get fA random point on surface
791 
793 {
794  double alpha = UUtils::Random(0., 1.);
795  double beta = UUtils::Random(0., 1.);
796  double lambda1 = alpha * beta;
797  double lambda0 = alpha - lambda1;
798 
799  return GetVertex(0) + lambda0 * fE1 + lambda1 * fE2;
800 }
801 
803 //
804 // GetArea
805 //
806 // Auxiliary method for returning the surface fArea
807 
809 {
810  return fArea;
811 }
812 
814 {
815  return "UTriangularFacet";
816 }
817 
819 {
820  return fSurfaceNormal;
821 }
822 
824 {
826 }
double Mag2() const
Definition: UVector3.hh:267
UTriangularFacet & operator=(const UTriangularFacet &right)
static const double dirTolerance
Definition: VUFacet.hh:88
UVector3 GetPointOnFace() const
UVector3 GetSurfaceNormal() const
void SetSurfaceNormal(UVector3 normal)
UVector3 Cross(const UVector3 &) const
Definition: UVector3.hh:262
static bool IntersectLineAndTriangle2D(const UVector2 &p, const UVector2 &v, const UVector2 &p0, const UVector2 &e0, const UVector2 &e1, UVector2 location[2])
UFacetVertexType
Definition: VUFacet.hh:49
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
void copy(std::vector< T > &main, const std::vector< T > &data)
Definition: DicomRun.hh:91
static const double kInfinity
Definition: UUtils.hh:53
void CopyFrom(const UTriangularFacet &rhs)
void SetVertex(int i, const UVector3 &val)
#define DBL_EPSILON
Definition: templates.hh:87
double Dot(const UVector3 &) const
Definition: UVector3.hh:257
double Mag() const
Definition: UVector3.cc:48
double mag() const
Definition: UVector2.hh:310
UTriangularFacet * GetFlippedFacet()
UVector3 GetVertex(int i) const
void Set(double xx, double yy, double zz)
Definition: UVector3.hh:245
std::vector< UVector3 > * fVertices
UVector3 Unit() const
Definition: UVector3.cc:80
std::string UGeometryType
Definition: UTypes.hh:39
double Extent(const UVector3 axis)
bool Intersect(const UVector3 &p, const UVector3 &v, const bool outgoing, double &distance, double &distFromSurface, UVector3 &normal)
void Exception(const char *originOfException, const char *exceptionCode, ExceptionSeverity severity, int level, const char *description)
Definition: UUtils.cc:122
UGeometryType GetEntityType() const
void SetVertices(std::vector< UVector3 > *v)
static const G4double alpha
static const double kCarTolerance
Definition: VUFacet.hh:89
double Random(double min=0.0, double max=1.0)
Definition: UUtils.cc:69
UVector3 Distance(const UVector3 &p)