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