Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4TriangularFacet.cc
Go to the documentation of this file.
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
47using namespace std;
48
49///////////////////////////////////////////////////////////////////////////////
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
142///////////////////////////////////////////////////////////////////////////////
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
162///////////////////////////////////////////////////////////////////////////////
163//
165{
166 SetVertices(nullptr);
167}
168
169///////////////////////////////////////////////////////////////////////////////
170//
171void G4TriangularFacet::CopyFrom (const G4TriangularFacet& rhs)
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
183///////////////////////////////////////////////////////////////////////////////
184//
185void G4TriangularFacet::MoveFrom (G4TriangularFacet& rhs)
186{
187 fSurfaceNormal = std::move(rhs.fSurfaceNormal);
188 fArea = std::move(rhs.fArea);
189 fCircumcentre = std::move(rhs.fCircumcentre);
190 fRadius = std::move(rhs.fRadius);
191 fIndices = std::move(rhs.fIndices);
192 fA = std::move(rhs.fA); fB = std::move(rhs.fB); fC = std::move(rhs.fC);
193 fDet = std::move(rhs.fDet);
194 fSqrDist = std::move(rhs.fSqrDist);
195 fE1 = std::move(rhs.fE1); fE2 = std::move(rhs.fE2);
196 fIsDefined = std::move(rhs.fIsDefined);
197 fVertices = std::move(rhs.fVertices);
198 rhs.fVertices = nullptr;
199}
200
201///////////////////////////////////////////////////////////////////////////////
202//
204 : G4VFacet(rhs)
205{
206 CopyFrom(rhs);
207}
208
209///////////////////////////////////////////////////////////////////////////////
210//
212 : G4VFacet(rhs)
213{
214 MoveFrom(rhs);
215}
216
217///////////////////////////////////////////////////////////////////////////////
218//
221{
222 SetVertices(nullptr);
223
224 if (this != &rhs)
225 {
226 delete fVertices;
227 CopyFrom(rhs);
228 }
229
230 return *this;
231}
232
233///////////////////////////////////////////////////////////////////////////////
234//
237{
238 SetVertices(nullptr);
239
240 if (this != &rhs)
241 {
242 delete fVertices;
243 MoveFrom(rhs);
244 }
245
246 return *this;
247}
248
249///////////////////////////////////////////////////////////////////////////////
250//
251// GetClone
252//
253// Simple member function to generate fA duplicate of the triangular facet.
254//
256{
259 return fc;
260}
261
262///////////////////////////////////////////////////////////////////////////////
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
276///////////////////////////////////////////////////////////////////////////////
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 G4double dist = fSurfaceNormal.dot(D);
350 fSqrDist = dist*dist;
351 return fSurfaceNormal*dist;
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
464///////////////////////////////////////////////////////////////////////////////
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
494///////////////////////////////////////////////////////////////////////////////
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);
527 G4double dir = v.dot(fSurfaceNormal);
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
543///////////////////////////////////////////////////////////////////////////////
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
560///////////////////////////////////////////////////////////////////////////////
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,
592 G4ThreeVector& normal)
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 //
599 G4double w = v.dot(fSurfaceNormal);
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);
636 if (fSqrDist <= kCarTolerance*kCarTolerance)
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();
676 G4ThreeVector nu = fSurfaceNormal.cross(mu);
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
773////////////////////////////////////////////////////////////////////////
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
787////////////////////////////////////////////////////////////////////////
788//
789// GetArea
790//
791// Auxiliary method for returning the surface fArea
792//
794{
795 return fArea;
796}
797
798////////////////////////////////////////////////////////////////////////
799//
801{
802 return "G4TriangularFacet";
803}
804
805////////////////////////////////////////////////////////////////////////
806//
808{
809 return fSurfaceNormal;
810}
811
812////////////////////////////////////////////////////////////////////////
813//
815{
816 fSurfaceNormal = normal;
817}
G4double D(G4double temp)
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
G4FacetVertexType
Definition: G4VFacet.hh:48
@ ABSOLUTE
Definition: G4VFacet.hh:48
#define G4endl
Definition: G4ios.hh:57
#define G4UniformRand()
Definition: Randomize.hh:52
double mag() const
Hep3Vector unit() const
double mag2() const
Hep3Vector cross(const Hep3Vector &) const
double dot(const Hep3Vector &) const
double mag() const
void set(double x, double y, double z)
static G4bool IntersectLineAndTriangle2D(const G4TwoVector &p, const G4TwoVector &v, const G4TwoVector &p0, const G4TwoVector &e0, const G4TwoVector &e1, G4TwoVector location[2])
G4double GetArea() const
void SetSurfaceNormal(G4ThreeVector normal)
void SetVertex(G4int i, const G4ThreeVector &val)
G4ThreeVector GetPointOnFace() const
void SetVertices(std::vector< G4ThreeVector > *v)
G4bool Intersect(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool outgoing, G4double &distance, G4double &distFromSurface, G4ThreeVector &normal)
G4TriangularFacet & operator=(const G4TriangularFacet &right)
G4TriangularFacet * GetFlippedFacet()
G4GeometryType GetEntityType() const
G4ThreeVector Distance(const G4ThreeVector &p)
G4ThreeVector GetVertex(G4int i) const
G4ThreeVector GetSurfaceNormal() const
G4double Extent(const G4ThreeVector axis)
static const G4double dirTolerance
Definition: G4VFacet.hh:92
G4double kCarTolerance
Definition: G4VFacet.hh:93
#define DBL_EPSILON
Definition: templates.hh:66