Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/specific/src/G4TwistTubsHypeSide.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 // G4TwistTubsHypeSide implementation
 27 //
 28 // 01-Aug-2002 - Kotoyo Hoshina (hoshina@hepburn.s.chiba-u.ac.jp), created.
 29 // 13-Nov-2003 - O.Link (Oliver.Link@cern.ch), Integration in Geant4
 30 //               from original version in Jupiter-2.5.02 application.
 31 // --------------------------------------------------------------------
 32 
 33 #include "G4TwistTubsHypeSide.hh"
 34 #include "G4PhysicalConstants.hh"
 35 #include "G4GeometryTolerance.hh"
 36 
 37 //=====================================================================
 38 //* constructors ------------------------------------------------------
 39 
 40 G4TwistTubsHypeSide::G4TwistTubsHypeSide(const G4String&         name,
 41                                          const G4RotationMatrix& rot,
 42                                          const G4ThreeVector&    tlate,
 43                                          const G4int             handedness,
 44                                          const G4double          kappa,
 45                                          const G4double          tanstereo,
 46                                          const G4double          r0,
 47                                          const EAxis             axis0,
 48                                          const EAxis             axis1,
 49                                                G4double          axis0min,
 50                                                G4double          axis1min,
 51                                                G4double          axis0max,
 52                                                G4double          axis1max )
 53   : G4VTwistSurface(name, rot, tlate, handedness, axis0, axis1,
 54                     axis0min, axis1min, axis0max, axis1max),
 55     fKappa(kappa), fTanStereo(tanstereo),
 56     fTan2Stereo(tanstereo*tanstereo), fR0(r0), fR02(r0*r0), fDPhi(twopi)
 57 {
 58    if ( (axis0 == kZAxis) && (axis1 == kPhi) )
 59    {
 60       G4Exception("G4TwistTubsHypeSide::G4TwistTubsHypeSide()",
 61                   "GeomSolids0002", FatalErrorInArgument,
 62                   "Should swap axis0 and axis1!");
 63    }
 64    fInside.gp.set(kInfinity, kInfinity, kInfinity);
 65    fInside.inside = kOutside;
 66    fIsValidNorm = false;
 67    SetCorners();
 68    SetBoundaries();
 69 }
 70 
 71 G4TwistTubsHypeSide::G4TwistTubsHypeSide(const G4String& name,
 72                                                G4double EndInnerRadius[2],
 73                                                G4double EndOuterRadius[2],
 74                                                G4double DPhi,
 75                                                G4double EndPhi[2],
 76                                                G4double EndZ[2], 
 77                                                G4double InnerRadius,
 78                                                G4double OuterRadius,
 79                                                G4double Kappa,
 80                                                G4double TanInnerStereo,
 81                                                G4double TanOuterStereo,
 82                                                G4int    handedness)
 83    : G4VTwistSurface(name)
 84 {
 85 
 86    fHandedness = handedness;   // +z = +ve, -z = -ve
 87    fAxis[0]    = kPhi;
 88    fAxis[1]    = kZAxis;
 89    fAxisMin[0] = kInfinity;         // we cannot fix boundary min of Phi, 
 90    fAxisMax[0] = kInfinity;         // because it depends on z.
 91    fAxisMin[1] = EndZ[0];
 92    fAxisMax[1] = EndZ[1];
 93    fKappa      = Kappa;
 94    fDPhi       = DPhi ;
 95 
 96    if (handedness < 0)  // inner hyperbolic surface
 97    {
 98       fTanStereo  = TanInnerStereo;
 99       fR0         = InnerRadius;
100    }
101    else                 // outer hyperbolic surface
102    {
103       fTanStereo  = TanOuterStereo;
104       fR0         = OuterRadius;
105    }
106    fTan2Stereo = fTanStereo * fTanStereo;
107    fR02        = fR0 * fR0;
108    
109    fTrans.set(0, 0, 0);
110    fIsValidNorm = false;
111 
112    fInside.gp.set(kInfinity, kInfinity, kInfinity);
113    fInside.inside = kOutside;
114    
115    SetCorners(EndInnerRadius, EndOuterRadius, DPhi, EndPhi, EndZ) ; 
116 
117    SetBoundaries();
118 }
119 
120 //=====================================================================
121 //* Fake default constructor ------------------------------------------
122 
123 G4TwistTubsHypeSide::G4TwistTubsHypeSide( __void__& a )
124   : G4VTwistSurface(a)
125 {
126 }
127 
128 //=====================================================================
129 //* destructor --------------------------------------------------------
130 
131 G4TwistTubsHypeSide::~G4TwistTubsHypeSide() = default;
132 
133 //=====================================================================
134 //* GetNormal ---------------------------------------------------------
135 
136 G4ThreeVector G4TwistTubsHypeSide::GetNormal(const G4ThreeVector& tmpxx, 
137                                                    G4bool isGlobal) 
138 {
139    // GetNormal returns a normal vector at a surface (or very close
140    // to surface) point at tmpxx.
141    // If isGlobal=true, it returns the normal in global coordinate.
142    
143    G4ThreeVector xx;
144    if (isGlobal)
145    {
146       xx = ComputeLocalPoint(tmpxx);
147       if ((xx - fCurrentNormal.p).mag() < 0.5 * kCarTolerance)
148       {
149          return ComputeGlobalDirection(fCurrentNormal.normal);
150       }
151    }
152    else
153    {
154       xx = tmpxx;
155       if (xx == fCurrentNormal.p)
156       {
157          return fCurrentNormal.normal;
158       }
159    }
160    
161    fCurrentNormal.p = xx;
162 
163    G4ThreeVector normal( xx.x(), xx.y(), -xx.z() * fTan2Stereo);
164    normal *= fHandedness;
165    normal = normal.unit();
166 
167    if (isGlobal)
168    {
169       fCurrentNormal.normal = ComputeLocalDirection(normal);
170    }
171    else
172    {
173       fCurrentNormal.normal = normal;
174    }
175    return fCurrentNormal.normal;
176 }
177 
178 //=====================================================================
179 //* Inside() ----------------------------------------------------------
180 
181 EInside G4TwistTubsHypeSide::Inside(const G4ThreeVector& gp) 
182 {
183    // Inside returns 
184    const G4double halftol
185      = 0.5 * G4GeometryTolerance::GetInstance()->GetRadialTolerance();
186 
187    if (fInside.gp == gp)
188    {
189       return fInside.inside;
190    }
191    fInside.gp = gp;
192    
193    G4ThreeVector p = ComputeLocalPoint(gp);
194   
195 
196    if (p.mag() < DBL_MIN)
197    {
198       fInside.inside = kOutside;
199       return fInside.inside;
200    }
201    
202    G4double rhohype = GetRhoAtPZ(p);
203    G4double distanceToOut = fHandedness * (rhohype - p.getRho());
204                             // +ve : inside
205 
206    if (distanceToOut < -halftol)
207    {
208      fInside.inside = kOutside;
209    }
210    else
211    {
212       G4int areacode = GetAreaCode(p);
213       if (IsOutside(areacode))
214       {
215          fInside.inside = kOutside;
216       }
217       else if (IsBoundary(areacode))
218       {
219          fInside.inside = kSurface;
220       }
221       else if (IsInside(areacode))
222       {
223          if (distanceToOut <= halftol)
224          {
225             fInside.inside = kSurface;
226          }
227          else
228          {
229             fInside.inside = kInside;
230          }
231       }
232       else
233       {
234          G4cout << "WARNING - G4TwistTubsHypeSide::Inside()" << G4endl
235                 << "          Invalid option !" << G4endl
236                 << "          name, areacode, distanceToOut = "
237                 << GetName() << ", " << std::hex << areacode
238                 << std::dec << ", " << distanceToOut << G4endl;
239       }
240    }
241 
242    return fInside.inside; 
243 }
244 
245 //=====================================================================
246 //* DistanceToSurface -------------------------------------------------
247 
248 G4int G4TwistTubsHypeSide::DistanceToSurface(const G4ThreeVector& gp,
249                                              const G4ThreeVector& gv,
250                                                    G4ThreeVector  gxx[],
251                                                    G4double       distance[],
252                                                    G4int          areacode[],
253                                                    G4bool         isvalid[],
254                                                    EValidate      validate)
255 {
256    // Decide if and where a line intersects with a hyperbolic
257    // surface (of infinite extent)
258    //
259    // Arguments:
260    //     p       - (in) Point on trajectory
261    //     v       - (in) Vector along trajectory
262    //     r2      - (in) Square of radius at z = 0
263    //     tan2phi - (in) std::tan(stereo)**2
264    //     s       - (out) Up to two points of intersection, where the
265    //                     intersection point is p + s*v, and if there are
266    //                     two intersections, s[0] < s[1]. May be negative.
267    // Returns:
268    //     The number of intersections. If 0, the trajectory misses.
269    //
270    //
271    // Equation of a line:
272    //
273    //       x = x0 + s*tx      y = y0 + s*ty      z = z0 + s*tz
274    //
275    // Equation of a hyperbolic surface:
276    //
277    //       x**2 + y**2 = r**2 + (z*tanPhi)**2
278    //
279    // Solution is quadratic:
280    //
281    //  a*s**2 + b*s + c = 0
282    //
283    // where:
284    //
285    //  a = tx**2 + ty**2 - (tz*tanPhi)**2
286    //
287    //  b = 2*( x0*tx + y0*ty - z0*tz*tanPhi**2 )
288    //
289    //  c = x0**2 + y0**2 - r**2 - (z0*tanPhi)**2
290    //
291       
292    fCurStatWithV.ResetfDone(validate, &gp, &gv);
293 
294    if (fCurStatWithV.IsDone())
295    {
296       for (G4int i=0; i<fCurStatWithV.GetNXX(); ++i)
297       {
298          gxx[i] = fCurStatWithV.GetXX(i);
299          distance[i] = fCurStatWithV.GetDistance(i);
300          areacode[i] = fCurStatWithV.GetAreacode(i);
301          isvalid[i]  = fCurStatWithV.IsValid(i);
302       }
303       return fCurStatWithV.GetNXX();
304    }
305    else   // initialize
306    {
307       for (auto i=0; i<2; ++i)
308       {
309          distance[i] = kInfinity;
310          areacode[i] = sOutside;
311          isvalid[i]  = false;
312          gxx[i].set(kInfinity, kInfinity, kInfinity);
313       }
314    }
315    
316    G4ThreeVector p = ComputeLocalPoint(gp);
317    G4ThreeVector v = ComputeLocalDirection(gv);
318    G4ThreeVector xx[2]; 
319    
320    //
321    // special case!  p is on origin.
322    // 
323 
324    if (p.mag() == 0)
325    {
326       // p is origin. 
327       // unique solution of 2-dimension question in r-z plane 
328       // Equations:
329       //    r^2 = fR02 + z^2*fTan2Stere0
330       //    r = beta*z
331       //        where 
332       //        beta = vrho / vz
333       // Solution (z value of intersection point):
334       //    xxz = +- std::sqrt (fR02 / (beta^2 - fTan2Stereo))
335       //
336 
337       G4double vz    = v.z();
338       G4double absvz = std::fabs(vz);
339       G4double vrho  = v.getRho();       
340       G4double vslope = vrho/vz;
341       G4double vslope2 = vslope * vslope;
342       if (vrho == 0 || (vrho/absvz) <= (absvz*std::fabs(fTanStereo)/absvz))
343       {
344          // vz/vrho is bigger than slope of asymptonic line
345          distance[0] = kInfinity;
346          fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
347                                         isvalid[0], 0, validate, &gp, &gv);
348          return 0;
349       }
350        
351       if (vz != 0.0)
352       { 
353          G4double xxz  = std::sqrt(fR02 / (vslope2 - fTan2Stereo)) 
354                         * (vz / std::fabs(vz)) ;
355          G4double t = xxz / vz;
356          xx[0].set(t*v.x(), t*v.y(), xxz);
357       }
358       else
359       {
360          // p.z = 0 && v.z =0
361          xx[0].set(v.x()*fR0, v.y()*fR0, 0);  // v is a unit vector.
362       }
363       distance[0] = xx[0].mag();
364       gxx[0]      = ComputeGlobalPoint(xx[0]);
365 
366       if (validate == kValidateWithTol)
367       {
368          areacode[0] = GetAreaCode(xx[0]);
369          if (!IsOutside(areacode[0]))
370          {
371             if (distance[0] >= 0) isvalid[0] = true;
372          }
373       }
374       else if (validate == kValidateWithoutTol)
375       {
376          areacode[0] = GetAreaCode(xx[0], false);
377          if (IsInside(areacode[0]))
378          {
379             if (distance[0] >= 0) isvalid[0] = true;
380          }
381       }
382       else  // kDontValidate                       
383       {
384          areacode[0] = sInside;
385             if (distance[0] >= 0) isvalid[0] = true;
386       }
387                  
388       fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
389                                      isvalid[0], 1, validate, &gp, &gv);
390       return 1;
391    }
392 
393    //
394    // special case end.
395    // 
396 
397    G4double a = v.x()*v.x() + v.y()*v.y() - v.z()*v.z()*fTan2Stereo;
398    G4double b = 2.0
399               * ( p.x() * v.x() + p.y() * v.y() - p.z() * v.z() * fTan2Stereo );
400    G4double c = p.x()*p.x() + p.y()*p.y() - fR02 - p.z()*p.z()*fTan2Stereo;
401    G4double D = b*b - 4*a*c;          //discriminant
402    G4int vout = 0;
403    
404    if (std::fabs(a) < DBL_MIN)
405    {
406       if (std::fabs(b) > DBL_MIN)            // single solution
407       {
408          distance[0] = -c/b;
409          xx[0] = p + distance[0]*v;
410          gxx[0] = ComputeGlobalPoint(xx[0]);
411 
412          if (validate == kValidateWithTol)
413          {
414             areacode[0] = GetAreaCode(xx[0]);
415             if (!IsOutside(areacode[0]))
416             {
417                if (distance[0] >= 0) isvalid[0] = true;
418             }
419          }
420          else if (validate == kValidateWithoutTol)
421          {
422             areacode[0] = GetAreaCode(xx[0], false);
423             if (IsInside(areacode[0]))
424             {
425                if (distance[0] >= 0) isvalid[0] = true;
426             }
427          }
428          else  // kDontValidate                       
429          {
430             areacode[0] = sInside;
431                if (distance[0] >= 0) isvalid[0] = true;
432          }
433                  
434          fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
435                                         isvalid[0], 1, validate, &gp, &gv);
436          vout = 1;
437       }
438       else
439       {
440         // if a=b=0 and c != 0, p is origin and v is parallel to asymptotic line
441         // if a=b=c=0, p is on surface and v is paralell to stereo wire.
442         // return distance = infinity
443 
444          fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
445                                         isvalid[0], 0, validate, &gp, &gv);
446          vout = 0;
447       }
448    }
449    else if (D > DBL_MIN)          // double solutions
450    {
451       D = std::sqrt(D);
452       G4double      factor = 0.5/a;
453       G4double      tmpdist[2] = {kInfinity, kInfinity};
454       G4ThreeVector tmpxx[2] ;
455       G4int         tmpareacode[2] = {sOutside, sOutside};
456       G4bool        tmpisvalid[2]  = {false, false};
457 
458       for (auto i=0; i<2; ++i)
459       {
460          tmpdist[i] = factor*(-b - D);
461          D = -D;
462          tmpxx[i] = p + tmpdist[i]*v;
463         
464          if (validate == kValidateWithTol)
465          {
466             tmpareacode[i] = GetAreaCode(tmpxx[i]);
467             if (!IsOutside(tmpareacode[i]))
468             {
469                if (tmpdist[i] >= 0) tmpisvalid[i] = true;
470                continue;
471             }
472          }
473          else if (validate == kValidateWithoutTol)
474          {
475             tmpareacode[i] = GetAreaCode(tmpxx[i], false);
476             if (IsInside(tmpareacode[i]))
477             {
478                if (tmpdist[i] >= 0) tmpisvalid[i] = true;
479                continue;
480             }
481          }
482          else  // kDontValidate
483          {
484             tmpareacode[i] = sInside;
485                if (tmpdist[i] >= 0) tmpisvalid[i] = true;
486             continue;
487          }
488       }      
489 
490       if (tmpdist[0] <= tmpdist[1])
491       {
492           distance[0] = tmpdist[0];
493           distance[1] = tmpdist[1];
494           xx[0]       = tmpxx[0];
495           xx[1]       = tmpxx[1];
496           gxx[0]      = ComputeGlobalPoint(tmpxx[0]);
497           gxx[1]      = ComputeGlobalPoint(tmpxx[1]);
498           areacode[0] = tmpareacode[0];
499           areacode[1] = tmpareacode[1];
500           isvalid[0]  = tmpisvalid[0];
501           isvalid[1]  = tmpisvalid[1];
502       }
503       else
504       {
505           distance[0] = tmpdist[1];
506           distance[1] = tmpdist[0];
507           xx[0]       = tmpxx[1];
508           xx[1]       = tmpxx[0];
509           gxx[0]      = ComputeGlobalPoint(tmpxx[1]);
510           gxx[1]      = ComputeGlobalPoint(tmpxx[0]);
511           areacode[0] = tmpareacode[1];
512           areacode[1] = tmpareacode[0];
513           isvalid[0]  = tmpisvalid[1];
514           isvalid[1]  = tmpisvalid[0];
515       }
516          
517       fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
518                                      isvalid[0], 2, validate, &gp, &gv);
519       fCurStatWithV.SetCurrentStatus(1, gxx[1], distance[1], areacode[1],
520                                      isvalid[1], 2, validate, &gp, &gv);
521       vout = 2;
522    }
523    else
524    {
525       // if D<0, no solution
526       // if D=0, just grazing the surfaces, return kInfinity
527 
528       fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
529                                      isvalid[0], 0, validate, &gp, &gv);
530       vout = 0;
531    }
532    return vout;
533 }
534 
535 //=====================================================================
536 //* DistanceToSurface -------------------------------------------------
537 
538 G4int G4TwistTubsHypeSide::DistanceToSurface(const G4ThreeVector& gp,
539                                                    G4ThreeVector  gxx[],
540                                                    G4double       distance[],
541                                                    G4int          areacode[])
542 {
543     // Find the approximate distance of a point of a hyperbolic surface.
544     // The distance must be an underestimate. 
545     // It will also be nice (although not necessary) that the estimate is
546     // always finite no matter how close the point is.
547     //
548     // We arranged G4Hype::ApproxDistOutside and G4Hype::ApproxDistInside
549     // for this function. See these discriptions.
550     
551    const G4double halftol
552      = 0.5 * G4GeometryTolerance::GetInstance()->GetRadialTolerance();
553 
554    fCurStat.ResetfDone(kDontValidate, &gp);
555 
556    if (fCurStat.IsDone())
557    {
558       for (G4int i=0; i<fCurStat.GetNXX(); ++i)
559       {
560          gxx[i] = fCurStat.GetXX(i);
561          distance[i] = fCurStat.GetDistance(i);
562          areacode[i] = fCurStat.GetAreacode(i);
563       }
564       return fCurStat.GetNXX();
565    }
566    else  // initialize
567    {
568       for (auto i=0; i<2; ++i)
569       {
570          distance[i] = kInfinity;
571          areacode[i] = sOutside;
572          gxx[i].set(kInfinity, kInfinity, kInfinity);
573       }
574    }
575    
576 
577    G4ThreeVector p = ComputeLocalPoint(gp);
578    G4ThreeVector xx;
579 
580    //
581    // special case!
582    // If p is on surface, return distance = 0 immediatery .
583    //
584    G4ThreeVector  lastgxx[2];
585    for (auto i=0; i<2; ++i)
586    {
587       lastgxx[i] = fCurStatWithV.GetXX(i);
588    }
589 
590    if ((gp - lastgxx[0]).mag() < halftol || (gp - lastgxx[1]).mag() < halftol)
591    {
592       // last winner, or last poststep point is on the surface.
593       xx = p;             
594       gxx[0] = gp;
595       distance[0] = 0;      
596 
597       G4bool isvalid = true;
598       fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
599                                 isvalid, 1, kDontValidate, &gp);
600 
601       return 1;
602    }
603    //
604    // special case end
605    //
606        
607    G4double prho       = p.getRho();
608    G4double pz         = std::fabs(p.z());           // use symmetry
609    G4double r1         = std::sqrt(fR02 + pz * pz * fTan2Stereo);
610    
611    G4ThreeVector pabsz(p.x(), p.y(), pz);
612     
613    if (prho > r1 + halftol)   // p is outside of Hyperbolic surface
614    {
615       // First point xx1
616       G4double t = r1 / prho;
617       G4ThreeVector xx1(t * pabsz.x(), t * pabsz.y() , pz);
618       
619       // Second point xx2
620       G4double z2 = (prho * fTanStereo + pz) / (1 + fTan2Stereo);
621       G4double r2 = std::sqrt(fR02 + z2 * z2 * fTan2Stereo);
622       t = r2 / prho;
623       G4ThreeVector xx2(t * pabsz.x(), t * pabsz.y() , z2);
624             
625       G4double len = (xx2 - xx1).mag();
626       if (len < DBL_MIN)
627       {
628          // xx2 = xx1?? I guess we
629          // must have really bracketed the normal
630          distance[0] = (pabsz - xx1).mag();
631          xx = xx1;
632       }
633       else
634       {
635          distance[0] = DistanceToLine(pabsz, xx1, (xx2 - xx1) , xx);
636       }
637       
638    }
639    else if (prho < r1 - halftol)  // p is inside of Hyperbolic surface.
640    {
641       // First point xx1
642       G4double t;
643       G4ThreeVector xx1;
644       if (prho < DBL_MIN)
645       {
646          xx1.set(r1, 0. , pz);
647       }
648       else
649       {
650          t = r1 / prho;
651          xx1.set(t * pabsz.x(), t * pabsz.y() , pz);
652       }
653       
654       // dr, dz is tangential vector of Hyparbolic surface at xx1
655       // dr = r, dz = z*tan2stereo
656       G4double dr  = pz * fTan2Stereo;
657       G4double dz  = r1;
658       G4double tanbeta   = dr / dz;
659       G4double pztanbeta = pz * tanbeta;
660       
661       // Second point xx2 
662       // xx2 is intersection between x-axis and tangential vector
663       G4double r2 = r1 - pztanbeta;
664       G4ThreeVector xx2;
665       if (prho < DBL_MIN)
666       {
667          xx2.set(r2, 0. , 0.);
668       }
669       else
670       {
671          t  = r2 / prho;
672          xx2.set(t * pabsz.x(), t * pabsz.y() , 0.);
673       }
674       
675       G4ThreeVector d = xx2 - xx1;
676       distance[0] = DistanceToLine(pabsz, xx1, d, xx);
677           
678    }
679    else   // p is on Hyperbolic surface.
680    {
681       distance[0] = 0;
682       xx.set(p.x(), p.y(), pz);
683    }
684 
685    if (p.z() < 0)
686    {
687       G4ThreeVector tmpxx(xx.x(), xx.y(), -xx.z());
688       xx = tmpxx;
689    }
690        
691    gxx[0] = ComputeGlobalPoint(xx);
692    areacode[0]    = sInside;
693    G4bool isvalid = true;
694    fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
695                              isvalid, 1, kDontValidate, &gp);
696    return 1;
697 }
698 
699 //=====================================================================
700 //* GetAreaCode -------------------------------------------------------
701 
702 G4int G4TwistTubsHypeSide::GetAreaCode(const G4ThreeVector& xx, 
703                                              G4bool         withTol)
704 {
705    const G4double ctol = 0.5 * kCarTolerance;
706    G4int areacode = sInside;
707 
708    if ((fAxis[0] == kPhi && fAxis[1] == kZAxis))
709    {
710       G4int zaxis   = 1;
711       
712       if (withTol)
713       {
714          G4bool isoutside      = false;
715          G4int  phiareacode    = GetAreaCodeInPhi(xx);
716          G4bool isoutsideinphi = IsOutside(phiareacode);
717 
718          // test boundary of phiaxis
719 
720          if ((phiareacode & sAxisMin) == sAxisMin)
721          {
722             areacode |= (sAxis0 & (sAxisPhi | sAxisMin)) | sBoundary;
723             if (isoutsideinphi) isoutside = true;
724          }
725          else if ((phiareacode & sAxisMax)  == sAxisMax)
726          {
727             areacode |= (sAxis0 & (sAxisPhi | sAxisMax)) | sBoundary;
728             if (isoutsideinphi) isoutside = true;
729          }
730 
731          // test boundary of zaxis
732 
733          if (xx.z() < fAxisMin[zaxis] + ctol)
734          {
735             areacode |= (sAxis1 & (sAxisZ | sAxisMin));
736             if   ((areacode & sBoundary) != 0) areacode |= sCorner;  // xx is on corner.
737             else                        areacode |= sBoundary;
738 
739             if (xx.z() <= fAxisMin[zaxis] - ctol) isoutside = true;
740 
741          }
742          else if (xx.z() > fAxisMax[zaxis] - ctol)
743          {
744             areacode |= (sAxis1 & (sAxisZ | sAxisMax));
745             if   ((areacode & sBoundary) != 0) areacode |= sCorner;  // xx is on corner.
746             else                        areacode |= sBoundary;
747 
748             if (xx.z() >= fAxisMax[zaxis] + ctol) isoutside = true;
749          }
750 
751          // if isoutside = true, clear sInside bit.
752          // if not on boundary, add boundary information. 
753 
754          if (isoutside)
755          {
756             G4int tmpareacode = areacode & (~sInside);
757             areacode = tmpareacode;
758          }
759          else if ((areacode & sBoundary) != sBoundary)
760          {
761             areacode |= (sAxis0 & sAxisPhi) | (sAxis1 & sAxisZ);
762          }
763 
764          return areacode;
765       }
766       else
767       {
768          G4int phiareacode = GetAreaCodeInPhi(xx, false);
769          
770          // test boundary of z-axis
771 
772          if (xx.z() < fAxisMin[zaxis])
773          {
774             areacode |= (sAxis1 & (sAxisZ | sAxisMin)) | sBoundary;
775 
776          }
777          else if (xx.z() > fAxisMax[zaxis])
778          {
779             areacode |= (sAxis1 & (sAxisZ | sAxisMax)) | sBoundary;
780          }
781 
782          // boundary of phi-axis
783 
784          if (phiareacode == sAxisMin)
785          {
786             areacode |= (sAxis0 & (sAxisPhi | sAxisMin));
787             if   ((areacode & sBoundary) != 0) areacode |= sCorner;  // xx is on corner.
788             else                        areacode |= sBoundary; 
789              
790          }
791          else if (phiareacode == sAxisMax)
792          {
793             areacode |= (sAxis0 & (sAxisPhi | sAxisMax));
794             if   ((areacode & sBoundary) != 0) areacode |= sCorner;  // xx is on corner.
795             else                        areacode |= sBoundary;
796          }
797 
798          // if not on boundary, add boundary information. 
799 
800          if ((areacode & sBoundary) != sBoundary)
801          {
802             areacode |= (sAxis0 & sAxisPhi) | (sAxis1 & sAxisZ);
803          }
804          return areacode;
805       }
806    }
807    else
808    {
809       std::ostringstream message;
810       message << "Feature NOT implemented !" << G4endl
811               << "        fAxis[0] = " << fAxis[0] << G4endl
812               << "        fAxis[1] = " << fAxis[1];
813       G4Exception("G4TwistTubsHypeSide::GetAreaCode()",
814                   "GeomSolids0001", FatalException, message);
815    }
816    return areacode;
817 }
818 
819 //=====================================================================
820 //* GetAreaCodeInPhi --------------------------------------------------
821 
822 G4int G4TwistTubsHypeSide::GetAreaCodeInPhi(const G4ThreeVector& xx,
823                                                   G4bool withTol)
824 {
825    
826    G4ThreeVector lowerlimit; // lower phi-boundary limit at z = xx.z()
827    G4ThreeVector upperlimit; // upper phi-boundary limit at z = xx.z()
828    lowerlimit = GetBoundaryAtPZ(sAxis0 & sAxisMin, xx);
829    upperlimit = GetBoundaryAtPZ(sAxis0 & sAxisMax, xx);
830 
831    G4int  areacode  = sInside;
832    G4bool isoutside = false; 
833    
834    if (withTol)
835    {
836       if (AmIOnLeftSide(xx, lowerlimit) >= 0)       // xx is on lowerlimit
837       {
838          areacode |= (sAxisMin | sBoundary);
839          if (AmIOnLeftSide(xx, lowerlimit) > 0) isoutside = true; 
840 
841       }
842       else if (AmIOnLeftSide(xx, upperlimit) <= 0)  // xx is on upperlimit
843       {
844          areacode |= (sAxisMax | sBoundary);
845          if (AmIOnLeftSide(xx, upperlimit) < 0) isoutside = true; 
846       }
847 
848       // if isoutside = true, clear inside bit.
849 
850       if (isoutside)
851       {
852          G4int tmpareacode = areacode & (~sInside);
853          areacode = tmpareacode;
854       }
855    }
856    else
857    {
858       if (AmIOnLeftSide(xx, lowerlimit, false) >= 0)
859       {
860          areacode |= (sAxisMin | sBoundary);
861       }
862       else if (AmIOnLeftSide(xx, upperlimit, false) <= 0)
863       {
864          areacode |= (sAxisMax | sBoundary);
865       }
866    }
867 
868    return areacode;
869 }
870 
871 //=====================================================================
872 //* SetCorners(EndInnerRadius, EndOuterRadius,DPhi,EndPhi,EndZ) -------
873 
874 void G4TwistTubsHypeSide::SetCorners( G4double         EndInnerRadius[2],
875                                       G4double         EndOuterRadius[2],
876                                       G4double         DPhi,
877                                       G4double         endPhi[2],
878                                       G4double         endZ[2] )
879 {
880    // Set Corner points in local coodinate.
881 
882    if (fAxis[0] == kPhi && fAxis[1] == kZAxis) {
883 
884       G4double endRad[2];
885       G4double halfdphi = 0.5*DPhi;
886       
887       for (auto i=0; i<2; ++i) // i=0,1 : -ve z, +ve z
888       {
889         endRad[i] = (fHandedness == 1 ? EndOuterRadius[i] : EndInnerRadius[i]);
890       }
891 
892       G4int zmin = 0 ;  // at -ve z
893       G4int zmax = 1 ;  // at +ve z
894 
895       G4double x, y, z;
896       
897       // corner of Axis0min and Axis1min
898       x = endRad[zmin]*std::cos(endPhi[zmin] - halfdphi);
899       y = endRad[zmin]*std::sin(endPhi[zmin] - halfdphi);
900       z = endZ[zmin];
901       SetCorner(sC0Min1Min, x, y, z);
902       
903       // corner of Axis0max and Axis1min
904       x = endRad[zmin]*std::cos(endPhi[zmin] + halfdphi);
905       y = endRad[zmin]*std::sin(endPhi[zmin] + halfdphi);
906       z = endZ[zmin];
907       SetCorner(sC0Max1Min, x, y, z);
908       
909       // corner of Axis0max and Axis1max
910       x = endRad[zmax]*std::cos(endPhi[zmax] + halfdphi);
911       y = endRad[zmax]*std::sin(endPhi[zmax] + halfdphi);
912       z = endZ[zmax];
913       SetCorner(sC0Max1Max, x, y, z);
914       
915       // corner of Axis0min and Axis1max
916       x = endRad[zmax]*std::cos(endPhi[zmax] - halfdphi);
917       y = endRad[zmax]*std::sin(endPhi[zmax] - halfdphi);
918       z = endZ[zmax];
919       SetCorner(sC0Min1Max, x, y, z);
920 
921    }
922    else
923    {
924       std::ostringstream message;
925       message << "Feature NOT implemented !" << G4endl
926               << "        fAxis[0] = " << fAxis[0] << G4endl
927               << "        fAxis[1] = " << fAxis[1];
928       G4Exception("G4TwistTubsHypeSide::SetCorners()",
929                   "GeomSolids0001", FatalException, message);
930    }
931 }
932 
933 //=====================================================================
934 //* SetCorners() ------------------------------------------------------
935 
936 void G4TwistTubsHypeSide::SetCorners()
937 {
938    G4Exception("G4TwistTubsHypeSide::SetCorners()",
939                "GeomSolids0001", FatalException,
940                "Method NOT implemented !");
941 }
942 
943 //=====================================================================
944 //* SetBoundaries() ---------------------------------------------------
945 
946 void G4TwistTubsHypeSide::SetBoundaries()
947 {
948    // Set direction-unit vector of phi-boundary-lines in local coodinate.
949    // sAxis0 must be kPhi.
950    // This fanction set lower phi-boundary and upper phi-boundary.
951 
952    if (fAxis[0] == kPhi && fAxis[1] == kZAxis)
953    {
954       G4ThreeVector direction;
955       // sAxis0 & sAxisMin
956       direction = GetCorner(sC0Min1Max) - GetCorner(sC0Min1Min);
957       direction = direction.unit();
958       SetBoundary(sAxis0 & (sAxisPhi | sAxisMin), direction, 
959                    GetCorner(sC0Min1Min), sAxisZ);
960 
961       // sAxis0 & sAxisMax
962       direction = GetCorner(sC0Max1Max) - GetCorner(sC0Max1Min);
963       direction = direction.unit();
964       SetBoundary(sAxis0 & (sAxisPhi | sAxisMax), direction, 
965                   GetCorner(sC0Max1Min), sAxisZ);
966 
967       // sAxis1 & sAxisMin
968       direction = GetCorner(sC0Max1Min) - GetCorner(sC0Min1Min);
969       direction = direction.unit();
970       SetBoundary(sAxis1 & (sAxisZ | sAxisMin), direction, 
971                    GetCorner(sC0Min1Min), sAxisPhi);
972 
973       // sAxis1 & sAxisMax
974       direction = GetCorner(sC0Max1Max) - GetCorner(sC0Min1Max);
975       direction = direction.unit();
976       SetBoundary(sAxis1 & (sAxisZ | sAxisMax), direction, 
977                   GetCorner(sC0Min1Max), sAxisPhi);
978    }
979    else
980    {
981       std::ostringstream message;
982       message << "Feature NOT implemented !" << G4endl
983               << "        fAxis[0] = " << fAxis[0] << G4endl
984               << "        fAxis[1] = " << fAxis[1];
985       G4Exception("G4TwistTubsHypeSide::SetBoundaries()",
986                   "GeomSolids0001", FatalException, message);
987    }
988 }
989 
990 //=====================================================================
991 //* GetFacets() -------------------------------------------------------
992 
993 void G4TwistTubsHypeSide::GetFacets( G4int k, G4int n, G4double xyz[][3],
994                                      G4int faces[][4], G4int iside ) 
995 {
996   G4double z ;     // the two parameters for the surface equation
997   G4double x,xmin,xmax ;
998 
999   G4ThreeVector p ;  // a point on the surface, given by (z,u)
1000 
1001   G4int nnode ;
1002   G4int nface ;
1003 
1004   // calculate the (n-1)*(k-1) vertices
1005 
1006   for ( G4int i = 0 ; i<n ; ++i )
1007   {
1008     z = fAxisMin[1] + i*(fAxisMax[1]-fAxisMin[1])/(n-1) ;
1009 
1010     for ( G4int j = 0 ; j<k ; ++j )
1011     {
1012       nnode = GetNode(i,j,k,n,iside) ;
1013 
1014       xmin = GetBoundaryMin(z) ; 
1015       xmax = GetBoundaryMax(z) ;
1016 
1017       if (fHandedness < 0)  // inner hyperbolic surface
1018       {
1019         x = xmin + j*(xmax-xmin)/(k-1) ;
1020       }
1021       else                  // outer hyperbolic surface
1022       {
1023         x = xmax - j*(xmax-xmin)/(k-1) ;
1024       }
1025 
1026       p = SurfacePoint(x,z,true) ;  // surface point in global coord.system
1027 
1028       xyz[nnode][0] = p.x() ;
1029       xyz[nnode][1] = p.y() ;
1030       xyz[nnode][2] = p.z() ;
1031 
1032       if ( i<n-1 && j<k-1 )    // clock wise filling
1033       {
1034         nface = GetFace(i,j,k,n,iside) ;
1035   faces[nface][0] = GetEdgeVisibility(i,j,k,n,0,1)
1036                         * ( GetNode(i  ,j  ,k,n,iside)+1) ;  
1037   faces[nface][1] = GetEdgeVisibility(i,j,k,n,1,1)
1038                         * ( GetNode(i+1,j  ,k,n,iside)+1) ;
1039   faces[nface][2] = GetEdgeVisibility(i,j,k,n,2,1)
1040                         * ( GetNode(i+1,j+1,k,n,iside)+1) ;
1041   faces[nface][3] = GetEdgeVisibility(i,j,k,n,3,1)
1042                         * ( GetNode(i  ,j+1,k,n,iside)+1) ;
1043       }
1044     }
1045   }
1046 }
1047