ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4TriangularFacet.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4TriangularFacet.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // G4TriangularFacet implementation
27 //
28 // 31.10.2004, P R Truscott, QinetiQ Ltd, UK - Created.
29 // 01.08.2007, P R Truscott, QinetiQ Ltd, UK
30 // Significant modification to correct for errors and enhance
31 // based on patches/observations kindly provided by Rickard
32 // Holmberg.
33 // 12.10.2012, M Gayer, CERN
34 // New implementation reducing memory requirements by 50%,
35 // and considerable CPU speedup together with the new
36 // implementation of G4TessellatedSolid.
37 // 23.02.2016, E Tcherniaev, CERN
38 // Improved test to detect degenerate (too small or
39 // too narrow) triangles.
40 // --------------------------------------------------------------------
41 
42 #include "G4TriangularFacet.hh"
43 
44 #include "Randomize.hh"
46 
47 using namespace std;
48 
50 //
51 // Definition of triangular facet using absolute vectors to fVertices.
52 // From this for first vector is retained to define the facet location and
53 // two relative vectors (E0 and E1) define the sides and orientation of
54 // the outward surface normal.
55 //
57  const G4ThreeVector& vt1,
58  const G4ThreeVector& vt2,
59  G4FacetVertexType vertexType)
60  : G4VFacet()
61 {
62  fVertices = new vector<G4ThreeVector>(3);
63 
64  SetVertex(0, vt0);
65  if (vertexType == ABSOLUTE)
66  {
67  SetVertex(1, vt1);
68  SetVertex(2, vt2);
69  fE1 = vt1 - vt0;
70  fE2 = vt2 - vt0;
71  }
72  else
73  {
74  SetVertex(1, vt0 + vt1);
75  SetVertex(2, vt0 + vt2);
76  fE1 = vt1;
77  fE2 = vt2;
78  }
79 
80  G4ThreeVector E1xE2 = fE1.cross(fE2);
81  fArea = 0.5 * E1xE2.mag();
82  for (G4int i = 0; i < 3; ++i) fIndices[i] = -1;
83 
84  fIsDefined = true;
85  G4double delta = kCarTolerance; // Set tolerance for checking
86 
87  // Check length of edges
88  //
89  G4double leng1 = fE1.mag();
90  G4double leng2 = (fE2-fE1).mag();
91  G4double leng3 = fE2.mag();
92  if (leng1 <= delta || leng2 <= delta || leng3 <= delta)
93  {
94  fIsDefined = false;
95  }
96 
97  // Check min height of triangle
98  //
99  if (fIsDefined)
100  {
101  if (2.*fArea/std::max(std::max(leng1,leng2),leng3) <= delta)
102  {
103  fIsDefined = false;
104  }
105  }
106 
107  // Define facet
108  //
109  if (!fIsDefined)
110  {
111  ostringstream message;
112  message << "Facet is too small or too narrow." << G4endl
113  << "Triangle area = " << fArea << G4endl
114  << "P0 = " << GetVertex(0) << G4endl
115  << "P1 = " << GetVertex(1) << G4endl
116  << "P2 = " << GetVertex(2) << G4endl
117  << "Side1 length (P0->P1) = " << leng1 << G4endl
118  << "Side2 length (P1->P2) = " << leng2 << G4endl
119  << "Side3 length (P2->P0) = " << leng3;
120  G4Exception("G4TriangularFacet::G4TriangularFacet()",
121  "GeomSolids1001", JustWarning, message);
122  fSurfaceNormal.set(0,0,0);
123  fA = fB = fC = 0.0;
124  fDet = 0.0;
125  fCircumcentre = vt0 + 0.5*fE1 + 0.5*fE2;
126  fArea = fRadius = 0.0;
127  }
128  else
129  {
130  fSurfaceNormal = E1xE2.unit();
131  fA = fE1.mag2();
132  fB = fE1.dot(fE2);
133  fC = fE2.mag2();
134  fDet = std::fabs(fA*fC - fB*fB);
135 
136  fCircumcentre =
137  vt0 + (E1xE2.cross(fE1)*fC + fE2.cross(E1xE2)*fA) / (2.*E1xE2.mag2());
138  fRadius = (fCircumcentre - vt0).mag();
139  }
140 }
141 
143 //
145  : fSqrDist(0.)
146 {
147  fVertices = new vector<G4ThreeVector>(3);
148  G4ThreeVector zero(0,0,0);
149  SetVertex(0, zero);
150  SetVertex(1, zero);
151  SetVertex(2, zero);
152  for (G4int i = 0; i < 3; ++i) fIndices[i] = -1;
153  fIsDefined = false;
154  fSurfaceNormal.set(0,0,0);
155  fA = fB = fC = 0;
156  fE1 = zero;
157  fE2 = zero;
158  fDet = 0.0;
159  fArea = fRadius = 0.0;
160 }
161 
163 //
165 {
166  SetVertices(nullptr);
167 }
168 
170 //
172 {
173  char *p = (char *) &rhs;
174  copy(p, p + sizeof(*this), (char *)this);
175 
176  if (fIndices[0] < 0 && fVertices == nullptr)
177  {
178  fVertices = new vector<G4ThreeVector>(3);
179  for (G4int i = 0; i < 3; ++i) (*fVertices)[i] = (*rhs.fVertices)[i];
180  }
181 }
182 
184 //
186 {
187  fSurfaceNormal = move(rhs.fSurfaceNormal);
188  fArea = move(rhs.fArea);
189  fCircumcentre = move(rhs.fCircumcentre);
190  fRadius = move(rhs.fRadius);
191  fIndices = move(rhs.fIndices);
192  fA = move(rhs.fA); fB = move(rhs.fB); fC = move(rhs.fC);
193  fDet = move(rhs.fDet);
194  fSqrDist = move(rhs.fSqrDist);
195  fE1 = move(rhs.fE1); fE2 = move(rhs.fE2);
196  fIsDefined = move(rhs.fIsDefined);
197  fVertices = move(rhs.fVertices);
198  rhs.fVertices = nullptr;
199 }
200 
202 //
204  : G4VFacet(rhs)
205 {
206  CopyFrom(rhs);
207 }
208 
210 //
212  : G4VFacet(rhs)
213 {
214  MoveFrom(rhs);
215 }
216 
218 //
221 {
222  SetVertices(nullptr);
223 
224  if (this != &rhs)
225  {
226  delete fVertices;
227  CopyFrom(rhs);
228  }
229 
230  return *this;
231 }
232 
234 //
237 {
238  SetVertices(nullptr);
239 
240  if (this != &rhs)
241  {
242  delete fVertices;
243  MoveFrom(rhs);
244  }
245 
246  return *this;
247 }
248 
250 //
251 // GetClone
252 //
253 // Simple member function to generate fA duplicate of the triangular facet.
254 //
256 {
257  G4TriangularFacet* fc =
259  return fc;
260 }
261 
263 //
264 // GetFlippedFacet
265 //
266 // Member function to generate an identical facet, but with the normal vector
267 // pointing at 180 degrees.
268 //
270 {
271  G4TriangularFacet* flipped =
273  return flipped;
274 }
275 
277 //
278 // Distance (G4ThreeVector)
279 //
280 // Determines the vector between p and the closest point on the facet to p.
281 // This is based on the algorithm published in "Geometric Tools for Computer
282 // Graphics," Philip J Scheider and David H Eberly, Elsevier Science (USA),
283 // 2003. at the time of writing, the algorithm is also available in fA
284 // technical note "Distance between point and triangle in 3D," by David Eberly
285 // at http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
286 //
287 // The by-product is the square-distance fSqrDist, which is retained
288 // in case needed by the other "Distance" member functions.
289 //
291 {
292  G4ThreeVector D = GetVertex(0) - p;
293  G4double d = fE1.dot(D);
294  G4double e = fE2.dot(D);
295  G4double f = D.mag2();
296  G4double q = fB*e - fC*d;
297  G4double t = fB*d - fA*e;
298  fSqrDist = 0.;
299 
300  if (q+t <= fDet)
301  {
302  if (q < 0.0)
303  {
304  if (t < 0.0)
305  {
306  //
307  // We are in region 4.
308  //
309  if (d < 0.0)
310  {
311  t = 0.0;
312  if (-d >= fA) {q = 1.0; fSqrDist = fA + 2.0*d + f;}
313  else {q = -d/fA; fSqrDist = d*q + f;}
314  }
315  else
316  {
317  q = 0.0;
318  if (e >= 0.0) {t = 0.0; fSqrDist = f;}
319  else if (-e >= fC) {t = 1.0; fSqrDist = fC + 2.0*e + f;}
320  else {t = -e/fC; fSqrDist = e*t + f;}
321  }
322  }
323  else
324  {
325  //
326  // We are in region 3.
327  //
328  q = 0.0;
329  if (e >= 0.0) {t = 0.0; fSqrDist = f;}
330  else if (-e >= fC) {t = 1.0; fSqrDist = fC + 2.0*e + f;}
331  else {t = -e/fC; fSqrDist = e*t + f;}
332  }
333  }
334  else if (t < 0.0)
335  {
336  //
337  // We are in region 5.
338  //
339  t = 0.0;
340  if (d >= 0.0) {q = 0.0; fSqrDist = f;}
341  else if (-d >= fA) {q = 1.0; fSqrDist = fA + 2.0*d + f;}
342  else {q = -d/fA; fSqrDist = d*q + f;}
343  }
344  else
345  {
346  //
347  // We are in region 0.
348  //
349  q = q / fDet;
350  t = t / fDet;
351  fSqrDist = q*(fA*q + fB*t + 2.0*d) + t*(fB*q + fC*t + 2.0*e) + f;
352  }
353  }
354  else
355  {
356  if (q < 0.0)
357  {
358  //
359  // We are in region 2.
360  //
361  G4double tmp0 = fB + d;
362  G4double tmp1 = fC + e;
363  if (tmp1 > tmp0)
364  {
365  G4double numer = tmp1 - tmp0;
366  G4double denom = fA - 2.0*fB + fC;
367  if (numer >= denom) {q = 1.0; t = 0.0; fSqrDist = fA + 2.0*d + f;}
368  else
369  {
370  q = numer/denom;
371  t = 1.0 - q;
372  fSqrDist = q*(fA*q + fB*t +2.0*d) + t*(fB*q + fC*t + 2.0*e) + f;
373  }
374  }
375  else
376  {
377  q = 0.0;
378  if (tmp1 <= 0.0) {t = 1.0; fSqrDist = fC + 2.0*e + f;}
379  else if (e >= 0.0) {t = 0.0; fSqrDist = f;}
380  else {t = -e/fC; fSqrDist = e*t + f;}
381  }
382  }
383  else if (t < 0.0)
384  {
385  //
386  // We are in region 6.
387  //
388  G4double tmp0 = fB + e;
389  G4double tmp1 = fA + d;
390  if (tmp1 > tmp0)
391  {
392  G4double numer = tmp1 - tmp0;
393  G4double denom = fA - 2.0*fB + fC;
394  if (numer >= denom) {t = 1.0; q = 0.0; fSqrDist = fC + 2.0*e + f;}
395  else
396  {
397  t = numer/denom;
398  q = 1.0 - t;
399  fSqrDist = q*(fA*q + fB*t +2.0*d) + t*(fB*q + fC*t + 2.0*e) + f;
400  }
401  }
402  else
403  {
404  t = 0.0;
405  if (tmp1 <= 0.0) {q = 1.0; fSqrDist = fA + 2.0*d + f;}
406  else if (d >= 0.0) {q = 0.0; fSqrDist = f;}
407  else {q = -d/fA; fSqrDist = d*q + f;}
408  }
409  }
410  else
411  //
412  // We are in region 1.
413  //
414  {
415  G4double numer = fC + e - fB - d;
416  if (numer <= 0.0)
417  {
418  q = 0.0;
419  t = 1.0;
420  fSqrDist = fC + 2.0*e + f;
421  }
422  else
423  {
424  G4double denom = fA - 2.0*fB + fC;
425  if (numer >= denom) {q = 1.0; t = 0.0; fSqrDist = fA + 2.0*d + f;}
426  else
427  {
428  q = numer/denom;
429  t = 1.0 - q;
430  fSqrDist = q*(fA*q + fB*t + 2.0*d) + t*(fB*q + fC*t + 2.0*e) + f;
431  }
432  }
433  }
434  }
435  //
436  //
437  // Do fA check for rounding errors in the distance-squared. It appears that
438  // the conventional methods for calculating fSqrDist breaks down when very
439  // near to or at the surface (as required by transport).
440  // We'll therefore also use the magnitude-squared of the vector displacement.
441  // (Note that I've also tried to get around this problem by using the
442  // existing equations for
443  //
444  // fSqrDist = function(fA,fB,fC,d,q,t)
445  //
446  // and use fA more accurate addition process which minimises errors and
447  // breakdown of cummutitivity [where (A+B)+C != A+(B+C)] but this still
448  // doesn't work.
449  // Calculation from u = D + q*fE1 + t*fE2 is less efficient, but appears
450  // more robust.
451  //
452  if (fSqrDist < 0.0) fSqrDist = 0.;
453  G4ThreeVector u = D + q*fE1 + t*fE2;
454  G4double u2 = u.mag2();
455  //
456  // The following (part of the roundoff error check) is from Oliver Merle'q
457  // updates.
458  //
459  if (fSqrDist > u2) fSqrDist = u2;
460 
461  return u;
462 }
463 
465 //
466 // Distance (G4ThreeVector, G4double)
467 //
468 // Determines the closest distance between point p and the facet. This makes
469 // use of G4ThreeVector G4TriangularFacet::Distance, which stores the
470 // square of the distance in variable fSqrDist. If approximate methods show
471 // the distance is to be greater than minDist, then forget about further
472 // computation and return fA very large number.
473 //
475  G4double minDist)
476 {
477  //
478  // Start with quicky test to determine if the surface of the sphere enclosing
479  // the triangle is any closer to p than minDist. If not, then don't bother
480  // about more accurate test.
481  //
482  G4double dist = kInfinity;
483  if ((p-fCircumcentre).mag()-fRadius < minDist)
484  {
485  //
486  // It's possible that the triangle is closer than minDist,
487  // so do more accurate assessment.
488  //
489  dist = Distance(p).mag();
490  }
491  return dist;
492 }
493 
495 //
496 // Distance (G4ThreeVector, G4double, G4bool)
497 //
498 // Determine the distance to point p. kInfinity is returned if either:
499 // (1) outgoing is TRUE and the dot product of the normal vector to the facet
500 // and the displacement vector from p to the triangle is negative.
501 // (2) outgoing is FALSE and the dot product of the normal vector to the facet
502 // and the displacement vector from p to the triangle is positive.
503 // If approximate methods show the distance is to be greater than minDist, then
504 // forget about further computation and return fA very large number.
505 //
506 // This method has been heavily modified thanks to the valuable comments and
507 // corrections of Rickard Holmberg.
508 //
510  G4double minDist,
511  const G4bool outgoing)
512 {
513  //
514  // Start with quicky test to determine if the surface of the sphere enclosing
515  // the triangle is any closer to p than minDist. If not, then don't bother
516  // about more accurate test.
517  //
518  G4double dist = kInfinity;
519  if ((p-fCircumcentre).mag()-fRadius < minDist)
520  {
521  //
522  // It's possible that the triangle is closer than minDist,
523  // so do more accurate assessment.
524  //
525  G4ThreeVector v = Distance(p);
526  G4double dist1 = sqrt(fSqrDist);
528  G4bool wrongSide = (dir > 0.0 && !outgoing) || (dir < 0.0 && outgoing);
529  if (dist1 <= kCarTolerance)
530  {
531  //
532  // Point p is very close to triangle. Check if it's on the wrong side,
533  // in which case return distance of 0.0 otherwise .
534  //
535  if (wrongSide) dist = 0.0;
536  else dist = dist1;
537  }
538  else if (!wrongSide) dist = dist1;
539  }
540  return dist;
541 }
542 
544 //
545 // Extent
546 //
547 // Calculates the furthest the triangle extends in fA particular direction
548 // defined by the vector axis.
549 //
551 {
552  G4double ss = GetVertex(0).dot(axis);
553  G4double sp = GetVertex(1).dot(axis);
554  if (sp > ss) ss = sp;
555  sp = GetVertex(2).dot(axis);
556  if (sp > ss) ss = sp;
557  return ss;
558 }
559 
561 //
562 // Intersect
563 //
564 // Member function to find the next intersection when going from p in the
565 // direction of v. If:
566 // (1) "outgoing" is TRUE, only consider the face if we are going out through
567 // the face.
568 // (2) "outgoing" is FALSE, only consider the face if we are going in through
569 // the face.
570 // Member functions returns TRUE if there is an intersection, FALSE otherwise.
571 // Sets the distance (distance along w), distFromSurface (orthogonal distance)
572 // and normal.
573 //
574 // Also considers intersections that happen with negative distance for small
575 // distances of distFromSurface = 0.5*kCarTolerance in the wrong direction.
576 // This is to detect kSurface without doing fA full Inside(p) in
577 // G4TessellatedSolid::Distance(p,v) calculation.
578 //
579 // This member function is thanks the valuable work of Rickard Holmberg. PT.
580 // However, "gotos" are the Work of the Devil have been exorcised with
581 // extreme prejudice!!
582 //
583 // IMPORTANT NOTE: These calculations are predicated on v being fA unit
584 // vector. If G4TessellatedSolid or other classes call this member function
585 // with |v| != 1 then there will be errors.
586 //
588  const G4ThreeVector& v,
589  G4bool outgoing,
590  G4double& distance,
591  G4double& distFromSurface,
593 {
594  //
595  // Check whether the direction of the facet is consistent with the vector v
596  // and the need to be outgoing or ingoing. If inconsistent, disregard and
597  // return false.
598  //
600  if ((outgoing && w < -dirTolerance) || (!outgoing && w > dirTolerance))
601  {
602  distance = kInfinity;
603  distFromSurface = kInfinity;
604  normal.set(0,0,0);
605  return false;
606  }
607  //
608  // Calculate the orthogonal distance from p to the surface containing the
609  // triangle. Then determine if we're on the right or wrong side of the
610  // surface (at fA distance greater than kCarTolerance to be consistent with
611  // "outgoing".
612  //
613  const G4ThreeVector& p0 = GetVertex(0);
614  G4ThreeVector D = p0 - p;
615  distFromSurface = D.dot(fSurfaceNormal);
616  G4bool wrongSide = (outgoing && distFromSurface < -0.5*kCarTolerance) ||
617  (!outgoing && distFromSurface > 0.5*kCarTolerance);
618 
619  if (wrongSide)
620  {
621  distance = kInfinity;
622  distFromSurface = kInfinity;
623  normal.set(0,0,0);
624  return false;
625  }
626 
627  wrongSide = (outgoing && distFromSurface < 0.0)
628  || (!outgoing && distFromSurface > 0.0);
629  if (wrongSide)
630  {
631  //
632  // We're slightly on the wrong side of the surface. Check if we're close
633  // enough using fA precise distance calculation.
634  //
635  G4ThreeVector u = Distance(p);
637  {
638  //
639  // We're very close. Therefore return fA small negative number
640  // to pretend we intersect.
641  //
642  // distance = -0.5*kCarTolerance
643  distance = 0.0;
644  normal = fSurfaceNormal;
645  return true;
646  }
647  else
648  {
649  //
650  // We're close to the surface containing the triangle, but sufficiently
651  // far from the triangle, and on the wrong side compared to the directions
652  // of the surface normal and v. There is no intersection.
653  //
654  distance = kInfinity;
655  distFromSurface = kInfinity;
656  normal.set(0,0,0);
657  return false;
658  }
659  }
660  if (w < dirTolerance && w > -dirTolerance)
661  {
662  //
663  // The ray is within the plane of the triangle. Project the problem into 2D
664  // in the plane of the triangle. First try to create orthogonal unit vectors
665  // mu and nu, where mu is fE1/|fE1|. This is kinda like
666  // the original algorithm due to Rickard Holmberg, but with better
667  // mathematical justification than the original method ... however,
668  // beware Rickard's was less time-consuming.
669  //
670  // Note that vprime is not fA unit vector. We need to keep it unnormalised
671  // since the values of distance along vprime (s0 and s1) for intersection
672  // with the triangle will be used to determine if we cut the plane at the
673  // same time.
674  //
675  G4ThreeVector mu = fE1.unit();
677  G4TwoVector pprime(p.dot(mu), p.dot(nu));
678  G4TwoVector vprime(v.dot(mu), v.dot(nu));
679  G4TwoVector P0prime(p0.dot(mu), p0.dot(nu));
680  G4TwoVector E0prime(fE1.mag(), 0.0);
681  G4TwoVector E1prime(fE2.dot(mu), fE2.dot(nu));
682  G4TwoVector loc[2];
684  vprime, P0prime, E0prime, E1prime, loc))
685  {
686  //
687  // There is an intersection between the line and triangle in 2D.
688  // Now check which part of the line intersects with the plane
689  // containing the triangle in 3D.
690  //
691  G4double vprimemag = vprime.mag();
692  G4double s0 = (loc[0] - pprime).mag()/vprimemag;
693  G4double s1 = (loc[1] - pprime).mag()/vprimemag;
694  G4double normDist0 = fSurfaceNormal.dot(s0*v) - distFromSurface;
695  G4double normDist1 = fSurfaceNormal.dot(s1*v) - distFromSurface;
696 
697  if ((normDist0 < 0.0 && normDist1 < 0.0)
698  || (normDist0 > 0.0 && normDist1 > 0.0)
699  || (normDist0 == 0.0 && normDist1 == 0.0) )
700  {
701  distance = kInfinity;
702  distFromSurface = kInfinity;
703  normal.set(0,0,0);
704  return false;
705  }
706  else
707  {
708  G4double dnormDist = normDist1 - normDist0;
709  if (fabs(dnormDist) < DBL_EPSILON)
710  {
711  distance = s0;
712  normal = fSurfaceNormal;
713  if (!outgoing) distFromSurface = -distFromSurface;
714  return true;
715  }
716  else
717  {
718  distance = s0 - normDist0*(s1-s0)/dnormDist;
719  normal = fSurfaceNormal;
720  if (!outgoing) distFromSurface = -distFromSurface;
721  return true;
722  }
723  }
724  }
725  else
726  {
727  distance = kInfinity;
728  distFromSurface = kInfinity;
729  normal.set(0,0,0);
730  return false;
731  }
732  }
733  //
734  //
735  // Use conventional algorithm to determine the whether there is an
736  // intersection. This involves determining the point of intersection of the
737  // line with the plane containing the triangle, and then calculating if the
738  // point is within the triangle.
739  //
740  distance = distFromSurface / w;
741  G4ThreeVector pp = p + v*distance;
742  G4ThreeVector DD = p0 - pp;
743  G4double d = fE1.dot(DD);
744  G4double e = fE2.dot(DD);
745  G4double ss = fB*e - fC*d;
746  G4double t = fB*d - fA*e;
747 
748  G4double sTolerance = (fabs(fB)+ fabs(fC) + fabs(d) + fabs(e))*kCarTolerance;
749  G4double tTolerance = (fabs(fA)+ fabs(fB) + fabs(d) + fabs(e))*kCarTolerance;
750  G4double detTolerance = (fabs(fA)+ fabs(fC) + 2*fabs(fB) )*kCarTolerance;
751 
752  //if (ss < 0.0 || t < 0.0 || ss+t > fDet)
753  if (ss < -sTolerance || t < -tTolerance || ( ss+t - fDet ) > detTolerance)
754  {
755  //
756  // The intersection is outside of the triangle.
757  //
758  distance = distFromSurface = kInfinity;
759  normal.set(0,0,0);
760  return false;
761  }
762  else
763  {
764  //
765  // There is an intersection. Now we only need to set the surface normal.
766  //
767  normal = fSurfaceNormal;
768  if (!outgoing) distFromSurface = -distFromSurface;
769  return true;
770  }
771 }
772 
774 //
775 // GetPointOnFace
776 //
777 // Auxiliary method, returns a uniform random point on the facet
778 //
780 {
783  if (u+v > 1.) { u = 1. - u; v = 1. - v; }
784  return GetVertex(0) + u*fE1 + v*fE2;
785 }
786 
788 //
789 // GetArea
790 //
791 // Auxiliary method for returning the surface fArea
792 //
794 {
795  return fArea;
796 }
797 
799 //
801 {
802  return "G4TriangularFacet";
803 }
804 
806 //
808 {
809  return fSurfaceNormal;
810 }
811 
813 //
815 {
817 }