Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/specific/src/G4PolyPhiFace.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 (davidw@scipp.ucsc.edu)
 30 // --------------------------------------------------------------------
 31 
 32 #include "G4PolyPhiFace.hh"
 33 #include "G4ClippablePolygon.hh"
 34 #include "G4ReduciblePolygon.hh"
 35 #include "G4AffineTransform.hh"
 36 #include "G4SolidExtentList.hh"
 37 #include "G4GeometryTolerance.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 //
 51 G4PolyPhiFace::G4PolyPhiFace( const G4ReduciblePolygon* rz,
 52                                     G4double phi, 
 53                                     G4double deltaPhi,
 54                                     G4double phiOther )
 55 {
 56   kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
 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   //
100   G4ReduciblePolygonIterator iterRZ(rz);
101   
102   G4PolyPhiFaceVertex* corn   = corners;
103   G4PolyPhiFaceVertex* helper = corners;
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 //
259 void G4PolyPhiFace::Diagnose( G4VSolid* owner )
260 {
261   G4PolyPhiFaceVertex* corner = corners;
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 //
276 G4PolyPhiFace::G4PolyPhiFace( __void__&)
277   : numEdges(0), rMin(0.), rMax(0.), zMin(0.), zMax(0.), kCarTolerance(0.)
278 {
279 }
280 
281 
282 //
283 // Destructor
284 //
285 G4PolyPhiFace::~G4PolyPhiFace()
286 {
287   delete [] edges;
288   delete [] corners;
289 }
290 
291 
292 //
293 // Copy constructor
294 //
295 G4PolyPhiFace::G4PolyPhiFace( const G4PolyPhiFace& source )
296 {
297   CopyStuff( source );
298 }
299 
300 
301 //
302 // Assignment operator
303 //
304 G4PolyPhiFace& G4PolyPhiFace::operator=( const G4PolyPhiFace& source )
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 //
320 void G4PolyPhiFace::CopyStuff( const G4PolyPhiFace& source )
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 
336   kCarTolerance = source.kCarTolerance;
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];
345   G4PolyPhiFaceVertex *corn = corners,
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 //
371 G4bool G4PolyPhiFace::Intersect( const G4ThreeVector& p,
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 //
426 G4double G4PolyPhiFace::Distance( const G4ThreeVector& p, G4bool outgoing )
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 //
468 EInside G4PolyPhiFace::Inside( const G4ThreeVector& p,
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 //
540 G4ThreeVector G4PolyPhiFace::Normal( const G4ThreeVector& p,
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 //
581 G4double G4PolyPhiFace::Extent( const G4ThreeVector axis )
582 {
583   G4double max = -kInfinity;
584   
585   G4PolyPhiFaceVertex* corner = corners;
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 //
601 void G4PolyPhiFace::CalculateExtent( const EAxis axis, 
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   
613   G4PolyPhiFaceVertex* corner = corners;
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 //
650 G4bool G4PolyPhiFace::InsideEdgesExact( G4double r, G4double z,
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;
672   G4PolyPhiFaceVertex *corn = corners, 
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 //
780 G4bool G4PolyPhiFace::InsideEdges( G4double r, G4double z )
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 //
800 G4bool G4PolyPhiFace::InsideEdges( G4double r, G4double z,
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 //
878 G4double G4PolyPhiFace::SurfaceTriangle( const G4ThreeVector& p1,
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 //
896 G4double G4PolyPhiFace::SurfaceArea()
897 {
898   if ( fSurfaceArea==0. ) { Triangulate(); }
899   return fSurfaceArea;
900 }
901 
902 // Return random point on face
903 //
904 G4ThreeVector G4PolyPhiFace::GetPointOnFace()
905 {
906   Triangulate();
907   return surface_point;
908 }
909 
910 //
911 // Auxiliary Functions used for Finding the PointOnFace using Triangulation
912 //
913 
914 // Calculation of 2*Area of Triangle with Sign
915 //
916 G4double G4PolyPhiFace::Area2( const G4TwoVector& a,
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 //
926 G4bool G4PolyPhiFace::Left( const G4TwoVector& a,
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 //
935 G4bool G4PolyPhiFace::LeftOn( const G4TwoVector& a,
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 //
944 G4bool G4PolyPhiFace::Collinear( const G4TwoVector& a,
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 // 
954 G4bool G4PolyPhiFace::IntersectProp( const G4TwoVector& a,
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 //
969 G4bool G4PolyPhiFace::Between( const G4TwoVector& a, const G4TwoVector& b, const G4TwoVector& c )
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 //
988 G4bool G4PolyPhiFace::Intersect( const G4TwoVector& a,
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 //
1006 G4bool G4PolyPhiFace::Diagonalie( G4PolyPhiFaceVertex* a,
1007                                   G4PolyPhiFaceVertex* b )
1008 {
1009   G4PolyPhiFaceVertex   *corner = triangles;
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 //
1039 G4bool G4PolyPhiFace::InCone( G4PolyPhiFaceVertex* a, G4PolyPhiFaceVertex* b )
1040 {
1041   // a0,a and a1 are consecutive vertices
1042   //
1043   G4PolyPhiFaceVertex *a0,*a1;
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 //
1065 G4bool G4PolyPhiFace::Diagonal( G4PolyPhiFaceVertex* a, G4PolyPhiFaceVertex* b )
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 //
1073 void G4PolyPhiFace::EarInit()
1074 {
1075   G4PolyPhiFaceVertex* corner = triangles;
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 //
1096 void G4PolyPhiFace::Triangulate()
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;
1104   G4PolyPhiFaceVertex* triang = triangles;
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 }
1246