Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4PolyPhiFace.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// Implementation of G4PolyPhiFace, the face that bounds a polycone or
27// polyhedra at its phi opening.
28//
29// Author: David C. Williams ([email protected])
30// --------------------------------------------------------------------
31
32#include "G4PolyPhiFace.hh"
33#include "G4ClippablePolygon.hh"
34#include "G4ReduciblePolygon.hh"
35#include "G4AffineTransform.hh"
36#include "G4SolidExtentList.hh"
38
39#include "Randomize.hh"
40#include "G4TwoVector.hh"
41
42// Constructor
43//
44// Points r,z should be supplied in clockwise order in r,z. For example:
45//
46// [1]---------[2] ^ R
47// | | |
48// | | +--> z
49// [0]---------[3]
50//
52 G4double phi,
53 G4double deltaPhi,
54 G4double phiOther )
55{
57
58 numEdges = rz->NumVertices();
59
60 rMin = rz->Amin();
61 rMax = rz->Amax();
62 zMin = rz->Bmin();
63 zMax = rz->Bmax();
64
65 //
66 // Is this the "starting" phi edge of the two?
67 //
68 G4bool start = (phiOther > phi);
69
70 //
71 // Build radial vector
72 //
73 radial = G4ThreeVector( std::cos(phi), std::sin(phi), 0.0 );
74
75 //
76 // Build normal
77 //
78 G4double zSign = start ? 1 : -1;
79 normal = G4ThreeVector( zSign*radial.y(), -zSign*radial.x(), 0 );
80
81 //
82 // Is allBehind?
83 //
84 allBehind = (zSign*(std::cos(phiOther)*radial.y() - std::sin(phiOther)*radial.x()) < 0);
85
86 //
87 // Adjacent edges
88 //
89 G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
90 G4double cosMid = std::cos(midPhi),
91 sinMid = std::sin(midPhi);
92 //
93 // Allocate corners
94 //
95 const std::size_t maxEdges = numEdges>0 ? numEdges : 1;
96 corners = new G4PolyPhiFaceVertex[maxEdges];
97 //
98 // Fill them
99 //
101
104
105 iterRZ.Begin();
106 do // Loop checking, 13.08.2015, G.Cosmo
107 {
108 corn->r = iterRZ.GetA();
109 corn->z = iterRZ.GetB();
110 corn->x = corn->r*radial.x();
111 corn->y = corn->r*radial.y();
112
113 // Add pointer on prev corner
114 //
115 if( corn == corners )
116 { corn->prev = corners+maxEdges-1;}
117 else
118 { corn->prev = helper; }
119
120 // Add pointer on next corner
121 //
122 if( corn < corners+maxEdges-1 )
123 { corn->next = corn+1;}
124 else
125 { corn->next = corners; }
126
127 helper = corn;
128 } while( ++corn, iterRZ.Next() );
129
130 //
131 // Allocate edges
132 //
133 edges = new G4PolyPhiFaceEdge[maxEdges];
134
135 //
136 // Fill them
137 //
138 G4double rFact = std::cos(0.5*deltaPhi);
139 G4double rFactNormalize = 1.0/std::sqrt(1.0+rFact*rFact);
140
141 G4PolyPhiFaceVertex* prev = corners+maxEdges-1,
142 * here = corners;
143 G4PolyPhiFaceEdge* edge = edges;
144 do // Loop checking, 13.08.2015, G.Cosmo
145 {
146 G4ThreeVector sideNorm;
147
148 edge->v0 = prev;
149 edge->v1 = here;
150
151 G4double dr = here->r - prev->r,
152 dz = here->z - prev->z;
153
154 edge->length = std::sqrt( dr*dr + dz*dz );
155
156 edge->tr = dr/edge->length;
157 edge->tz = dz/edge->length;
158
159 if ((here->r < DBL_MIN) && (prev->r < DBL_MIN))
160 {
161 //
162 // Sigh! Always exceptions!
163 // This edge runs at r==0, so its adjoing surface is not a
164 // PolyconeSide or PolyhedraSide, but the opposite PolyPhiFace.
165 //
166 G4double zSignOther = start ? -1 : 1;
167 sideNorm = G4ThreeVector( zSignOther*std::sin(phiOther),
168 -zSignOther*std::cos(phiOther), 0 );
169 }
170 else
171 {
172 sideNorm = G4ThreeVector( edge->tz*cosMid,
173 edge->tz*sinMid,
174 -edge->tr*rFact );
175 sideNorm *= rFactNormalize;
176 }
177 sideNorm += normal;
178
179 edge->norm3D = sideNorm.unit();
180 } while( edge++, prev=here, ++here < corners+maxEdges );
181
182 //
183 // Go back and fill in corner "normals"
184 //
185 G4PolyPhiFaceEdge* prevEdge = edges+maxEdges-1;
186 edge = edges;
187 do // Loop checking, 13.08.2015, G.Cosmo
188 {
189 //
190 // Calculate vertex 2D normals (on the phi surface)
191 //
192 G4double rPart = prevEdge->tr + edge->tr;
193 G4double zPart = prevEdge->tz + edge->tz;
194 G4double norm = std::sqrt( rPart*rPart + zPart*zPart );
195 G4double rNorm = +zPart/norm;
196 G4double zNorm = -rPart/norm;
197
198 edge->v0->rNorm = rNorm;
199 edge->v0->zNorm = zNorm;
200
201 //
202 // Calculate the 3D normals.
203 //
204 // Find the vector perpendicular to the z axis
205 // that defines the plane that contains the vertex normal
206 //
207 G4ThreeVector xyVector;
208
209 if (edge->v0->r < DBL_MIN)
210 {
211 //
212 // This is a vertex at r==0, which is a special
213 // case. The normal we will construct lays in the
214 // plane at the center of the phi opening.
215 //
216 // We also know that rNorm < 0
217 //
218 G4double zSignOther = start ? -1 : 1;
219 G4ThreeVector normalOther( zSignOther*std::sin(phiOther),
220 -zSignOther*std::cos(phiOther), 0 );
221
222 xyVector = - normal - normalOther;
223 }
224 else
225 {
226 //
227 // This is a vertex at r > 0. The plane
228 // is the average of the normal and the
229 // normal of the adjacent phi face
230 //
231 xyVector = G4ThreeVector( cosMid, sinMid, 0 );
232 if (rNorm < 0)
233 xyVector -= normal;
234 else
235 xyVector += normal;
236 }
237
238 //
239 // Combine it with the r/z direction from the face
240 //
241 edge->v0->norm3D = rNorm*xyVector.unit() + G4ThreeVector( 0, 0, zNorm );
242 } while( prevEdge=edge, ++edge < edges+maxEdges );
243
244 //
245 // Build point on surface
246 //
247 G4double rAve = 0.5*(rMax-rMin),
248 zAve = 0.5*(zMax-zMin);
249 surface = G4ThreeVector( rAve*radial.x(), rAve*radial.y(), zAve );
250}
251
252// Diagnose
253//
254// Throw an exception if something is found inconsistent with
255// the solid.
256//
257// For debugging purposes only
258//
260{
262 do // Loop checking, 13.08.2015, G.Cosmo
263 {
264 G4ThreeVector test(corner->x, corner->y, corner->z);
265 test -= 1E-6*corner->norm3D;
266
267 if (owner->Inside(test) != kInside)
268 G4Exception( "G4PolyPhiFace::Diagnose()", "GeomSolids0002",
269 FatalException, "Bad vertex normal found." );
270 } while( ++corner < corners+numEdges );
271}
272
273// Fake default constructor - sets only member data and allocates memory
274// for usage restricted to object persistency.
275//
277 : numEdges(0), rMin(0.), rMax(0.), zMin(0.), zMax(0.), kCarTolerance(0.)
278{
279}
280
281
282//
283// Destructor
284//
286{
287 delete [] edges;
288 delete [] corners;
289}
290
291
292//
293// Copy constructor
294//
296{
297 CopyStuff( source );
298}
299
300
301//
302// Assignment operator
303//
305{
306 if (this == &source) { return *this; }
307
308 delete [] edges;
309 delete [] corners;
310
311 CopyStuff( source );
312
313 return *this;
314}
315
316
317//
318// CopyStuff (protected)
319//
321{
322 //
323 // The simple stuff
324 //
325 numEdges = source.numEdges;
326 normal = source.normal;
327 radial = source.radial;
328 surface = source.surface;
329 rMin = source.rMin;
330 rMax = source.rMax;
331 zMin = source.zMin;
332 zMax = source.zMax;
333 allBehind = source.allBehind;
334 triangles = nullptr;
335
337 fSurfaceArea = source.fSurfaceArea;
338
339 const std::size_t maxEdges = (numEdges > 0) ? numEdges : 1;
340
341 //
342 // Corner dynamic array
343 //
344 corners = new G4PolyPhiFaceVertex[maxEdges];
346 *sourceCorn = source.corners;
347 do // Loop checking, 13.08.2015, G.Cosmo
348 {
349 *corn = *sourceCorn;
350 } while( ++sourceCorn, ++corn < corners+maxEdges );
351
352 //
353 // Edge dynamic array
354 //
355 edges = new G4PolyPhiFaceEdge[maxEdges];
356
357 G4PolyPhiFaceVertex* prev = corners+maxEdges-1,
358 * here = corners;
359 G4PolyPhiFaceEdge* edge = edges,
360 * sourceEdge = source.edges;
361 do // Loop checking, 13.08.2015, G.Cosmo
362 {
363 *edge = *sourceEdge;
364 edge->v0 = prev;
365 edge->v1 = here;
366 } while( ++sourceEdge, ++edge, prev=here, ++here < corners+maxEdges );
367}
368
369// Intersect
370//
372 const G4ThreeVector& v,
373 G4bool outgoing,
374 G4double surfTolerance,
375 G4double& distance,
376 G4double& distFromSurface,
377 G4ThreeVector& aNormal,
378 G4bool& isAllBehind )
379{
380 G4double normSign = outgoing ? +1 : -1;
381
382 //
383 // These don't change
384 //
385 isAllBehind = allBehind;
386 aNormal = normal;
387
388 //
389 // Correct normal? Here we have straight sides, and can safely ignore
390 // intersections where the dot product with the normal is zero.
391 //
392 G4double dotProd = normSign*normal.dot(v);
393
394 if (dotProd <= 0) return false;
395
396 //
397 // Calculate distance to surface. If the side is too far
398 // behind the point, we must reject it.
399 //
400 G4ThreeVector ps = p - surface;
401 distFromSurface = -normSign*ps.dot(normal);
402
403 if (distFromSurface < -surfTolerance) return false;
404
405 //
406 // Calculate precise distance to intersection with the side
407 // (along the trajectory, not normal to the surface)
408 //
409 distance = distFromSurface/dotProd;
410
411 //
412 // Calculate intersection point in r,z
413 //
414 G4ThreeVector ip = p + distance*v;
415
416 G4double r = radial.dot(ip);
417
418 //
419 // And is it inside the r/z extent?
420 //
421 return InsideEdgesExact( r, ip.z(), normSign, p, v );
422}
423
424// Distance
425//
427{
428 G4double normSign = outgoing ? +1 : -1;
429 //
430 // Correct normal?
431 //
432 G4ThreeVector ps = p - surface;
433 G4double distPhi = -normSign*normal.dot(ps);
434
435 if (distPhi < -0.5*kCarTolerance)
436 return kInfinity;
437 else if (distPhi < 0)
438 distPhi = 0.0;
439
440 //
441 // Calculate projected point in r,z
442 //
443 G4double r = radial.dot(p);
444
445 //
446 // Are we inside the face?
447 //
448 G4double distRZ2;
449
450 if (InsideEdges( r, p.z(), &distRZ2, nullptr ))
451 {
452 //
453 // Yup, answer is just distPhi
454 //
455 return distPhi;
456 }
457 else
458 {
459 //
460 // Nope. Penalize by distance out
461 //
462 return std::sqrt( distPhi*distPhi + distRZ2 );
463 }
464}
465
466// Inside
467//
469 G4double tolerance,
470 G4double* bestDistance )
471{
472 //
473 // Get distance along phi, which if negative means the point
474 // is nominally inside the shape.
475 //
476 G4ThreeVector ps = p - surface;
477 G4double distPhi = normal.dot(ps);
478
479 //
480 // Calculate projected point in r,z
481 //
482 G4double r = radial.dot(p);
483
484 //
485 // Are we inside the face?
486 //
487 G4double distRZ2;
488 G4PolyPhiFaceVertex* base3Dnorm = nullptr;
489 G4ThreeVector* head3Dnorm = nullptr;
490
491 if (InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm ))
492 {
493 //
494 // Looks like we're inside. Distance is distance in phi.
495 //
496 *bestDistance = std::fabs(distPhi);
497
498 //
499 // Use distPhi to decide fate
500 //
501 if (distPhi < -tolerance) return kInside;
502 if (distPhi < tolerance) return kSurface;
503 return kOutside;
504 }
505 else
506 {
507 //
508 // We're outside the extent of the face,
509 // so the distance is penalized by distance from edges in RZ
510 //
511 *bestDistance = std::sqrt( distPhi*distPhi + distRZ2 );
512
513 //
514 // Use edge normal to decide fate
515 //
516 G4ThreeVector cc( base3Dnorm->r*radial.x(),
517 base3Dnorm->r*radial.y(),
518 base3Dnorm->z );
519 cc = p - cc;
520 G4double normDist = head3Dnorm->dot(cc);
521 if ( distRZ2 > tolerance*tolerance )
522 {
523 //
524 // We're far enough away that kSurface is not possible
525 //
526 return normDist < 0 ? kInside : kOutside;
527 }
528
529 if (normDist < -tolerance) return kInside;
530 if (normDist < tolerance) return kSurface;
531 return kOutside;
532 }
533}
534
535// Normal
536//
537// This virtual member is simple for our planer shape,
538// which has only one normal
539//
541 G4double* bestDistance )
542{
543 //
544 // Get distance along phi, which if negative means the point
545 // is nominally inside the shape.
546 //
547 G4double distPhi = normal.dot(p);
548
549 //
550 // Calculate projected point in r,z
551 //
552 G4double r = radial.dot(p);
553
554 //
555 // Are we inside the face?
556 //
557 G4double distRZ2;
558
559 if (InsideEdges( r, p.z(), &distRZ2, nullptr ))
560 {
561 //
562 // Yup, answer is just distPhi
563 //
564 *bestDistance = std::fabs(distPhi);
565 }
566 else
567 {
568 //
569 // Nope. Penalize by distance out
570 //
571 *bestDistance = std::sqrt( distPhi*distPhi + distRZ2 );
572 }
573
574 return normal;
575}
576
577// Extent
578//
579// This actually isn't needed by polycone or polyhedra...
580//
582{
583 G4double max = -kInfinity;
584
586 do // Loop checking, 13.08.2015, G.Cosmo
587 {
588 G4double here = axis.x()*corner->r*radial.x()
589 + axis.y()*corner->r*radial.y()
590 + axis.z()*corner->z;
591 if (here > max) max = here;
592 } while( ++corner < corners + numEdges );
593
594 return max;
595}
596
597// CalculateExtent
598//
599// See notes in G4VCSGface
600//
602 const G4VoxelLimits& voxelLimit,
603 const G4AffineTransform& transform,
604 G4SolidExtentList& extentList )
605{
606 //
607 // Construct a (sometimes big) clippable polygon,
608 //
609 // Perform the necessary transformations while doing so
610 //
611 G4ClippablePolygon polygon;
612
614 do // Loop checking, 13.08.2015, G.Cosmo
615 {
616 G4ThreeVector point( 0, 0, corner->z );
617 point += radial*corner->r;
618
619 polygon.AddVertexInOrder( transform.TransformPoint( point ) );
620 } while( ++corner < corners + numEdges );
621
622 //
623 // Clip away
624 //
625 if (polygon.PartialClip( voxelLimit, axis ))
626 {
627 //
628 // Add it to the list
629 //
630 polygon.SetNormal( transform.TransformAxis(normal) );
631 extentList.AddSurface( polygon );
632 }
633}
634
635// InsideEdgesExact
636//
637// Decide if the point in r,z is inside the edges of our face,
638// **but** do so consistently with other faces.
639//
640// This routine has functionality similar to InsideEdges, but uses
641// an algorithm to decide if a trajectory falls inside or outside the
642// face that uses only the trajectory p,v values and the three dimensional
643// points representing the edges of the polygon. The objective is to plug up
644// any leaks between touching G4PolyPhiFaces (at r==0) and any other face
645// that uses the same convention.
646//
647// See: "Computational Geometry in C (Second Edition)"
648// http://cs.smith.edu/~orourke/
649//
651 G4double normSign,
652 const G4ThreeVector& p,
653 const G4ThreeVector& v )
654{
655 //
656 // Quick check of extent
657 //
658 if ( (r < rMin-kCarTolerance)
659 || (r > rMax+kCarTolerance) ) return false;
660
661 if ( (z < zMin-kCarTolerance)
662 || (z > zMax+kCarTolerance) ) return false;
663
664 //
665 // Exact check: loop over all vertices
666 //
667 G4double qx = p.x() + v.x(),
668 qy = p.y() + v.y(),
669 qz = p.z() + v.z();
670
671 G4int answer = 0;
673 *prev = corners+numEdges-1;
674
675 G4double cornZ, prevZ;
676
677 prevZ = ExactZOrder( z, qx, qy, qz, v, normSign, prev );
678 do // Loop checking, 13.08.2015, G.Cosmo
679 {
680 //
681 // Get z order of this vertex, and compare to previous vertex
682 //
683 cornZ = ExactZOrder( z, qx, qy, qz, v, normSign, corn );
684
685 if (cornZ < 0)
686 {
687 if (prevZ < 0) continue;
688 }
689 else if (cornZ > 0)
690 {
691 if (prevZ > 0) continue;
692 }
693 else
694 {
695 //
696 // By chance, we overlap exactly (within precision) with
697 // the current vertex. Continue if the same happened previously
698 // (e.g. the previous vertex had the same z value)
699 //
700 if (prevZ == 0) continue;
701
702 //
703 // Otherwise, to decide what to do, we need to know what is
704 // coming up next. Specifically, we need to find the next vertex
705 // with a non-zero z order.
706 //
707 // One might worry about infinite loops, but the above conditional
708 // should prevent it
709 //
710 G4PolyPhiFaceVertex *next = corn;
711 G4double nextZ;
712 do // Loop checking, 13.08.2015, G.Cosmo
713 {
714 ++next;
715 if (next == corners+numEdges) next = corners;
716
717 nextZ = ExactZOrder( z, qx, qy, qz, v, normSign, next );
718 } while( nextZ == 0 );
719
720 //
721 // If we won't be changing direction, go to the next vertex
722 //
723 if (nextZ*prevZ < 0) continue;
724 }
725
726
727 //
728 // We overlap in z with the side of the face that stretches from
729 // vertex "prev" to "corn". On which side (left or right) do
730 // we lay with respect to this segment?
731 //
732 G4ThreeVector qa( qx - prev->x, qy - prev->y, qz - prev->z ),
733 qb( qx - corn->x, qy - corn->y, qz - corn->z );
734
735 G4double aboveOrBelow = normSign*qa.cross(qb).dot(v);
736
737 if (aboveOrBelow > 0)
738 ++answer;
739 else if (aboveOrBelow < 0)
740 --answer;
741 else
742 {
743 //
744 // A precisely zero answer here means we exactly
745 // intersect (within roundoff) the edge of the face.
746 // Return true in this case.
747 //
748 return true;
749 }
750 } while( prevZ = cornZ, prev=corn, ++corn < corners+numEdges );
751
752 return answer!=0;
753}
754
755// InsideEdges (don't care about distance)
756//
757// Decide if the point in r,z is inside the edges of our face
758//
759// This routine can be made a zillion times quicker by implementing
760// better code, for example:
761//
762// int pnpoly(int npol, float *xp, float *yp, float x, float y)
763// {
764// int i, j, c = 0;
765// for (i = 0, j = npol-1; i < npol; j = i++) {
766// if ((((yp[i]<=y) && (y<yp[j])) ||
767// ((yp[j]<=y) && (y<yp[i]))) &&
768// (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
769//
770// c = !c;
771// }
772// return c;
773// }
774//
775// See "Point in Polyon Strategies", Eric Haines [Graphic Gems IV] pp. 24-46
776//
777// The algorithm below is rather unique, but is based on code needed to
778// calculate the distance to the shape. Left here for testing...
779//
781{
782 //
783 // Quick check of extent
784 //
785 if ( r < rMin || r > rMax ) return false;
786 if ( z < zMin || z > zMax ) return false;
787
788 //
789 // More thorough check
790 //
791 G4double notUsed;
792
793 return InsideEdges( r, z, &notUsed, nullptr );
794}
795
796// InsideEdges (care about distance)
797//
798// Decide if the point in r,z is inside the edges of our face
799//
801 G4double* bestDist2,
802 G4PolyPhiFaceVertex** base3Dnorm,
803 G4ThreeVector** head3Dnorm )
804{
805 G4double bestDistance2 = kInfinity;
806 G4bool answer = false;
807
808 G4PolyPhiFaceEdge* edge = edges;
809 do // Loop checking, 13.08.2015, G.Cosmo
810 {
811 G4PolyPhiFaceVertex* testMe = nullptr;
812 G4PolyPhiFaceVertex* v0_vertex = edge->v0;
813 G4PolyPhiFaceVertex* v1_vertex = edge->v1;
814 //
815 // Get distance perpendicular to the edge
816 //
817 G4double dr = (r-v0_vertex->r), dz = (z-v0_vertex->z);
818
819 G4double distOut = dr*edge->tz - dz*edge->tr;
820 G4double distance2 = distOut*distOut;
821 if (distance2 > bestDistance2) continue; // No hope!
822
823 //
824 // Check to see if normal intersects edge within the edge's boundary
825 //
826 G4double q = dr*edge->tr + dz*edge->tz;
827
828 //
829 // If it doesn't, penalize distance2 appropriately
830 //
831 if (q < 0)
832 {
833 distance2 += q*q;
834 testMe = v0_vertex;
835 }
836 else if (q > edge->length)
837 {
838 G4double s2 = q-edge->length;
839 distance2 += s2*s2;
840 testMe = v1_vertex;
841 }
842
843 //
844 // Closest edge so far?
845 //
846 if (distance2 < bestDistance2)
847 {
848 bestDistance2 = distance2;
849 if (testMe != nullptr)
850 {
851 G4double distNorm = dr*testMe->rNorm + dz*testMe->zNorm;
852 answer = (distNorm <= 0);
853 if (base3Dnorm != nullptr)
854 {
855 *base3Dnorm = testMe;
856 *head3Dnorm = &testMe->norm3D;
857 }
858 }
859 else
860 {
861 answer = (distOut <= 0);
862 if (base3Dnorm != nullptr)
863 {
864 *base3Dnorm = v0_vertex;
865 *head3Dnorm = &edge->norm3D;
866 }
867 }
868 }
869 } while( ++edge < edges + numEdges );
870
871 *bestDist2 = bestDistance2;
872 return answer;
873}
874
875// Calculation of Surface Area of a Triangle
876// In the same time Random Point in Triangle is given
877//
879 const G4ThreeVector& p2,
880 const G4ThreeVector& p3,
881 G4ThreeVector* p4 )
882{
883 G4ThreeVector v, w;
884
885 v = p3 - p1;
886 w = p1 - p2;
887 G4double lambda1 = G4UniformRand();
888 G4double lambda2 = lambda1*G4UniformRand();
889
890 *p4=p2 + lambda1*w + lambda2*v;
891 return 0.5*(v.cross(w)).mag();
892}
893
894// Compute surface area
895//
897{
898 if ( fSurfaceArea==0. ) { Triangulate(); }
899 return fSurfaceArea;
900}
901
902// Return random point on face
903//
909
910//
911// Auxiliary Functions used for Finding the PointOnFace using Triangulation
912//
913
914// Calculation of 2*Area of Triangle with Sign
915//
917 const G4TwoVector& b,
918 const G4TwoVector& c )
919{
920 return ((b.x()-a.x())*(c.y()-a.y())-
921 (c.x()-a.x())*(b.y()-a.y()));
922}
923
924// Boolean function for sign of Surface
925//
927 const G4TwoVector& b,
928 const G4TwoVector& c )
929{
930 return Area2(a,b,c)>0;
931}
932
933// Boolean function for sign of Surface
934//
936 const G4TwoVector& b,
937 const G4TwoVector& c )
938{
939 return Area2(a,b,c)>=0;
940}
941
942// Boolean function for sign of Surface
943//
945 const G4TwoVector& b,
946 const G4TwoVector& c )
947{
948 return Area2(a,b,c)==0;
949}
950
951// Boolean function for finding "Proper" Intersection
952// That means Intersection of two lines segments (a,b) and (c,d)
953//
955 const G4TwoVector& b,
956 const G4TwoVector& c, const G4TwoVector& d )
957{
958 if( Collinear(a,b,c) || Collinear(a,b,d)||
959 Collinear(c,d,a) || Collinear(c,d,b) ) { return false; }
960
961 G4bool Positive;
962 Positive = !(Left(a,b,c))^!(Left(a,b,d));
963 return Positive && ((!Left(c,d,a)^!Left(c,d,b)) != 0);
964}
965
966// Boolean function for determining if Point c is between a and b
967// For the tree points(a,b,c) on the same line
968//
970{
971 if( !Collinear(a,b,c) ) { return false; }
972
973 if(a.x()!=b.x())
974 {
975 return ((a.x()<=c.x())&&(c.x()<=b.x()))||
976 ((a.x()>=c.x())&&(c.x()>=b.x()));
977 }
978 else
979 {
980 return ((a.y()<=c.y())&&(c.y()<=b.y()))||
981 ((a.y()>=c.y())&&(c.y()>=b.y()));
982 }
983}
984
985// Boolean function for finding Intersection "Proper" or not
986// Between two line segments (a,b) and (c,d)
987//
989 const G4TwoVector& b,
990 const G4TwoVector& c, const G4TwoVector& d )
991{
992 if( IntersectProp(a,b,c,d) )
993 { return true; }
994 else if( Between(a,b,c)||
995 Between(a,b,d)||
996 Between(c,d,a)||
997 Between(c,d,b) )
998 { return true; }
999 else
1000 { return false; }
1001}
1002
1003// Boolean Diagonalie help to determine
1004// if diagonal s of segment (a,b) is convex or reflex
1005//
1008{
1010 G4PolyPhiFaceVertex *corner_next=triangles;
1011
1012 // For each Edge (corner,corner_next)
1013 do // Loop checking, 13.08.2015, G.Cosmo
1014 {
1015 corner_next=corner->next;
1016
1017 // Skip edges incident to a of b
1018 //
1019 if( (corner!=a)&&(corner_next!=a)
1020 &&(corner!=b)&&(corner_next!=b) )
1021 {
1022 G4TwoVector rz1,rz2,rz3,rz4;
1023 rz1 = G4TwoVector(a->r,a->z);
1024 rz2 = G4TwoVector(b->r,b->z);
1025 rz3 = G4TwoVector(corner->r,corner->z);
1026 rz4 = G4TwoVector(corner_next->r,corner_next->z);
1027 if( Intersect(rz1,rz2,rz3,rz4) ) { return false; }
1028 }
1029 corner=corner->next;
1030
1031 } while( corner != triangles );
1032
1033 return true;
1034}
1035
1036// Boolean function that determine if b is Inside Cone (a0,a,a1)
1037// being a the center of the Cone
1038//
1040{
1041 // a0,a and a1 are consecutive vertices
1042 //
1044 a1=a->next;
1045 a0=a->prev;
1046
1047 G4TwoVector arz,arz0,arz1,brz;
1048 arz=G4TwoVector(a->r,a->z);arz0=G4TwoVector(a0->r,a0->z);
1049 arz1=G4TwoVector(a1->r,a1->z);brz=G4TwoVector(b->r,b->z);
1050
1051
1052 if(LeftOn(arz,arz1,arz0)) // If a is convex vertex
1053 {
1054 return Left(arz,brz,arz0)&&Left(brz,arz,arz1);
1055 }
1056 else // Else a is reflex
1057 {
1058 return !( LeftOn(arz,brz,arz1)&&LeftOn(brz,arz,arz0));
1059 }
1060}
1061
1062// Boolean function finding if Diagonal is possible
1063// inside Polycone or PolyHedra
1064//
1066{
1067 return InCone(a,b) && InCone(b,a) && Diagonalie(a,b);
1068}
1069
1070// Initialisation for Triangulisation by ear tips
1071// For details see "Computational Geometry in C" by Joseph O'Rourke
1072//
1074{
1076 G4PolyPhiFaceVertex* c_prev, *c_next;
1077
1078 do // Loop checking, 13.08.2015, G.Cosmo
1079 {
1080 // We need to determine three consecutive vertices
1081 //
1082 c_next=corner->next;
1083 c_prev=corner->prev;
1084
1085 // Calculation of ears
1086 //
1087 corner->ear=Diagonal(c_prev,c_next);
1088 corner=corner->next;
1089
1090 } while( corner!=triangles );
1091}
1092
1093// Triangulisation by ear tips for Polycone or Polyhedra
1094// For details see "Computational Geometry in C" by Joseph O'Rourke
1095//
1097{
1098 // The copy of Polycone is made and this copy is reordered in order to
1099 // have a list of triangles. This list is used for GetPointOnFace().
1100
1101 const std::size_t maxEdges = (numEdges > 0) ? numEdges : 1;
1102 auto tri_help = new G4PolyPhiFaceVertex[maxEdges];
1103 triangles = tri_help;
1105
1106 std::vector<G4double> areas;
1107 std::vector<G4ThreeVector> points;
1108 G4double area=0.;
1109 G4PolyPhiFaceVertex *v0,*v1,*v2,*v3,*v4;
1110 v2=triangles;
1111
1112 // Make copy for prev/next for triang=corners
1113 //
1114 G4PolyPhiFaceVertex* helper = corners;
1115 G4PolyPhiFaceVertex* helper2 = corners;
1116 do // Loop checking, 13.08.2015, G.Cosmo
1117 {
1118 triang->r = helper->r;
1119 triang->z = helper->z;
1120 triang->x = helper->x;
1121 triang->y = helper->y;
1122
1123 // add pointer on prev corner
1124 //
1125 if( helper==corners )
1126 { triang->prev=triangles+maxEdges-1; }
1127 else
1128 { triang->prev=helper2; }
1129
1130 // add pointer on next corner
1131 //
1132 if( helper<corners+maxEdges-1 )
1133 { triang->next=triang+1; }
1134 else
1135 { triang->next=triangles; }
1136 helper2=triang;
1137 helper=helper->next;
1138 triang=triang->next;
1139
1140 } while( helper!=corners );
1141
1142 EarInit();
1143
1144 G4int n=numEdges;
1145 G4int i=0;
1146 G4ThreeVector p1,p2,p3,p4;
1147 const G4int max_n_loops=numEdges*10000; // protection against infinite loop
1148
1149 // Each step of outer loop removes one ear
1150 //
1151 while(n>3) // Loop checking, 13.08.2015, G.Cosmo
1152 { // Inner loop searches for one ear
1153 v2=triangles;
1154 do // Loop checking, 13.08.2015, G.Cosmo
1155 {
1156 if(v2->ear) // Ear found. Fill variables
1157 {
1158 // (v1,v3) is diagonal
1159 //
1160 v3=v2->next; v4=v3->next;
1161 v1=v2->prev; v0=v1->prev;
1162
1163 // Calculate areas and points
1164
1165 p1=G4ThreeVector((v2)->x,(v2)->y,(v2)->z);
1166 p2=G4ThreeVector((v1)->x,(v1)->y,(v1)->z);
1167 p3=G4ThreeVector((v3)->x,(v3)->y,(v3)->z);
1168
1169 G4double result1 = SurfaceTriangle(p1,p2,p3,&p4 );
1170 points.push_back(p4);
1171 areas.push_back(result1);
1172 area=area+result1;
1173
1174 // Update earity of diagonal endpoints
1175 //
1176 v1->ear=Diagonal(v0,v3);
1177 v3->ear=Diagonal(v1,v4);
1178
1179 // Cut off the ear v2
1180 // Has to be done for a copy and not for real PolyPhiFace
1181 //
1182 v1->next=v3;
1183 v3->prev=v1;
1184 triangles=v3; // In case the head was v2
1185 --n;
1186
1187 break; // out of inner loop
1188 } // end if ear found
1189
1190 v2=v2->next;
1191
1192 } while( v2!=triangles );
1193
1194 ++i;
1195 if(i>=max_n_loops)
1196 {
1197 G4Exception( "G4PolyPhiFace::Triangulation()",
1198 "GeomSolids0003", FatalException,
1199 "Maximum number of steps is reached for triangulation!" );
1200 }
1201 } // end outer while loop
1202
1203 if(v2->next != nullptr)
1204 {
1205 // add last triangle
1206 //
1207 v2=v2->next;
1208 p1=G4ThreeVector((v2)->x,(v2)->y,(v2)->z);
1209 p2=G4ThreeVector((v2->next)->x,(v2->next)->y,(v2->next)->z);
1210 p3=G4ThreeVector((v2->prev)->x,(v2->prev)->y,(v2->prev)->z);
1211 G4double result1 = SurfaceTriangle(p1,p2,p3,&p4 );
1212 points.push_back(p4);
1213 areas.push_back(result1);
1214 area=area+result1;
1215 }
1216
1217 // Surface Area is stored
1218 //
1219 fSurfaceArea = area;
1220
1221 // Second Step: choose randomly one surface
1222 //
1223 G4double chose = area*G4UniformRand();
1224
1225 // Third Step: Get a point on choosen surface
1226 //
1227 G4double Achose1, Achose2;
1228 Achose1=0; Achose2=0.;
1229 i=0;
1230 do // Loop checking, 13.08.2015, G.Cosmo
1231 {
1232 Achose2+=areas[i];
1233 if(chose>=Achose1 && chose<Achose2)
1234 {
1235 G4ThreeVector point;
1236 point=points[i];
1237 surface_point=point;
1238 break;
1239 }
1240 ++i; Achose1=Achose2;
1241 } while( i<numEdges-2 );
1242
1243 delete [] tri_help;
1244 tri_help = nullptr;
1245}
const G4double kCarTolerance
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
const G4double a0
CLHEP::Hep3Vector G4ThreeVector
CLHEP::Hep2Vector G4TwoVector
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4UniformRand()
Definition Randomize.hh:52
double x() const
double y() const
double z() const
Hep3Vector unit() const
double x() const
double y() const
Hep3Vector cross(const Hep3Vector &) const
double dot(const Hep3Vector &) const
double mag() const
G4ThreeVector TransformPoint(const G4ThreeVector &vec) const
G4ThreeVector TransformAxis(const G4ThreeVector &axis) const
virtual G4bool PartialClip(const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe)
virtual void AddVertexInOrder(const G4ThreeVector vertex)
void SetNormal(const G4ThreeVector &newNormal)
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
G4double Distance(const G4ThreeVector &p, G4bool outgoing) override
G4double Area2(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c)
G4bool LeftOn(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c)
G4ThreeVector GetPointOnFace() override
EInside Inside(const G4ThreeVector &p, G4double tolerance, G4double *bestDistance) override
G4bool Collinear(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c)
void Diagnose(G4VSolid *solid)
void CalculateExtent(const EAxis axis, const G4VoxelLimits &voxelLimit, const G4AffineTransform &tranform, G4SolidExtentList &extentList) override
G4PolyPhiFace & operator=(const G4PolyPhiFace &source)
G4bool Diagonal(G4PolyPhiFaceVertex *a, G4PolyPhiFaceVertex *b)
G4ThreeVector surface_point
G4bool InsideEdges(G4double r, G4double z)
G4bool Left(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c)
G4bool Diagonalie(G4PolyPhiFaceVertex *a, G4PolyPhiFaceVertex *b)
G4double SurfaceTriangle(const G4ThreeVector &p1, const G4ThreeVector &p2, const G4ThreeVector &p3, G4ThreeVector *p4)
G4ThreeVector surface
G4double fSurfaceArea
G4bool IntersectProp(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c, const G4TwoVector &d)
void CopyStuff(const G4PolyPhiFace &source)
G4double ExactZOrder(G4double z, G4double qx, G4double qy, G4double qz, const G4ThreeVector &v, G4double normSign, const G4PolyPhiFaceVertex *vert) const
G4double Extent(const G4ThreeVector axis) override
G4PolyPhiFaceEdge * edges
G4ThreeVector radial
G4ThreeVector Normal(const G4ThreeVector &p, G4double *bestDistance) override
G4bool InCone(G4PolyPhiFaceVertex *a, G4PolyPhiFaceVertex *b)
G4bool Intersect(const G4ThreeVector &p, const G4ThreeVector &v, G4bool outgoing, G4double surfTolerance, G4double &distance, G4double &distFromSurface, G4ThreeVector &normal, G4bool &allBehind) override
G4PolyPhiFaceVertex * corners
G4PolyPhiFaceVertex * triangles
G4ThreeVector normal
~G4PolyPhiFace() override
G4double SurfaceArea() override
G4bool Between(const G4TwoVector &a, const G4TwoVector &b, const G4TwoVector &c)
G4double kCarTolerance
G4bool InsideEdgesExact(G4double r, G4double z, G4double normSign, const G4ThreeVector &p, const G4ThreeVector &v)
G4PolyPhiFace(const G4ReduciblePolygon *rz, G4double phi, G4double deltaPhi, G4double phiOther)
G4double Amin() const
G4double Bmin() const
G4double Bmax() const
G4double Amax() const
void AddSurface(const G4ClippablePolygon &surface)
virtual EInside Inside(const G4ThreeVector &p) const =0
EAxis
Definition geomdefs.hh:54
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69
G4PolyPhiFaceVertex * v1
G4ThreeVector norm3D
G4PolyPhiFaceVertex * v0
G4ThreeVector norm3D
G4PolyPhiFaceVertex * next
G4PolyPhiFaceVertex * prev
#define DBL_MIN
Definition templates.hh:54