source: trunk/source/geometry/solids/specific/src/G4PolyPhiFace.cc @ 836

Last change on this file since 836 was 831, checked in by garnier, 16 years ago

import all except CVS

File size: 21.9 KB
Line 
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: G4PolyPhiFace.cc,v 1.13 2007/07/19 12:57:14 gcosmo Exp $
28// GEANT4 tag $Name:  $
29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4PolyPhiFace.cc
36//
37// Implementation of the face that bounds a polycone or polyhedra at
38// its phi opening.
39//
40// --------------------------------------------------------------------
41
42#include "G4PolyPhiFace.hh"
43#include "G4ClippablePolygon.hh"
44#include "G4ReduciblePolygon.hh"
45#include "G4AffineTransform.hh"
46#include "G4SolidExtentList.hh"
47#include "G4GeometryTolerance.hh"
48
49//
50// Constructor
51//
52// Points r,z should be supplied in clockwise order in r,z. For example:
53//
54//                [1]---------[2]         ^ R
55//                 |           |          |
56//                 |           |          +--> z
57//                [0]---------[3]
58//
59G4PolyPhiFace::G4PolyPhiFace( const G4ReduciblePolygon *rz,
60                                    G4double phi, 
61                                    G4double deltaPhi,
62                                    G4double phiOther )
63{
64  kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
65
66  numEdges = rz->NumVertices();
67 
68  rMin = rz->Amin();
69  rMax = rz->Amax();
70  zMin = rz->Bmin();
71  zMax = rz->Bmax();
72
73  //
74  // Is this the "starting" phi edge of the two?
75  //
76  G4bool start = (phiOther > phi);
77 
78  //
79  // Build radial vector
80  //
81  radial = G4ThreeVector( std::cos(phi), std::sin(phi), 0.0 );
82 
83  //
84  // Build normal
85  //
86  G4double zSign = start ? 1 : -1;
87  normal = G4ThreeVector( zSign*radial.y(), -zSign*radial.x(), 0 );
88 
89  //
90  // Is allBehind?
91  //
92  allBehind = (zSign*(std::cos(phiOther)*radial.y() - std::sin(phiOther)*radial.x()) < 0);
93 
94  //
95  // Adjacent edges
96  //
97  G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
98  G4double cosMid = std::cos(midPhi), 
99                 sinMid = std::sin(midPhi);
100
101  //
102  // Allocate corners
103  //
104  corners = new G4PolyPhiFaceVertex[numEdges];
105
106  //
107  // Fill them
108  //
109  G4ReduciblePolygonIterator iterRZ(rz);
110 
111  G4PolyPhiFaceVertex *corn = corners;
112  iterRZ.Begin();
113  do
114  {
115    corn->r = iterRZ.GetA();
116    corn->z = iterRZ.GetB();
117    corn->x = corn->r*radial.x();
118    corn->y = corn->r*radial.y();
119  } while( ++corn, iterRZ.Next() );
120
121  //
122  // Allocate edges
123  //
124  edges = new G4PolyPhiFaceEdge[numEdges];
125
126  //
127  // Fill them
128  //
129  G4double rFact = std::cos(0.5*deltaPhi);
130  G4double rFactNormalize = 1.0/std::sqrt(1.0+rFact*rFact);
131
132  G4PolyPhiFaceVertex *prev = corners+numEdges-1,
133                      *here = corners;
134  G4PolyPhiFaceEdge   *edge = edges;
135  do
136  {
137    G4ThreeVector sideNorm;
138   
139    edge->v0 = prev;
140    edge->v1 = here;
141
142    G4double dr = here->r - prev->r,
143             dz = here->z - prev->z;
144                         
145    edge->length = std::sqrt( dr*dr + dz*dz );
146
147    edge->tr = dr/edge->length;
148    edge->tz = dz/edge->length;
149   
150    if ((here->r < DBL_MIN) && (prev->r < DBL_MIN))
151    {
152      //
153      // Sigh! Always exceptions!
154      // This edge runs at r==0, so its adjoing surface is not a
155      // PolyconeSide or PolyhedraSide, but the opposite PolyPhiFace.
156      //
157      G4double zSignOther = start ? -1 : 1;
158      sideNorm = G4ThreeVector(  zSignOther*std::sin(phiOther), 
159                                -zSignOther*std::cos(phiOther), 0 );
160    }
161    else
162    {
163      sideNorm = G4ThreeVector( edge->tz*cosMid,
164                                edge->tz*sinMid,
165                               -edge->tr*rFact );
166      sideNorm *= rFactNormalize;
167    }
168    sideNorm += normal;
169   
170    edge->norm3D = sideNorm.unit();
171  } while( edge++, prev=here, ++here < corners+numEdges );
172
173  //
174  // Go back and fill in corner "normals"
175  //
176  G4PolyPhiFaceEdge *prevEdge = edges+numEdges-1;
177  edge = edges;
178  do
179  {
180    //
181    // Calculate vertex 2D normals (on the phi surface)
182    //
183    G4double rPart = prevEdge->tr + edge->tr;
184    G4double zPart = prevEdge->tz + edge->tz;
185    G4double norm = std::sqrt( rPart*rPart + zPart*zPart );
186    G4double rNorm = +zPart/norm;
187    G4double zNorm = -rPart/norm;
188   
189    edge->v0->rNorm = rNorm;
190    edge->v0->zNorm = zNorm;
191   
192    //
193    // Calculate the 3D normals.
194    //
195    // Find the vector perpendicular to the z axis
196    // that defines the plane that contains the vertex normal
197    //
198    G4ThreeVector xyVector;
199   
200    if (edge->v0->r < DBL_MIN)
201    {
202      //
203      // This is a vertex at r==0, which is a special
204      // case. The normal we will construct lays in the
205      // plane at the center of the phi opening.
206      //
207      // We also know that rNorm < 0
208      //
209      G4double zSignOther = start ? -1 : 1;
210      G4ThreeVector normalOther(  zSignOther*std::sin(phiOther), 
211                                 -zSignOther*std::cos(phiOther), 0 );
212               
213      xyVector = - normal - normalOther;
214    }
215    else
216    {
217      //
218      // This is a vertex at r > 0. The plane
219      // is the average of the normal and the
220      // normal of the adjacent phi face
221      //
222      xyVector = G4ThreeVector( cosMid, sinMid, 0 );
223      if (rNorm < 0)
224        xyVector -= normal;
225      else
226        xyVector += normal;
227    }
228   
229    //
230    // Combine it with the r/z direction from the face
231    //
232    edge->v0->norm3D = rNorm*xyVector.unit() + G4ThreeVector( 0, 0, zNorm );
233  } while(  prevEdge=edge, ++edge < edges+numEdges );
234 
235  //
236  // Build point on surface
237  //
238  G4double rAve = 0.5*(rMax-rMin),
239           zAve = 0.5*(zMax-zMin);
240  surface = G4ThreeVector( rAve*radial.x(), rAve*radial.y(), zAve );
241}
242
243
244//
245// Diagnose
246//
247// Throw an exception if something is found inconsistent with
248// the solid.
249//
250// For debugging purposes only
251//
252void G4PolyPhiFace::Diagnose( G4VSolid *owner )
253{
254  G4PolyPhiFaceVertex   *corner = corners;
255  do
256  {
257    G4ThreeVector test(corner->x, corner->y, corner->z);
258    test -= 1E-6*corner->norm3D;
259   
260    if (owner->Inside(test) != kInside) 
261      G4Exception( "G4PolyPhiFace::Diagnose()", "InvalidSetup",
262                   FatalException, "Bad vertex normal found." );
263  } while( ++corner < corners+numEdges );
264}
265
266
267//
268// Fake default constructor - sets only member data and allocates memory
269//                            for usage restricted to object persistency.
270//
271G4PolyPhiFace::G4PolyPhiFace( __void__&)
272  : edges(0), corners(0)
273{
274}
275
276
277//
278// Destructor
279//
280G4PolyPhiFace::~G4PolyPhiFace()
281{
282  delete [] edges;
283  delete [] corners;
284}
285
286
287//
288// Copy constructor
289//
290G4PolyPhiFace::G4PolyPhiFace( const G4PolyPhiFace &source )
291  : G4VCSGface()
292{
293  CopyStuff( source );
294}
295
296
297//
298// Assignment operator
299//
300G4PolyPhiFace& G4PolyPhiFace::operator=( const G4PolyPhiFace &source )
301{
302  if (this == &source) return *this;
303
304  delete [] edges;
305  delete [] corners;
306 
307  CopyStuff( source );
308 
309  return *this;
310}
311
312
313//
314// CopyStuff (protected)
315//
316void G4PolyPhiFace::CopyStuff( const G4PolyPhiFace &source )
317{
318  //
319  // The simple stuff
320  //
321  numEdges  = source.numEdges;
322  normal    = source.normal;
323  radial    = source.radial;
324  surface    = source.surface;
325  rMin    = source.rMin;
326  rMax    = source.rMax;
327  zMin    = source.zMin;
328  zMax    = source.zMax;
329  allBehind  = source.allBehind;
330
331  kCarTolerance = source.kCarTolerance;
332
333  //
334  // Corner dynamic array
335  //
336  corners = new G4PolyPhiFaceVertex[numEdges];
337  G4PolyPhiFaceVertex *corn = corners,
338                      *sourceCorn = source.corners;
339  do
340  {
341    *corn = *sourceCorn;
342  } while( ++sourceCorn, ++corn < corners+numEdges );
343 
344  //
345  // Edge dynamic array
346  //
347  edges = new G4PolyPhiFaceEdge[numEdges];
348
349  G4PolyPhiFaceVertex *prev = corners+numEdges-1,
350                      *here = corners;
351  G4PolyPhiFaceEdge   *edge = edges,
352                      *sourceEdge = source.edges;
353  do
354  {
355    *edge = *sourceEdge;
356    edge->v0 = prev;
357    edge->v1 = here;
358  } while( ++sourceEdge, ++edge, prev=here, ++here < corners+numEdges );
359}
360
361
362//
363// Intersect
364//
365G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p,
366                                 const G4ThreeVector &v,
367                                       G4bool outgoing,
368                                       G4double surfTolerance,
369                                       G4double &distance,
370                                       G4double &distFromSurface,
371                                       G4ThreeVector &aNormal,
372                                       G4bool &isAllBehind )
373{
374  G4double normSign = outgoing ? +1 : -1;
375 
376  //
377  // These don't change
378  //
379  isAllBehind = allBehind;
380  aNormal = normal;
381
382  //
383  // Correct normal? Here we have straight sides, and can safely ignore
384  // intersections where the dot product with the normal is zero.
385  //
386  G4double dotProd = normSign*normal.dot(v);
387 
388  if (dotProd <= 0) return false;
389
390  //
391  // Calculate distance to surface. If the side is too far
392  // behind the point, we must reject it.
393  //
394  G4ThreeVector ps = p - surface;
395  distFromSurface = -normSign*ps.dot(normal);
396   
397  if (distFromSurface < -surfTolerance) return false;
398
399  //
400  // Calculate precise distance to intersection with the side
401  // (along the trajectory, not normal to the surface)
402  //
403  distance = distFromSurface/dotProd;
404
405  //
406  // Calculate intersection point in r,z
407  //
408  G4ThreeVector ip = p + distance*v;
409 
410  G4double r = radial.dot(ip);
411 
412  //
413  // And is it inside the r/z extent?
414  //
415  return InsideEdgesExact( r, ip.z(), normSign, p, v );
416}
417
418
419//
420// Distance
421//
422G4double G4PolyPhiFace::Distance( const G4ThreeVector &p, G4bool outgoing )
423{
424  G4double normSign = outgoing ? +1 : -1;
425  //
426  // Correct normal?
427  //
428  G4ThreeVector ps = p - surface;
429  G4double distPhi = -normSign*normal.dot(ps);
430 
431  if (distPhi < -0.5*kCarTolerance) 
432    return kInfinity;
433  else if (distPhi < 0)
434    distPhi = 0.0;
435 
436  //
437  // Calculate projected point in r,z
438  //
439  G4double r = radial.dot(p);
440 
441  //
442  // Are we inside the face?
443  //
444  G4double distRZ2;
445 
446  if (InsideEdges( r, p.z(), &distRZ2, 0 ))
447  {
448    //
449    // Yup, answer is just distPhi
450    //
451    return distPhi;
452  }
453  else
454  {
455    //
456    // Nope. Penalize by distance out
457    //
458    return std::sqrt( distPhi*distPhi + distRZ2 );
459  }
460} 
461 
462
463//
464// Inside
465//
466EInside G4PolyPhiFace::Inside( const G4ThreeVector &p,
467                                     G4double tolerance, 
468                                     G4double *bestDistance )
469{
470  //
471  // Get distance along phi, which if negative means the point
472  // is nominally inside the shape.
473  //
474  G4ThreeVector ps = p - surface;
475  G4double distPhi = normal.dot(ps);
476 
477  //
478  // Calculate projected point in r,z
479  //
480  G4double r = radial.dot(p);
481 
482  //
483  // Are we inside the face?
484  //
485  G4double distRZ2;
486  G4PolyPhiFaceVertex *base3Dnorm;
487  G4ThreeVector      *head3Dnorm;
488 
489  if (InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm ))
490  {
491    //
492    // Looks like we're inside. Distance is distance in phi.
493    //
494    *bestDistance = std::fabs(distPhi);
495   
496    //
497    // Use distPhi to decide fate
498    //
499    if (distPhi < -tolerance) return kInside;
500    if (distPhi <  tolerance) return kSurface;
501    return kOutside;
502  }
503  else
504  {
505    //
506    // We're outside the extent of the face,
507    // so the distance is penalized by distance from edges in RZ
508    //
509    *bestDistance = std::sqrt( distPhi*distPhi + distRZ2 );
510   
511    //
512    // Use edge normal to decide fate
513    //
514    G4ThreeVector cc( base3Dnorm->r*radial.x(),
515          base3Dnorm->r*radial.y(),
516          base3Dnorm->z );
517    cc = p - cc;
518    G4double normDist = head3Dnorm->dot(cc);
519    if ( distRZ2 > tolerance*tolerance )
520    {
521      //
522      // We're far enough away that kSurface is not possible
523      //
524      return normDist < 0 ? kInside : kOutside;
525    }
526   
527    if (normDist < -tolerance) return kInside;
528    if (normDist <  tolerance) return kSurface;
529    return kOutside;
530  }
531} 
532
533
534//
535// Normal
536//
537// This virtual member is simple for our planer shape,
538// which has only one normal
539//
540G4ThreeVector 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, 0 ))
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
578//
579// Extent
580//
581// This actually isn't needed by polycone or polyhedra...
582//
583G4double G4PolyPhiFace::Extent( const G4ThreeVector axis )
584{
585  G4double max = -kInfinity;
586 
587  G4PolyPhiFaceVertex *corner = corners;
588  do
589  {
590    G4double here = axis.x()*corner->r*radial.x()
591            + axis.y()*corner->r*radial.y()
592            + axis.z()*corner->z;
593    if (here > max) max = here;
594  } while( ++corner < corners + numEdges );
595 
596  return max;
597} 
598
599
600//
601// CalculateExtent
602//
603// See notes in G4VCSGface
604//
605void G4PolyPhiFace::CalculateExtent( const EAxis axis, 
606                                     const G4VoxelLimits &voxelLimit,
607                                     const G4AffineTransform &transform,
608                                           G4SolidExtentList &extentList )
609{
610  //
611  // Construct a (sometimes big) clippable polygon,
612  //
613  // Perform the necessary transformations while doing so
614  //
615  G4ClippablePolygon polygon;
616 
617  G4PolyPhiFaceVertex *corner = corners;
618  do
619  {
620    G4ThreeVector point( 0, 0, corner->z );
621    point += radial*corner->r;
622   
623    polygon.AddVertexInOrder( transform.TransformPoint( point ) );
624  } while( ++corner < corners + numEdges );
625 
626  //
627  // Clip away
628  //
629  if (polygon.PartialClip( voxelLimit, axis ))
630  {
631    //
632    // Add it to the list
633    //
634    polygon.SetNormal( transform.TransformAxis(normal) );
635    extentList.AddSurface( polygon );
636  }
637}
638
639
640//
641//-------------------------------------------------------
642 
643 
644//
645// InsideEdgesExact
646//
647// Decide if the point in r,z is inside the edges of our face,
648// **but** do so consistently with other faces.
649//
650// This routine has functionality similar to InsideEdges, but uses
651// an algorithm to decide if a trajectory falls inside or outside the
652// face that uses only the trajectory p,v values and the three dimensional
653// points representing the edges of the polygon. The objective is to plug up
654// any leaks between touching G4PolyPhiFaces (at r==0) and any other face
655// that uses the same convention.
656//
657// See: "Computational Geometry in C (Second Edition)"
658// http://cs.smith.edu/~orourke/
659//
660G4bool G4PolyPhiFace::InsideEdgesExact( G4double r, G4double z,
661                                        G4double normSign,
662                                  const G4ThreeVector &p,
663                                  const G4ThreeVector &v )
664{
665  //
666  // Quick check of extent
667  //
668  if ( (r < rMin-kCarTolerance)
669    || (r > rMax+kCarTolerance) ) return false;
670       
671  if ( (z < zMin-kCarTolerance)
672    || (z > zMax+kCarTolerance) ) return false;
673 
674  //
675  // Exact check: loop over all vertices
676  //
677  G4double qx = p.x() + v.x(),
678           qy = p.y() + v.y(),
679           qz = p.z() + v.z();
680
681  G4int answer = 0;
682  G4PolyPhiFaceVertex *corn = corners, 
683                      *prev = corners+numEdges-1;
684
685  G4double cornZ, prevZ;
686 
687  prevZ = ExactZOrder( z, qx, qy, qz, v, normSign, prev );
688  do
689  {
690    //
691    // Get z order of this vertex, and compare to previous vertex
692    //
693    cornZ = ExactZOrder( z, qx, qy, qz, v, normSign, corn );
694   
695    if (cornZ < 0)
696    {
697      if (prevZ < 0) continue;
698    }
699    else if (cornZ > 0)
700    {
701      if (prevZ > 0) continue;
702    }
703    else
704    {
705      //
706      // By chance, we overlap exactly (within precision) with
707      // the current vertex. Continue if the same happened previously
708      // (e.g. the previous vertex had the same z value)
709      //
710      if (prevZ == 0) continue;
711     
712      //
713      // Otherwise, to decide what to do, we need to know what is
714      // coming up next. Specifically, we need to find the next vertex
715      // with a non-zero z order.
716      //
717      // One might worry about infinite loops, but the above conditional
718      // should prevent it
719      //
720      G4PolyPhiFaceVertex *next = corn;
721      G4double nextZ;
722      do
723      {
724        next++;
725        if (next == corners+numEdges) next = corners;
726
727        nextZ = ExactZOrder( z, qx, qy, qz, v, normSign, next );
728      } while( nextZ == 0 );
729     
730      //
731      // If we won't be changing direction, go to the next vertex
732      //
733      if (nextZ*prevZ < 0) continue;
734    }
735 
736     
737    //
738    // We overlap in z with the side of the face that stretches from
739    // vertex "prev" to "corn". On which side (left or right) do
740    // we lay with respect to this segment?
741    // 
742    G4ThreeVector qa( qx - prev->x, qy - prev->y, qz - prev->z ),
743                  qb( qx - corn->x, qy - corn->y, qz - corn->z );
744
745    G4double aboveOrBelow = normSign*qa.cross(qb).dot(v);
746   
747    if (aboveOrBelow > 0) 
748      answer++;
749    else if (aboveOrBelow < 0)
750      answer--;
751    else
752    {
753      //
754      // A precisely zero answer here means we exactly
755      // intersect (within roundoff) the edge of the face.
756      // Return true in this case.
757      //
758      return true;
759    }
760  } while( prevZ = cornZ, prev=corn, ++corn < corners+numEdges );
761 
762//  G4int fanswer = std::abs(answer);
763//  if (fanswer==1 || fanswer>2) {
764//    G4cerr << "G4PolyPhiFace::InsideEdgesExact: answer is "
765//           << answer << G4endl;
766//  }
767
768  return answer!=0;
769}
770 
771 
772//
773// InsideEdges (don't care aboud distance)
774//
775// Decide if the point in r,z is inside the edges of our face
776//
777// This routine can be made a zillion times quicker by implementing
778// better code, for example:
779//
780//    int pnpoly(int npol, float *xp, float *yp, float x, float y)
781//    {
782//      int i, j, c = 0;
783//      for (i = 0, j = npol-1; i < npol; j = i++) {
784//        if ((((yp[i]<=y) && (y<yp[j])) ||
785//             ((yp[j]<=y) && (y<yp[i]))) &&
786//            (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
787//
788//          c = !c;
789//      }
790//      return c;
791//    }
792//
793// See "Point in Polyon Strategies", Eric Haines [Graphic Gems IV]  pp. 24-46
794//
795// My algorithm below is rather unique, but is based on code needed to
796// calculate the distance to the shape. I left it in here because ...
797// well ... to test it better.
798//
799G4bool G4PolyPhiFace::InsideEdges( G4double r, G4double z )
800{
801  //
802  // Quick check of extent
803  //
804  if ( r < rMin || r > rMax ) return false;
805  if ( z < zMin || z > zMax ) return false;
806 
807  //
808  // More thorough check
809  //
810  G4double notUsed;
811 
812  return InsideEdges( r, z, &notUsed, 0 );
813}
814
815
816//
817// InsideEdges (care about distance)
818//
819// Decide if the point in r,z is inside the edges of our face
820//
821G4bool G4PolyPhiFace::InsideEdges( G4double r, G4double z,
822                                   G4double *bestDist2, 
823                                   G4PolyPhiFaceVertex **base3Dnorm, 
824                                   G4ThreeVector **head3Dnorm )
825{
826  G4double bestDistance2 = kInfinity;
827  G4bool   answer = 0;
828 
829  G4PolyPhiFaceEdge *edge = edges;
830  do
831  {
832    G4PolyPhiFaceVertex *testMe;
833    //
834    // Get distance perpendicular to the edge
835    //
836    G4double dr = (r-edge->v0->r), dz = (z-edge->v0->z);
837
838    G4double distOut = dr*edge->tz - dz*edge->tr;
839    G4double distance2 = distOut*distOut;
840    if (distance2 > bestDistance2) continue;        // No hope!
841
842    //
843    // Check to see if normal intersects edge within the edge's boundary
844    //
845    G4double s = dr*edge->tr + dz*edge->tz;
846
847    //
848    // If it doesn't, penalize distance2 appropriately
849    //
850    if (s < 0)
851    {
852      distance2 += s*s;
853      testMe = edge->v0;
854    }
855    else if (s > edge->length)
856    {
857      G4double s2 = s-edge->length;
858      distance2 += s2*s2;
859      testMe = edge->v1;
860    }
861    else
862    {
863      testMe = 0;
864    }
865   
866    //
867    // Closest edge so far?
868    //
869    if (distance2 < bestDistance2)
870    {
871      bestDistance2 = distance2;
872      if (testMe)
873      {
874        G4double distNorm = dr*testMe->rNorm + dz*testMe->zNorm;
875        answer = (distNorm <= 0);
876        if (base3Dnorm)
877        {
878          *base3Dnorm = testMe;
879          *head3Dnorm = &testMe->norm3D;
880        }
881      }
882      else
883      {
884        answer = (distOut <= 0);                       
885        if (base3Dnorm)
886        {
887          *base3Dnorm = edge->v0;
888          *head3Dnorm = &edge->norm3D;
889        }
890      }
891    }
892  } while( ++edge < edges + numEdges );
893 
894  *bestDist2 = bestDistance2;
895  return answer;
896}
Note: See TracBrowser for help on using the repository browser.