Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4PolyhedraSide.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 //
27 // $Id: G4PolyhedraSide.cc 67011 2013-01-29 16:17:41Z gcosmo $
28 //
29 //
30 // --------------------------------------------------------------------
31 // GEANT 4 class source file
32 //
33 //
34 // G4PolyhedraSide.cc
35 //
36 // Implementation of the face representing one segmented side of a Polyhedra
37 //
38 // --------------------------------------------------------------------
39 
40 #include "G4PolyhedraSide.hh"
41 #include "G4PhysicalConstants.hh"
42 #include "G4IntersectingCone.hh"
43 #include "G4ClippablePolygon.hh"
44 #include "G4AffineTransform.hh"
45 #include "G4SolidExtentList.hh"
46 #include "G4GeometryTolerance.hh"
47 
48 #include "Randomize.hh"
49 
50 //
51 // Constructor
52 //
53 // Values for r1,z1 and r2,z2 should be specified in clockwise
54 // order in (r,z).
55 //
57  const G4PolyhedraSideRZ *tail,
58  const G4PolyhedraSideRZ *head,
59  const G4PolyhedraSideRZ *nextRZ,
60  G4int theNumSide,
61  G4double thePhiStart,
62  G4double thePhiTotal,
63  G4bool thePhiIsOpen,
64  G4bool isAllBehind )
65 {
67  fSurfaceArea=0.;
68  fPhi.first = G4ThreeVector(0,0,0);
69  fPhi.second= 0.0;
70 
71  //
72  // Record values
73  //
74  r[0] = tail->r; z[0] = tail->z;
75  r[1] = head->r; z[1] = head->z;
76 
77  G4double phiTotal;
78 
79  //
80  // Set phi to our convention
81  //
82  startPhi = thePhiStart;
83  while (startPhi < 0.0) startPhi += twopi;
84 
85  phiIsOpen = thePhiIsOpen;
86  phiTotal = (phiIsOpen) ? thePhiTotal : twopi;
87 
88  allBehind = isAllBehind;
89 
90  //
91  // Make our intersecting cone
92  //
93  cone = new G4IntersectingCone( r, z );
94 
95  //
96  // Construct side plane vector set
97  //
98  numSide = theNumSide;
99  deltaPhi = phiTotal/theNumSide;
100  endPhi = startPhi+phiTotal;
101 
103 
105 
106  //
107  // ...this is where we start
108  //
109  G4double phi = startPhi;
110  G4ThreeVector a1( r[0]*std::cos(phi), r[0]*std::sin(phi), z[0] ),
111  b1( r[1]*std::cos(phi), r[1]*std::sin(phi), z[1] ),
112  c1( prevRZ->r*std::cos(phi), prevRZ->r*std::sin(phi), prevRZ->z ),
113  d1( nextRZ->r*std::cos(phi), nextRZ->r*std::sin(phi), nextRZ->z ),
114  a2, b2, c2, d2;
115  G4PolyhedraSideEdge *edge = edges;
116 
117  G4PolyhedraSideVec *vec = vecs;
118  do
119  {
120  //
121  // ...this is where we are going
122  //
123  phi += deltaPhi;
124  a2 = G4ThreeVector( r[0]*std::cos(phi), r[0]*std::sin(phi), z[0] );
125  b2 = G4ThreeVector( r[1]*std::cos(phi), r[1]*std::sin(phi), z[1] );
126  c2 = G4ThreeVector( prevRZ->r*std::cos(phi), prevRZ->r*std::sin(phi), prevRZ->z );
127  d2 = G4ThreeVector( nextRZ->r*std::cos(phi), nextRZ->r*std::sin(phi), nextRZ->z );
128 
129  G4ThreeVector tt;
130 
131  //
132  // ...build some relevant vectors.
133  // the point is to sacrifice a little memory with precalcs
134  // to gain speed
135  //
136  vec->center = 0.25*( a1 + a2 + b1 + b2 );
137 
138  tt = b2 + b1 - a2 - a1;
139  vec->surfRZ = tt.unit();
140  if (vec==vecs) lenRZ = 0.25*tt.mag();
141 
142  tt = b2 - b1 + a2 - a1;
143  vec->surfPhi = tt.unit();
144  if (vec==vecs)
145  {
146  lenPhi[0] = 0.25*tt.mag();
147  tt = b2 - b1;
148  lenPhi[1] = (0.5*tt.mag()-lenPhi[0])/lenRZ;
149  }
150 
151  tt = vec->surfPhi.cross(vec->surfRZ);
152  vec->normal = tt.unit();
153 
154  //
155  // ...edge normals are the average of the normals of
156  // the two faces they connect.
157  //
158  // ...edge normals are necessary if we are to accurately
159  // decide if a point is "inside" a face. For non-convex
160  // shapes, it is absolutely necessary to know information
161  // on adjacent faces to accurate determine this.
162  //
163  // ...we don't need them for the phi edges, since that
164  // information is taken care of internally. The r/z edges,
165  // however, depend on the adjacent G4PolyhedraSide.
166  //
167  G4ThreeVector a12, adj;
168 
169  a12 = a2-a1;
170 
171  adj = 0.5*(c1+c2-a1-a2);
172  adj = adj.cross(a12);
173  adj = adj.unit() + vec->normal;
174  vec->edgeNorm[0] = adj.unit();
175 
176  a12 = b1-b2;
177  adj = 0.5*(d1+d2-b1-b2);
178  adj = adj.cross(a12);
179  adj = adj.unit() + vec->normal;
180  vec->edgeNorm[1] = adj.unit();
181 
182  //
183  // ...the corners are crucial. It is important that
184  // they are calculated consistently for adjacent
185  // G4PolyhedraSides, to avoid gaps caused by roundoff.
186  //
187  vec->edges[0] = edge;
188  edge->corner[0] = a1;
189  edge->corner[1] = b1;
190  edge++;
191  vec->edges[1] = edge;
192 
193  a1 = a2;
194  b1 = b2;
195  c1 = c2;
196  d1 = d2;
197  } while( ++vec < vecs+numSide );
198 
199  //
200  // Clean up hanging edge
201  //
202  if (phiIsOpen)
203  {
204  edge->corner[0] = a2;
205  edge->corner[1] = b2;
206  }
207  else
208  {
209  vecs[numSide-1].edges[1] = edges;
210  }
211 
212  //
213  // Go back and fill in remaining fields in edges
214  //
215  vec = vecs;
216  G4PolyhedraSideVec *prev = vecs+numSide-1;
217  do
218  {
219  edge = vec->edges[0]; // The edge between prev and vec
220 
221  //
222  // Okay: edge normal is average of normals of adjacent faces
223  //
224  G4ThreeVector eNorm = vec->normal + prev->normal;
225  edge->normal = eNorm.unit();
226 
227  //
228  // Vertex normal is average of norms of adjacent surfaces (all four)
229  // However, vec->edgeNorm is unit vector in some direction
230  // as the sum of normals of adjacent PolyhedraSide with vec.
231  // The normalization used for this vector should be the same
232  // for vec and prev.
233  //
234  eNorm = vec->edgeNorm[0] + prev->edgeNorm[0];
235  edge->cornNorm[0] = eNorm.unit();
236 
237  eNorm = vec->edgeNorm[1] + prev->edgeNorm[1];
238  edge->cornNorm[1] = eNorm.unit();
239  } while( prev=vec, ++vec < vecs + numSide );
240 
241  if (phiIsOpen)
242  {
243  // G4double rFact = std::cos(0.5*deltaPhi);
244  //
245  // If phi is open, we need to patch up normals of the
246  // first and last edges and their corresponding
247  // vertices.
248  //
249  // We use vectors that are in the plane of the
250  // face. This should be safe.
251  //
252  vec = vecs;
253 
254  G4ThreeVector normvec = vec->edges[0]->corner[0]
255  - vec->edges[0]->corner[1];
256  normvec = normvec.cross(vec->normal);
257  if (normvec.dot(vec->surfPhi) > 0) normvec = -normvec;
258 
259  vec->edges[0]->normal = normvec.unit();
260 
261  vec->edges[0]->cornNorm[0] = (vec->edges[0]->corner[0]
262  - vec->center).unit();
263  vec->edges[0]->cornNorm[1] = (vec->edges[0]->corner[1]
264  - vec->center).unit();
265 
266  //
267  // Repeat for ending phi
268  //
269  vec = vecs + numSide - 1;
270 
271  normvec = vec->edges[1]->corner[0] - vec->edges[1]->corner[1];
272  normvec = normvec.cross(vec->normal);
273  if (normvec.dot(vec->surfPhi) < 0) normvec = -normvec;
274 
275  vec->edges[1]->normal = normvec.unit();
276 
277  vec->edges[1]->cornNorm[0] = (vec->edges[1]->corner[0]
278  - vec->center).unit();
279  vec->edges[1]->cornNorm[1] = (vec->edges[1]->corner[1]
280  - vec->center).unit();
281  }
282 
283  //
284  // edgeNorm is the factor one multiplies the distance along vector phi
285  // on the surface of one of our sides in order to calculate the distance
286  // from the edge. (see routine DistanceAway)
287  //
288  edgeNorm = 1.0/std::sqrt( 1.0 + lenPhi[1]*lenPhi[1] );
289 }
290 
291 
292 //
293 // Fake default constructor - sets only member data and allocates memory
294 // for usage restricted to object persistency.
295 //
297  : numSide(0), startPhi(0.), deltaPhi(0.), endPhi(0.),
298  phiIsOpen(false), allBehind(false), cone(0), vecs(0), edges(0),
299  lenRZ(0.), edgeNorm(0.), kCarTolerance(0.), fSurfaceArea(0.)
300 {
301  r[0] = r[1] = 0.;
302  z[0] = z[1] = 0.;
303  lenPhi[0] = lenPhi[1] = 0.;
304 }
305 
306 
307 //
308 // Destructor
309 //
311 {
312  delete cone;
313  delete [] vecs;
314  delete [] edges;
315 }
316 
317 
318 //
319 // Copy constructor
320 //
322  : G4VCSGface()
323 {
324  CopyStuff( source );
325 }
326 
327 
328 //
329 // Assignment operator
330 //
332 {
333  if (this == &source) return *this;
334 
335  delete cone;
336  delete [] vecs;
337  delete [] edges;
338 
339  CopyStuff( source );
340 
341  return *this;
342 }
343 
344 
345 //
346 // CopyStuff
347 //
349 {
350  //
351  // The simple stuff
352  //
353  numSide = source.numSide;
354  r[0] = source.r[0];
355  r[1] = source.r[1];
356  z[0] = source.z[0];
357  z[1] = source.z[1];
358  startPhi = source.startPhi;
359  deltaPhi = source.deltaPhi;
360  endPhi = source.endPhi;
361  phiIsOpen = source.phiIsOpen;
362  allBehind = source.allBehind;
363 
364  lenRZ = source.lenRZ;
365  lenPhi[0] = source.lenPhi[0];
366  lenPhi[1] = source.lenPhi[1];
367  edgeNorm = source.edgeNorm;
368 
369  kCarTolerance = source.kCarTolerance;
370  fSurfaceArea = source.fSurfaceArea;
371 
372  cone = new G4IntersectingCone( *source.cone );
373 
374  //
375  // Duplicate edges
376  //
377  G4int numEdges = phiIsOpen ? numSide+1 : numSide;
378  edges = new G4PolyhedraSideEdge[numEdges];
379 
380  G4PolyhedraSideEdge *edge = edges,
381  *sourceEdge = source.edges;
382  do
383  {
384  *edge = *sourceEdge;
385  } while( ++sourceEdge, ++edge < edges + numEdges);
386 
387  //
388  // Duplicate vecs
389  //
391 
392  G4PolyhedraSideVec *vec = vecs,
393  *sourceVec = source.vecs;
394  do
395  {
396  *vec = *sourceVec;
397  vec->edges[0] = edges + (sourceVec->edges[0] - source.edges);
398  vec->edges[1] = edges + (sourceVec->edges[1] - source.edges);
399  } while( ++sourceVec, ++vec < vecs + numSide );
400 }
401 
402 
403 //
404 // Intersect
405 //
406 // Decide if a line intersects the face.
407 //
408 // Arguments:
409 // p = (in) starting point of line segment
410 // v = (in) direction of line segment (assumed a unit vector)
411 // A, B = (in) 2d transform variables (see note top of file)
412 // normSign = (in) desired sign for dot product with normal (see below)
413 // surfTolerance = (in) minimum distance from the surface
414 // vecs = (in) Vector set array
415 // distance = (out) distance to surface furfilling all requirements
416 // distFromSurface = (out) distance from the surface
417 // thisNormal = (out) normal vector of the intersecting surface
418 //
419 // Return value:
420 // true if an intersection is found. Otherwise, output parameters are
421 // undefined.
422 //
423 // Notes:
424 // * normSign: if we are "inside" the shape and only want to find out how far
425 // to leave the shape, we only want to consider intersections with surfaces in
426 // which the trajectory is leaving the shape. Since the normal vectors to the
427 // surface always point outwards from the inside, this means we want the dot
428 // product of the trajectory direction v and the normal of the side normals[i]
429 // to be positive. Thus, we should specify normSign as +1.0. Otherwise, if
430 // we are outside and want to go in, normSign should be set to -1.0.
431 // Don't set normSign to zero, or you will get no intersections!
432 //
433 // * surfTolerance: see notes on argument "surfTolerance" in routine
434 // "IntersectSidePlane".
435 // ----HOWEVER---- We should *not* apply this surface tolerance if the
436 // starting point is not within phi or z of the surface. Specifically,
437 // if the starting point p angle in x/y places it on a separate side from the
438 // intersection or if the starting point p is outside the z bounds of the
439 // segment, surfTolerance must be ignored or we should *always* accept the
440 // intersection!
441 // This is simply because the sides do not have infinite extent.
442 //
443 //
445  const G4ThreeVector &v,
446  G4bool outgoing,
447  G4double surfTolerance,
448  G4double &distance,
449  G4double &distFromSurface,
450  G4ThreeVector &normal,
451  G4bool &isAllBehind )
452 {
453  G4double normSign = outgoing ? +1 : -1;
454 
455  //
456  // ------------------TO BE IMPLEMENTED---------------------
457  // Testing the intersection of individual phi faces is
458  // pretty straight forward. The simple thing therefore is to
459  // form a loop and check them all in sequence.
460  //
461  // But, I worry about one day someone making
462  // a polygon with a thousands sides. A linear search
463  // would not be ideal in such a case.
464  //
465  // So, it would be nice to be able to quickly decide
466  // which face would be intersected. One can make a very
467  // good guess by using the intersection with a cone.
468  // However, this is only reliable in 99% of the cases.
469  //
470  // My solution: make a decent guess as to the one or
471  // two potential faces might get intersected, and then
472  // test them. If we have the wrong face, use the test
473  // to make a better guess.
474  //
475  // Since we might have two guesses, form a queue of
476  // potential intersecting faces. Keep an array of
477  // already tested faces to avoid doing one more than
478  // once.
479  //
480  // Result: at worst, an iterative search. On average,
481  // a little more than two tests would be required.
482  //
483  G4ThreeVector q = p + v;
484 
485  G4int face = 0;
486  G4PolyhedraSideVec *vec = vecs;
487  do
488  {
489  //
490  // Correct normal?
491  //
492  G4double dotProd = normSign*v.dot(vec->normal);
493  if (dotProd <= 0) continue;
494 
495  //
496  // Is this face in front of the point along the trajectory?
497  //
498  G4ThreeVector delta = p - vec->center;
499  distFromSurface = -normSign*delta.dot(vec->normal);
500 
501  if (distFromSurface < -surfTolerance) continue;
502 
503  //
504  // phi
505  // c -------- d ^
506  // | | |
507  // a -------- b +---> r/z
508  //
509  //
510  // Do we remain on this particular segment?
511  //
512  G4ThreeVector qc = q - vec->edges[1]->corner[0];
513  G4ThreeVector qd = q - vec->edges[1]->corner[1];
514 
515  if (normSign*qc.cross(qd).dot(v) < 0) continue;
516 
517  G4ThreeVector qa = q - vec->edges[0]->corner[0];
518  G4ThreeVector qb = q - vec->edges[0]->corner[1];
519 
520  if (normSign*qa.cross(qb).dot(v) > 0) continue;
521 
522  //
523  // We found the one and only segment we might be intersecting.
524  // Do we remain within r/z bounds?
525  //
526 
527  if (r[0] > 1/kInfinity && normSign*qa.cross(qc).dot(v) < 0) return false;
528  if (r[1] > 1/kInfinity && normSign*qb.cross(qd).dot(v) > 0) return false;
529 
530  //
531  // We allow the face to be slightly behind the trajectory
532  // (surface tolerance) only if the point p is within
533  // the vicinity of the face
534  //
535  if (distFromSurface < 0)
536  {
537  G4ThreeVector ps = p - vec->center;
538 
539  G4double rz = ps.dot(vec->surfRZ);
540  if (std::fabs(rz) > lenRZ+surfTolerance) return false;
541 
542  G4double pp = ps.dot(vec->surfPhi);
543  if (std::fabs(pp) > lenPhi[0] + lenPhi[1]*rz + surfTolerance) return false;
544  }
545 
546 
547  //
548  // Intersection found. Return answer.
549  //
550  distance = distFromSurface/dotProd;
551  normal = vec->normal;
552  isAllBehind = allBehind;
553  return true;
554  } while( ++vec, ++face < numSide );
555 
556  //
557  // Oh well. Better luck next time.
558  //
559  return false;
560 }
561 
562 
564 {
565  G4double normSign = outgoing ? -1 : +1;
566 
567  //
568  // Try the closest phi segment first
569  //
570  G4int iPhi = ClosestPhiSegment( GetPhi(p) );
571 
572  G4ThreeVector pdotc = p - vecs[iPhi].center;
573  G4double normDist = pdotc.dot(vecs[iPhi].normal);
574 
575  if (normSign*normDist > -0.5*kCarTolerance)
576  {
577  return DistanceAway( p, vecs[iPhi], &normDist );
578  }
579 
580  //
581  // Now we have an interesting problem... do we try to find the
582  // closest facing side??
583  //
584  // Considered carefully, the answer is no. We know that if we
585  // are asking for the distance out, we are supposed to be inside,
586  // and vice versa.
587  //
588 
589  return kInfinity;
590 }
591 
592 
593 //
594 // Inside
595 //
597  G4double tolerance,
598  G4double *bestDistance )
599 {
600  //
601  // Which phi segment is closest to this point?
602  //
603  G4int iPhi = ClosestPhiSegment( GetPhi(p) );
604 
605  G4double norm;
606 
607  //
608  // Get distance to this segment
609  //
610  *bestDistance = DistanceToOneSide( p, vecs[iPhi], &norm );
611 
612  //
613  // Use distance along normal to decide return value
614  //
615  if ( (std::fabs(norm) < tolerance) && (*bestDistance < 2.0*tolerance) )
616  return kSurface;
617  else if (norm < 0)
618  return kInside;
619  else
620  return kOutside;
621 }
622 
623 
624 //
625 // Normal
626 //
628  G4double *bestDistance )
629 {
630  //
631  // Which phi segment is closest to this point?
632  //
633  G4int iPhi = ClosestPhiSegment( GetPhi(p) );
634 
635  //
636  // Get distance to this segment
637  //
638  G4double norm;
639  *bestDistance = DistanceToOneSide( p, vecs[iPhi], &norm );
640 
641  return vecs[iPhi].normal;
642 }
643 
644 
645 //
646 // Extent
647 //
649 {
650  if (axis.perp2() < DBL_MIN)
651  {
652  //
653  // Special case
654  //
655  return axis.z() < 0 ? -cone->ZLo() : cone->ZHi();
656  }
657 
658  G4int iPhi, i1, i2;
659  G4double best;
660  G4ThreeVector *list[4];
661 
662  //
663  // Which phi segment, if any, does the axis belong to
664  //
665  iPhi = PhiSegment( GetPhi(axis) );
666 
667  if (iPhi < 0)
668  {
669  //
670  // No phi segment? Check front edge of first side and
671  // last edge of second side
672  //
673  i1 = 0; i2 = numSide-1;
674  }
675  else
676  {
677  //
678  // Check all corners of matching phi side
679  //
680  i1 = iPhi; i2 = iPhi;
681  }
682 
683  list[0] = vecs[i1].edges[0]->corner;
684  list[1] = vecs[i1].edges[0]->corner+1;
685  list[2] = vecs[i2].edges[1]->corner;
686  list[3] = vecs[i2].edges[1]->corner+1;
687 
688  //
689  // Who's biggest?
690  //
691  best = -kInfinity;
692  G4ThreeVector **vec = list;
693  do
694  {
695  G4double answer = (*vec)->dot(axis);
696  if (answer > best) best = answer;
697  } while( ++vec < list+4 );
698 
699  return best;
700 }
701 
702 
703 //
704 // CalculateExtent
705 //
706 // See notes in G4VCSGface
707 //
709  const G4VoxelLimits &voxelLimit,
710  const G4AffineTransform &transform,
711  G4SolidExtentList &extentList )
712 {
713  //
714  // Loop over all sides
715  //
716  G4PolyhedraSideVec *vec = vecs;
717  do
718  {
719  //
720  // Fill our polygon with the four corners of
721  // this side, after the specified transformation
722  //
723  G4ClippablePolygon polygon;
724 
725  polygon.AddVertexInOrder(transform.
726  TransformPoint(vec->edges[0]->corner[0]));
727  polygon.AddVertexInOrder(transform.
728  TransformPoint(vec->edges[0]->corner[1]));
729  polygon.AddVertexInOrder(transform.
730  TransformPoint(vec->edges[1]->corner[1]));
731  polygon.AddVertexInOrder(transform.
732  TransformPoint(vec->edges[1]->corner[0]));
733 
734  //
735  // Get extent
736  //
737  if (polygon.PartialClip( voxelLimit, axis ))
738  {
739  //
740  // Get dot product of normal along target axis
741  //
742  polygon.SetNormal( transform.TransformAxis(vec->normal) );
743 
744  extentList.AddSurface( polygon );
745  }
746  } while( ++vec < vecs+numSide );
747 
748  return;
749 }
750 
751 
752 //
753 // IntersectSidePlane
754 //
755 // Decide if a line correctly intersects one side plane of our segment.
756 // It is assumed that the correct side has been chosen, and thus only
757 // the z bounds (of the entire segment) are checked.
758 //
759 // normSign - To be multiplied against normal:
760 // = +1.0 normal is unchanged
761 // = -1.0 normal is reversed (now points inward)
762 //
763 // Arguments:
764 // p - (in) Point
765 // v - (in) Direction
766 // vec - (in) Description record of the side plane
767 // normSign - (in) Sign (+/- 1) to apply to normal
768 // surfTolerance - (in) Surface tolerance (generally > 0, see below)
769 // distance - (out) Distance along v to intersection
770 // distFromSurface - (out) Distance from surface normal
771 //
772 // Notes:
773 // surfTolerance - Used to decide if a point is behind the surface,
774 // a point is allow to be -surfTolerance behind the
775 // surface (as measured along the normal), but *only*
776 // if the point is within the r/z bounds + surfTolerance
777 // of the segment.
778 //
780  const G4ThreeVector &v,
781  const G4PolyhedraSideVec& vec,
782  G4double normSign,
783  G4double surfTolerance,
784  G4double &distance,
785  G4double &distFromSurface )
786 {
787  //
788  // Correct normal? Here we have straight sides, and can safely ignore
789  // intersections where the dot product with the normal is zero.
790  //
791  G4double dotProd = normSign*v.dot(vec.normal);
792 
793  if (dotProd <= 0) return false;
794 
795  //
796  // Calculate distance to surface. If the side is too far
797  // behind the point, we must reject it.
798  //
799  G4ThreeVector delta = p - vec.center;
800  distFromSurface = -normSign*delta.dot(vec.normal);
801 
802  if (distFromSurface < -surfTolerance) return false;
803 
804  //
805  // Calculate precise distance to intersection with the side
806  // (along the trajectory, not normal to the surface)
807  //
808  distance = distFromSurface/dotProd;
809 
810  //
811  // Do we fall off the r/z extent of the segment?
812  //
813  // Calculate this very, very carefully! Why?
814  // 1. If a RZ end is at R=0, you can't miss!
815  // 2. If you just fall off in RZ, the answer must
816  // be consistent with adjacent G4PolyhedraSide faces.
817  // (2) implies that only variables used by other G4PolyhedraSide
818  // faces may be used, which includes only: p, v, and the edge corners.
819  // It also means that one side is a ">" or "<", which the other
820  // must be ">=" or "<=". Fortunately, this isn't a new problem.
821  // The solution below I borrowed from Joseph O'Rourke,
822  // "Computational Geometry in C (Second Edition)"
823  // See: http://cs.smith.edu/~orourke/
824  //
825  G4ThreeVector ic = p + distance*v - vec.center;
826  G4double atRZ = vec.surfRZ.dot(ic);
827 
828  if (atRZ < 0)
829  {
830  if (r[0]==0) return true; // Can't miss!
831 
832  if (atRZ < -lenRZ*1.2) return false; // Forget it! Missed by a mile.
833 
834  G4ThreeVector q = p + v;
835  G4ThreeVector qa = q - vec.edges[0]->corner[0],
836  qb = q - vec.edges[1]->corner[0];
837  G4ThreeVector qacb = qa.cross(qb);
838  if (normSign*qacb.dot(v) < 0) return false;
839 
840  if (distFromSurface < 0)
841  {
842  if (atRZ < -lenRZ-surfTolerance) return false;
843  }
844  }
845  else if (atRZ > 0)
846  {
847  if (r[1]==0) return true; // Can't miss!
848 
849  if (atRZ > lenRZ*1.2) return false; // Missed by a mile
850 
851  G4ThreeVector q = p + v;
852  G4ThreeVector qa = q - vec.edges[0]->corner[1],
853  qb = q - vec.edges[1]->corner[1];
854  G4ThreeVector qacb = qa.cross(qb);
855  if (normSign*qacb.dot(v) >= 0) return false;
856 
857  if (distFromSurface < 0)
858  {
859  if (atRZ > lenRZ+surfTolerance) return false;
860  }
861  }
862 
863  return true;
864 }
865 
866 
867 //
868 // LineHitsSegments
869 //
870 // Calculate which phi segments a line intersects in three dimensions.
871 // No check is made as to whether the intersections are within the z bounds of
872 // the segment.
873 //
875  const G4ThreeVector &v,
876  G4int *i1, G4int *i2 )
877 {
878  G4double s1, s2;
879  //
880  // First, decide if and where the line intersects the cone
881  //
882  G4int n = cone->LineHitsCone( p, v, &s1, &s2 );
883 
884  if (n==0) return 0;
885 
886  //
887  // Try first intersection.
888  //
889  *i1 = PhiSegment( std::atan2( p.y() + s1*v.y(), p.x() + s1*v.x() ) );
890  if (n==1)
891  {
892  return (*i1 < 0) ? 0 : 1;
893  }
894 
895  //
896  // Try second intersection
897  //
898  *i2 = PhiSegment( std::atan2( p.y() + s2*v.y(), p.x() + s2*v.x() ) );
899  if (*i1 == *i2) return 0;
900 
901  if (*i1 < 0)
902  {
903  if (*i2 < 0) return 0;
904  *i1 = *i2;
905  return 1;
906  }
907 
908  if (*i2 < 0) return 1;
909 
910  return 2;
911 }
912 
913 
914 //
915 // ClosestPhiSegment
916 //
917 // Decide which phi segment is closest in phi to the point.
918 // The result is the same as PhiSegment if there is no phi opening.
919 //
921 {
922  G4int iPhi = PhiSegment( phi0 );
923  if (iPhi >= 0) return iPhi;
924 
925  //
926  // Boogers! The points falls inside the phi segment.
927  // Look for the closest point: the start, or end
928  //
929  G4double phi = phi0;
930 
931  while( phi < startPhi ) phi += twopi;
932  G4double d1 = phi-endPhi;
933 
934  while( phi > startPhi ) phi -= twopi;
935  G4double d2 = startPhi-phi;
936 
937  return (d2 < d1) ? 0 : numSide-1;
938 }
939 
940 
941 //
942 // PhiSegment
943 //
944 // Decide which phi segment an angle belongs to, counting from zero.
945 // A value of -1 indicates that the phi value is outside the shape
946 // (only possible if phiTotal < 360 degrees).
947 //
949 {
950  //
951  // How far are we from phiStart? Come up with a positive answer
952  // that is less than 2*PI
953  //
954  G4double phi = phi0 - startPhi;
955  while( phi < 0 ) phi += twopi;
956  while( phi > twopi ) phi -= twopi;
957 
958  //
959  // Divide
960  //
961  G4int answer = (G4int)(phi/deltaPhi);
962 
963  if (answer >= numSide)
964  {
965  if (phiIsOpen)
966  {
967  return -1; // Looks like we missed
968  }
969  else
970  {
971  answer = numSide-1; // Probably just roundoff
972  }
973  }
974 
975  return answer;
976 }
977 
978 
979 //
980 // GetPhi
981 //
982 // Calculate Phi for a given 3-vector (point), if not already cached for the
983 // same point, in the attempt to avoid consecutive computation of the same
984 // quantity
985 //
987 {
988  G4double val=0.;
989 
990  if (fPhi.first != p)
991  {
992  val = p.phi();
993  fPhi.first = p;
994  fPhi.second = val;
995  }
996  else
997  {
998  val = fPhi.second;
999  }
1000  return val;
1001 }
1002 
1003 
1004 //
1005 // DistanceToOneSide
1006 //
1007 // Arguments:
1008 // p - (in) Point to check
1009 // vec - (in) vector set of this side
1010 // normDist - (out) distance normal to the side or edge, as appropriate, signed
1011 // Return value = total distance from the side
1012 //
1014  const G4PolyhedraSideVec &vec,
1015  G4double *normDist )
1016 {
1017  G4ThreeVector pct = p - vec.center;
1018 
1019  //
1020  // Get normal distance
1021  //
1022  *normDist = vec.normal.dot(pct);
1023 
1024  //
1025  // Add edge penalty
1026  //
1027  return DistanceAway( p, vec, normDist );
1028 }
1029 
1030 
1031 //
1032 // DistanceAway
1033 //
1034 // Add distance from side edges, if necesssary, to total distance,
1035 // and updates normDist appropriate depending on edge normals.
1036 //
1038  const G4PolyhedraSideVec &vec,
1039  G4double *normDist )
1040 {
1041  G4double distOut2;
1042  G4ThreeVector pct = p - vec.center;
1043  G4double distFaceNorm = *normDist;
1044 
1045  //
1046  // Okay, are we inside bounds?
1047  //
1048  G4double pcDotRZ = pct.dot(vec.surfRZ);
1049  G4double pcDotPhi = pct.dot(vec.surfPhi);
1050 
1051  //
1052  // Go through all permutations.
1053  // Phi
1054  // | | ^
1055  // B | H | E |
1056  // ------[1]------------[3]----- |
1057  // |XXXXXXXXXXXXXX| +----> RZ
1058  // C |XXXXXXXXXXXXXX| F
1059  // |XXXXXXXXXXXXXX|
1060  // ------[0]------------[2]----
1061  // A | G | D
1062  // | |
1063  //
1064  // It's real messy, but at least it's quick
1065  //
1066 
1067  if (pcDotRZ < -lenRZ)
1068  {
1069  G4double lenPhiZ = lenPhi[0] - lenRZ*lenPhi[1];
1070  G4double distOutZ = pcDotRZ+lenRZ;
1071  //
1072  // Below in RZ
1073  //
1074  if (pcDotPhi < -lenPhiZ)
1075  {
1076  //
1077  // ...and below in phi. Find distance to point (A)
1078  //
1079  G4double distOutPhi = pcDotPhi+lenPhiZ;
1080  distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
1081  G4ThreeVector pa = p - vec.edges[0]->corner[0];
1082  *normDist = pa.dot(vec.edges[0]->cornNorm[0]);
1083  }
1084  else if (pcDotPhi > lenPhiZ)
1085  {
1086  //
1087  // ...and above in phi. Find distance to point (B)
1088  //
1089  G4double distOutPhi = pcDotPhi-lenPhiZ;
1090  distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
1091  G4ThreeVector pb = p - vec.edges[1]->corner[0];
1092  *normDist = pb.dot(vec.edges[1]->cornNorm[0]);
1093  }
1094  else
1095  {
1096  //
1097  // ...and inside in phi. Find distance to line (C)
1098  //
1099  G4ThreeVector pa = p - vec.edges[0]->corner[0];
1100  distOut2 = distOutZ*distOutZ;
1101  *normDist = pa.dot(vec.edgeNorm[0]);
1102  }
1103  }
1104  else if (pcDotRZ > lenRZ)
1105  {
1106  G4double lenPhiZ = lenPhi[0] + lenRZ*lenPhi[1];
1107  G4double distOutZ = pcDotRZ-lenRZ;
1108  //
1109  // Above in RZ
1110  //
1111  if (pcDotPhi < -lenPhiZ)
1112  {
1113  //
1114  // ...and below in phi. Find distance to point (D)
1115  //
1116  G4double distOutPhi = pcDotPhi+lenPhiZ;
1117  distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
1118  G4ThreeVector pd = p - vec.edges[0]->corner[1];
1119  *normDist = pd.dot(vec.edges[0]->cornNorm[1]);
1120  }
1121  else if (pcDotPhi > lenPhiZ)
1122  {
1123  //
1124  // ...and above in phi. Find distance to point (E)
1125  //
1126  G4double distOutPhi = pcDotPhi-lenPhiZ;
1127  distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
1128  G4ThreeVector pe = p - vec.edges[1]->corner[1];
1129  *normDist = pe.dot(vec.edges[1]->cornNorm[1]);
1130  }
1131  else
1132  {
1133  //
1134  // ...and inside in phi. Find distance to line (F)
1135  //
1136  distOut2 = distOutZ*distOutZ;
1137  G4ThreeVector pd = p - vec.edges[0]->corner[1];
1138  *normDist = pd.dot(vec.edgeNorm[1]);
1139  }
1140  }
1141  else
1142  {
1143  G4double lenPhiZ = lenPhi[0] + pcDotRZ*lenPhi[1];
1144  //
1145  // We are inside RZ bounds
1146  //
1147  if (pcDotPhi < -lenPhiZ)
1148  {
1149  //
1150  // ...and below in phi. Find distance to line (G)
1151  //
1152  G4double distOut = edgeNorm*(pcDotPhi+lenPhiZ);
1153  distOut2 = distOut*distOut;
1154  G4ThreeVector pd = p - vec.edges[0]->corner[1];
1155  *normDist = pd.dot(vec.edges[0]->normal);
1156  }
1157  else if (pcDotPhi > lenPhiZ)
1158  {
1159  //
1160  // ...and above in phi. Find distance to line (H)
1161  //
1162  G4double distOut = edgeNorm*(pcDotPhi-lenPhiZ);
1163  distOut2 = distOut*distOut;
1164  G4ThreeVector pe = p - vec.edges[1]->corner[1];
1165  *normDist = pe.dot(vec.edges[1]->normal);
1166  }
1167  else
1168  {
1169  //
1170  // Inside bounds! No penalty.
1171  //
1172  return std::fabs(distFaceNorm);
1173  }
1174  }
1175  return std::sqrt( distFaceNorm*distFaceNorm + distOut2 );
1176 }
1177 
1178 
1179 //
1180 // Calculation of surface area of a triangle.
1181 // At the same time a random point in the triangle is given
1182 //
1184  G4ThreeVector p2,
1185  G4ThreeVector p3,
1186  G4ThreeVector *p4 )
1187 {
1188  G4ThreeVector v, w;
1189 
1190  v = p3 - p1;
1191  w = p1 - p2;
1192  G4double lambda1 = G4UniformRand();
1193  G4double lambda2 = lambda1*G4UniformRand();
1194 
1195  *p4=p2 + lambda1*w + lambda2*v;
1196  return 0.5*(v.cross(w)).mag();
1197 }
1198 
1199 
1200 //
1201 // GetPointOnPlane
1202 //
1203 // Auxiliary method for GetPointOnSurface()
1204 //
1208  G4double *Area )
1209 {
1210  G4double chose,aOne,aTwo;
1211  G4ThreeVector point1,point2;
1212  aOne = SurfaceTriangle(p0,p1,p2,&point1);
1213  aTwo = SurfaceTriangle(p2,p3,p0,&point2);
1214  *Area= aOne+aTwo;
1215 
1216  chose = G4UniformRand()*(aOne+aTwo);
1217  if( (chose>=0.) && (chose < aOne) )
1218  {
1219  return (point1);
1220  }
1221  return (point2);
1222 }
1223 
1224 
1225 //
1226 // SurfaceArea()
1227 //
1229 {
1230  if( fSurfaceArea==0. )
1231  {
1232  // Define the variables
1233  //
1234  G4double area,areas;
1235  G4ThreeVector point1;
1236  G4ThreeVector v1,v2,v3,v4;
1237  G4PolyhedraSideVec *vec = vecs;
1238  areas=0.;
1239 
1240  // Do a loop on all SideEdge
1241  //
1242  do
1243  {
1244  // Define 4points for a Plane or Triangle
1245  //
1246  v1=vec->edges[0]->corner[0];
1247  v2=vec->edges[0]->corner[1];
1248  v3=vec->edges[1]->corner[1];
1249  v4=vec->edges[1]->corner[0];
1250  point1=GetPointOnPlane(v1,v2,v3,v4,&area);
1251  areas+=area;
1252  } while( ++vec < vecs + numSide);
1253 
1254  fSurfaceArea=areas;
1255  }
1256  return fSurfaceArea;
1257 }
1258 
1259 
1260 //
1261 // GetPointOnFace()
1262 //
1264 {
1265  // Define the variables
1266  //
1267  std::vector<G4double>areas;
1268  std::vector<G4ThreeVector>points;
1269  G4double area=0;
1270  G4double result1;
1271  G4ThreeVector point1;
1272  G4ThreeVector v1,v2,v3,v4;
1273  G4PolyhedraSideVec *vec = vecs;
1274 
1275  // Do a loop on all SideEdge
1276  //
1277  do
1278  {
1279  // Define 4points for a Plane or Triangle
1280  //
1281  v1=vec->edges[0]->corner[0];
1282  v2=vec->edges[0]->corner[1];
1283  v3=vec->edges[1]->corner[1];
1284  v4=vec->edges[1]->corner[0];
1285  point1=GetPointOnPlane(v1,v2,v3,v4,&result1);
1286  points.push_back(point1);
1287  areas.push_back(result1);
1288  area+=result1;
1289  } while( ++vec < vecs+numSide );
1290 
1291  // Choose randomly one of the surfaces and point on it
1292  //
1293  G4double chose = area*G4UniformRand();
1294  G4double Achose1,Achose2;
1295  Achose1=0;Achose2=0.;
1296  G4int i=0;
1297  do
1298  {
1299  Achose2+=areas[i];
1300  if(chose>=Achose1 && chose<Achose2)
1301  {
1302  point1=points[i] ; break;
1303  }
1304  i++; Achose1=Achose2;
1305  } while( i<numSide );
1306 
1307  return point1;
1308 }