source: trunk/source/geometry/solids/CSG/src/G4Tubs.cc @ 1198

Last change on this file since 1198 was 1058, checked in by garnier, 15 years ago

file release beta

File size: 55.0 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: G4Tubs.cc,v 1.74 2008/11/06 15:26:53 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-02-ref-02 $
29//
30//
31// class G4Tubs
32//
33// History:
34//
35// 02.08.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for negative value under sqrt
36//                      for the case: p on the surface and v is tangent to the surface
37// 11.05.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for phi < 2pi
38// 03.05.05 V.Grichine: SurfaceNormal(p) according to J. Apostolakis proposal
39// 16.03.05 V.Grichine: SurfaceNormal(p) with edges/corners for boolean
40// 20.07.01 V.Grichine: bug fixed in Inside(p)
41// 20.02.01 V.Grichine: bug fixed in Inside(p) and CalculateExtent was
42//                      simplified base on G4Box::CalculateExtent
43// 07.12.00 V.Grichine: phi-section algorithm was changed in Inside(p)
44// 28.11.00 V.Grichine: bug fixed in Inside(p)
45// 31.10.00 V.Grichine: assign sr, sphi in Distance ToOut(p,v,...)
46// 08.08.00 V.Grichine: more stable roots of 2-equation in DistanceToOut(p,v,..)
47// 02.08.00 V.Grichine: point is outside check in Distance ToOut(p)
48// 17.05.00 V.Grichine: bugs (#76,#91) fixed in Distance ToOut(p,v,...)
49// 31.03.00 V.Grichine: bug fixed in Inside(p)
50// 19.11.99 V.Grichine: side = kNull in DistanceToOut(p,v,...)
51// 13.10.99 V.Grichine: bugs fixed in DistanceToIn(p,v)
52// 28.05.99 V.Grichine: bugs fixed in DistanceToOut(p,v,...)
53// 25.05.99 V.Grichine: bugs fixed in DistanceToIn(p,v)
54// 23.03.99 V.Grichine: bug fixed in DistanceToIn(p,v)
55// 09.10.98 V.Grichine: modifications in DistanceToOut(p,v,...)
56// 18.06.98 V.Grichine: n-normalisation in DistanceToOut(p,v)
57//
58// 1994-95  P.Kent:     implementation
59//
60/////////////////////////////////////////////////////////////////////////
61
62#include "G4Tubs.hh"
63
64#include "G4VoxelLimits.hh"
65#include "G4AffineTransform.hh"
66#include "G4GeometryTolerance.hh"
67
68#include "G4VPVParameterisation.hh"
69
70#include "Randomize.hh"
71
72#include "meshdefs.hh"
73
74#include "G4VGraphicsScene.hh"
75#include "G4Polyhedron.hh"
76#include "G4NURBS.hh"
77#include "G4NURBStube.hh"
78#include "G4NURBScylinder.hh"
79#include "G4NURBStubesector.hh"
80
81using namespace CLHEP;
82
83/////////////////////////////////////////////////////////////////////////
84//
85// Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
86//             - note if pdphi>2PI then reset to 2PI
87
88G4Tubs::G4Tubs( const G4String &pName,
89                      G4double pRMin, G4double pRMax,
90                      G4double pDz,
91                      G4double pSPhi, G4double pDPhi )
92  : G4CSGSolid(pName)
93{
94
95  kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance();
96  kAngTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance();
97
98  if (pDz>0) // Check z-len
99  {
100    fDz = pDz ;
101  }
102  else
103  {
104    G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
105           << "        Negative Z half-length ! - "
106           << pDz << G4endl;
107    G4Exception("G4Tubs::G4Tubs()", "InvalidSetup", FatalException,
108                "Invalid Z half-length");
109  }
110  if ( (pRMin < pRMax) && (pRMin >= 0) ) // Check radii
111  {
112    fRMin = pRMin ; 
113    fRMax = pRMax ;
114  }
115  else
116  {
117    G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
118           << "        Invalid values for radii !" << G4endl
119           << "        pRMin = " << pRMin << ", pRMax = " << pRMax << G4endl;
120    G4Exception("G4Tubs::G4Tubs()", "InvalidSetup", FatalException,
121                "Invalid radii.");
122  }
123
124  fPhiFullTube = true;
125  if ( pDPhi >= twopi-kAngTolerance*0.5 ) // Check angles
126  {
127    fDPhi=twopi;
128    fSPhi=0;
129  }
130  else
131  {
132    fPhiFullTube = false;
133    if ( pDPhi > 0 )
134    {
135      fDPhi = pDPhi;
136    }
137    else
138    {
139      G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
140             << "        Negative delta-Phi ! - "
141             << pDPhi << G4endl;
142      G4Exception("G4Tubs::G4Tubs()", "InvalidSetup",
143                  FatalException, "Invalid dphi.");
144    }
145
146    // Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
147
148    if ( pSPhi < 0 )
149    {
150      fSPhi = twopi - std::fmod(std::fabs(pSPhi),twopi);
151    }
152    else
153    {
154      fSPhi = std::fmod(pSPhi,twopi) ;
155    }
156    if ( fSPhi+fDPhi > twopi )
157    {
158      fSPhi -= twopi ;
159    }
160  }
161  InitializeTrigonometry();
162}
163
164///////////////////////////////////////////////////////////////////////
165//
166// Fake default constructor - sets only member data and allocates memory
167//                            for usage restricted to object persistency.
168//
169G4Tubs::G4Tubs( __void__& a )
170  : G4CSGSolid(a)
171{
172}
173
174//////////////////////////////////////////////////////////////////////////
175//
176// Destructor
177
178G4Tubs::~G4Tubs()
179{
180}
181
182/////////////////////////////////////////////////////////////////////////
183//
184// Dispatch to parameterisation for replication mechanism dimension
185// computation & modification.
186
187void G4Tubs::ComputeDimensions(       G4VPVParameterisation* p,
188                                const G4int n,
189                                const G4VPhysicalVolume* pRep )
190{
191  p->ComputeDimensions(*this,n,pRep) ;
192}
193
194////////////////////////////////////////////////////////////////////////
195//
196// Calculate extent under transform and specified limit
197
198G4bool G4Tubs::CalculateExtent( const EAxis              pAxis,
199                                const G4VoxelLimits&     pVoxelLimit,
200                                const G4AffineTransform& pTransform,
201                                      G4double&          pMin, 
202                                      G4double&          pMax    ) const
203{
204
205  if ( !pTransform.IsRotated() && fDPhi == twopi && fRMin == 0 )
206  {
207    // Special case handling for unrotated solid tubes
208    // Compute x/y/z mins and maxs fro bounding box respecting limits,
209    // with early returns if outside limits. Then switch() on pAxis,
210    // and compute exact x and y limit for x/y case
211     
212    G4double xoffset, xMin, xMax ;
213    G4double yoffset, yMin, yMax ;
214    G4double zoffset, zMin, zMax ;
215
216    G4double diff1, diff2, maxDiff, newMin, newMax ;
217    G4double xoff1, xoff2, yoff1, yoff2, delta ;
218
219    xoffset = pTransform.NetTranslation().x() ;
220    xMin = xoffset - fRMax ;
221    xMax = xoffset + fRMax ;
222
223    if (pVoxelLimit.IsXLimited())
224    {
225      if ( (xMin > pVoxelLimit.GetMaxXExtent())
226        || (xMax < pVoxelLimit.GetMinXExtent()) )
227      {
228        return false;
229      }
230      else
231      {
232        if ( xMin < pVoxelLimit.GetMinXExtent() )
233        {
234          xMin = pVoxelLimit.GetMinXExtent() ;
235        }
236        if (xMax > pVoxelLimit.GetMaxXExtent() )
237        {
238          xMax = pVoxelLimit.GetMaxXExtent() ;
239        }
240      }
241    }
242    yoffset = pTransform.NetTranslation().y() ;
243    yMin    = yoffset - fRMax ;
244    yMax    = yoffset + fRMax ;
245
246    if ( pVoxelLimit.IsYLimited() )
247    {
248      if ( (yMin > pVoxelLimit.GetMaxYExtent())
249        || (yMax < pVoxelLimit.GetMinYExtent()) )
250      {
251        return false ;
252      }
253      else
254      {
255        if ( yMin < pVoxelLimit.GetMinYExtent() )
256        {
257          yMin = pVoxelLimit.GetMinYExtent() ;
258        }
259        if ( yMax > pVoxelLimit.GetMaxYExtent() )
260        {
261          yMax=pVoxelLimit.GetMaxYExtent();
262        }
263      }
264    }
265    zoffset = pTransform.NetTranslation().z() ;
266    zMin    = zoffset - fDz ;
267    zMax    = zoffset + fDz ;
268
269    if ( pVoxelLimit.IsZLimited() )
270    {
271      if ( (zMin > pVoxelLimit.GetMaxZExtent())
272        || (zMax < pVoxelLimit.GetMinZExtent()) )
273      {
274        return false ;
275      }
276      else
277      {
278        if ( zMin < pVoxelLimit.GetMinZExtent() )
279        {
280          zMin = pVoxelLimit.GetMinZExtent() ;
281        }
282        if ( zMax > pVoxelLimit.GetMaxZExtent() )
283        {
284          zMax = pVoxelLimit.GetMaxZExtent();
285        }
286      }
287    }
288    switch ( pAxis )  // Known to cut cylinder
289    {
290      case kXAxis :
291      {
292        yoff1 = yoffset - yMin ;
293        yoff2 = yMax    - yoffset ;
294
295        if ( (yoff1 >= 0) && (yoff2 >= 0) ) // Y limits cross max/min x
296        {                                   // => no change
297          pMin = xMin ;
298          pMax = xMax ;
299        }
300        else
301        {
302          // Y limits don't cross max/min x => compute max delta x,
303          // hence new mins/maxs
304
305          delta   = fRMax*fRMax - yoff1*yoff1;
306          diff1   = (delta>0.) ? std::sqrt(delta) : 0.;
307          delta   = fRMax*fRMax - yoff2*yoff2;
308          diff2   = (delta>0.) ? std::sqrt(delta) : 0.;
309          maxDiff = (diff1 > diff2) ? diff1:diff2;
310          newMin  = xoffset - maxDiff;
311          newMax  = xoffset + maxDiff;
312          pMin    = (newMin < xMin) ? xMin : newMin;
313          pMax    = (newMax > xMax) ? xMax : newMax;
314        }   
315        break;
316      }
317      case kYAxis :
318      {
319        xoff1 = xoffset - xMin ;
320        xoff2 = xMax - xoffset ;
321
322        if ( (xoff1 >= 0) && (xoff2 >= 0) ) // X limits cross max/min y
323        {                                   // => no change
324          pMin = yMin ;
325          pMax = yMax ;
326        }
327        else
328        {
329          // X limits don't cross max/min y => compute max delta y,
330          // hence new mins/maxs
331
332          delta   = fRMax*fRMax - xoff1*xoff1;
333          diff1   = (delta>0.) ? std::sqrt(delta) : 0.;
334          delta   = fRMax*fRMax - xoff2*xoff2;
335          diff2   = (delta>0.) ? std::sqrt(delta) : 0.;
336          maxDiff = (diff1 > diff2) ? diff1 : diff2 ;
337          newMin  = yoffset - maxDiff ;
338          newMax  = yoffset + maxDiff ;
339          pMin    = (newMin < yMin) ? yMin : newMin ;
340          pMax     =(newMax > yMax) ? yMax : newMax ;
341        }
342        break ;
343      }
344      case kZAxis:
345      {
346        pMin = zMin ;
347        pMax = zMax ;
348        break ;
349      }
350      default:
351        break;
352    }
353    pMin -= kCarTolerance ;
354    pMax += kCarTolerance ;
355    return true;   
356  }
357  else // Calculate rotated vertex coordinates
358  {
359    G4int i, noEntries, noBetweenSections4 ;
360    G4bool existsAfterClip = false ;
361    G4ThreeVectorList* vertices = CreateRotatedVertices(pTransform) ;
362   
363    pMin = +kInfinity ;
364    pMax = -kInfinity ;
365
366    noEntries = vertices->size() ;
367    noBetweenSections4 = noEntries - 4 ;
368   
369    for (i = 0 ; i < noEntries ; i += 4 )
370    {
371      ClipCrossSection(vertices, i, pVoxelLimit, pAxis, pMin, pMax) ;
372    }
373    for (i = 0 ; i < noBetweenSections4 ; i += 4 )
374    {
375      ClipBetweenSections(vertices, i, pVoxelLimit, pAxis, pMin, pMax) ;
376    }
377    if ((pMin != kInfinity) || (pMax != -kInfinity) )
378    {
379      existsAfterClip = true ;
380      pMin -= kCarTolerance ; // Add 2*tolerance to avoid precision troubles
381      pMax += kCarTolerance ;
382    }
383    else
384    {
385      // Check for case where completely enveloping clipping volume
386      // If point inside then we are confident that the solid completely
387      // envelopes the clipping volume. Hence set min/max extents according
388      // to clipping volume extents along the specified axis.
389
390      G4ThreeVector clipCentre(
391             (pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
392             (pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
393             (pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5 ) ;
394       
395      if ( Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside )
396      {
397        existsAfterClip = true ;
398        pMin            = pVoxelLimit.GetMinExtent(pAxis) ;
399        pMax            = pVoxelLimit.GetMaxExtent(pAxis) ;
400      }
401    }
402    delete vertices;
403    return existsAfterClip;
404  }
405}
406
407
408///////////////////////////////////////////////////////////////////////////
409//
410// Return whether point inside/outside/on surface
411
412EInside G4Tubs::Inside( const G4ThreeVector& p ) const
413{
414  G4double r2,pPhi,tolRMin,tolRMax;
415  EInside in = kOutside ;
416  static const G4double halfCarTolerance=kCarTolerance*0.5;
417  static const G4double halfRadTolerance=kRadTolerance*0.5;
418  static const G4double halfAngTolerance=kAngTolerance*0.5;
419
420  if (std::fabs(p.z()) <= fDz - halfCarTolerance)
421  {
422    r2 = p.x()*p.x() + p.y()*p.y() ;
423
424    if (fRMin) { tolRMin = fRMin + halfRadTolerance ; }
425    else       { tolRMin = 0 ; }
426
427    tolRMax = fRMax - halfRadTolerance ;
428     
429    if ((r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax))
430    {
431      if ( fPhiFullTube )
432      {
433        in = kInside ;
434      }
435      else
436      {
437        // Try inner tolerant phi boundaries (=>inside)
438        // if not inside, try outer tolerant phi boundaries
439
440        if ((tolRMin==0)&&(p.x()<=halfCarTolerance)&&(p.y()<=halfCarTolerance))
441        {
442          in=kSurface;
443        }
444        else
445        {
446          pPhi = std::atan2(p.y(),p.x()) ;
447          if ( pPhi < -halfAngTolerance )  { pPhi += twopi; } // 0<=pPhi<2pi
448
449          if ( fSPhi >= 0 )
450          {
451            if ( (std::abs(pPhi) < halfAngTolerance)
452              && (std::abs(fSPhi + fDPhi - twopi) < halfAngTolerance) )
453            { 
454              pPhi += twopi ; // 0 <= pPhi < 2pi
455            }
456            if ( (pPhi >= fSPhi + halfAngTolerance)
457              && (pPhi <= fSPhi + fDPhi - halfAngTolerance) )
458            {
459              in = kInside ;
460            }
461            else if ( (pPhi >= fSPhi - halfAngTolerance)
462                   && (pPhi <= fSPhi + fDPhi + halfAngTolerance) )
463            {
464              in = kSurface ;
465            }
466          }
467          else  // fSPhi < 0
468          {
469            if ( (pPhi <= fSPhi + twopi - halfAngTolerance)
470              && (pPhi >= fSPhi + fDPhi  + halfAngTolerance) ) {;} //kOutside
471            else if ( (pPhi <= fSPhi + twopi + halfAngTolerance)
472                   && (pPhi >= fSPhi + fDPhi  - halfAngTolerance) )
473            {
474              in = kSurface ;
475            }
476            else
477            {
478              in = kInside ;
479            }
480          }
481        }                   
482      }
483    }
484    else  // Try generous boundaries
485    {
486      tolRMin = fRMin - halfRadTolerance ;
487      tolRMax = fRMax + halfRadTolerance ;
488
489      if ( tolRMin < 0 )  { tolRMin = 0; }
490
491      if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) )
492      {
493        if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance) )
494        {                        // Continuous in phi or on z-axis
495          in = kSurface ;
496        }
497        else // Try outer tolerant phi boundaries only
498        {
499          pPhi = std::atan2(p.y(),p.x()) ;
500
501          if ( pPhi < -halfAngTolerance)  { pPhi += twopi; } // 0<=pPhi<2pi
502          if ( fSPhi >= 0 )
503          {
504            if ( (std::abs(pPhi) < halfAngTolerance)
505              && (std::abs(fSPhi + fDPhi - twopi) < halfAngTolerance) )
506            { 
507              pPhi += twopi ; // 0 <= pPhi < 2pi
508            }
509            if ( (pPhi >= fSPhi - halfAngTolerance)
510              && (pPhi <= fSPhi + fDPhi + halfAngTolerance) )
511            {
512              in = kSurface ;
513            }
514          }
515          else  // fSPhi < 0
516          {
517            if ( (pPhi <= fSPhi + twopi - halfAngTolerance)
518              && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} // kOutside
519            else
520            {
521              in = kSurface ;
522            }
523          }
524        }
525      }
526    }
527  }
528  else if (std::fabs(p.z()) <= fDz + halfCarTolerance)
529  {                                          // Check within tolerant r limits
530    r2      = p.x()*p.x() + p.y()*p.y() ;
531    tolRMin = fRMin - halfRadTolerance ;
532    tolRMax = fRMax + halfRadTolerance ;
533
534    if ( tolRMin < 0 )  { tolRMin = 0; }
535
536    if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) )
537    {
538      if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance))
539      {                        // Continuous in phi or on z-axis
540        in = kSurface ;
541      }
542      else // Try outer tolerant phi boundaries
543      {
544        pPhi = std::atan2(p.y(),p.x()) ;
545
546        if ( pPhi < -halfAngTolerance )  { pPhi += twopi; }  // 0<=pPhi<2pi
547        if ( fSPhi >= 0 )
548        {
549          if ( (std::abs(pPhi) < halfAngTolerance)
550            && (std::abs(fSPhi + fDPhi - twopi) < halfAngTolerance) )
551          { 
552            pPhi += twopi ; // 0 <= pPhi < 2pi
553          }
554          if ( (pPhi >= fSPhi - halfAngTolerance)
555            && (pPhi <= fSPhi + fDPhi + halfAngTolerance) )
556          {
557            in = kSurface;
558          }
559        }
560        else  // fSPhi < 0
561        {
562          if ( (pPhi <= fSPhi + twopi - halfAngTolerance)
563            && (pPhi >= fSPhi + fDPhi  + halfAngTolerance) ) {;}
564          else
565          {
566            in = kSurface ;
567          }
568        }     
569      }
570    }
571  }
572  return in;
573}
574
575///////////////////////////////////////////////////////////////////////////
576//
577// Return unit normal of surface closest to p
578// - note if point on z axis, ignore phi divided sides
579// - unsafe if point close to z axis a rmin=0 - no explicit checks
580
581G4ThreeVector G4Tubs::SurfaceNormal( const G4ThreeVector& p ) const
582{
583  G4int noSurfaces = 0;
584  G4double rho, pPhi;
585  G4double distZ, distRMin, distRMax;
586  G4double distSPhi = kInfinity, distEPhi = kInfinity;
587
588  static const G4double halfCarTolerance = 0.5*kCarTolerance;
589  static const G4double halfAngTolerance = 0.5*kAngTolerance;
590
591  G4ThreeVector norm, sumnorm(0.,0.,0.);
592  G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0);
593  G4ThreeVector nR, nPs, nPe;
594
595  rho = std::sqrt(p.x()*p.x() + p.y()*p.y());
596
597  distRMin = std::fabs(rho - fRMin);
598  distRMax = std::fabs(rho - fRMax);
599  distZ    = std::fabs(std::fabs(p.z()) - fDz);
600
601  if (!fPhiFullTube)    // Protected against (0,0,z)
602  {
603    if ( rho > halfCarTolerance )
604    {
605      pPhi = std::atan2(p.y(),p.x());
606   
607      if(pPhi  < fSPhi- halfCarTolerance)           { pPhi += twopi; }
608      else if(pPhi > fSPhi+fDPhi+ halfCarTolerance) { pPhi -= twopi; }
609
610      distSPhi = std::fabs(pPhi - fSPhi);       
611      distEPhi = std::fabs(pPhi - fSPhi - fDPhi); 
612    }
613    else if( !fRMin )
614    {
615      distSPhi = 0.; 
616      distEPhi = 0.; 
617    }
618    nPs = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0);
619    nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0);
620  }
621  if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); }
622
623  if( distRMax <= halfCarTolerance )
624  {
625    noSurfaces ++;
626    sumnorm += nR;
627  }
628  if( fRMin && (distRMin <= halfCarTolerance) )
629  {
630    noSurfaces ++;
631    sumnorm -= nR;
632  }
633  if( fDPhi < twopi )   
634  {
635    if (distSPhi <= halfAngTolerance) 
636    {
637      noSurfaces ++;
638      sumnorm += nPs;
639    }
640    if (distEPhi <= halfAngTolerance) 
641    {
642      noSurfaces ++;
643      sumnorm += nPe;
644    }
645  }
646  if (distZ <= halfCarTolerance) 
647  {
648    noSurfaces ++;
649    if ( p.z() >= 0.)  { sumnorm += nZ; }
650    else               { sumnorm -= nZ; }
651  }
652  if ( noSurfaces == 0 )
653  {
654#ifdef G4CSGDEBUG
655    G4Exception("G4Tube::SurfaceNormal(p)", "Notification",
656                JustWarning, "Point p is not on surface !?" );
657    G4cout.precision(20);
658    G4cout<< "G4Tubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); "
659          << G4endl << G4endl;
660#endif
661     norm = ApproxSurfaceNormal(p);
662  }
663  else if ( noSurfaces == 1 )  { norm = sumnorm; }
664  else                         { norm = sumnorm.unit(); }
665
666  return norm;
667}
668
669/////////////////////////////////////////////////////////////////////////////
670//
671// Algorithm for SurfaceNormal() following the original specification
672// for points not on the surface
673
674G4ThreeVector G4Tubs::ApproxSurfaceNormal( const G4ThreeVector& p ) const
675{ ENorm side ;
676  G4ThreeVector norm ;
677  G4double rho, phi ;
678  G4double distZ, distRMin, distRMax, distSPhi, distEPhi, distMin ;
679
680  rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
681
682  distRMin = std::fabs(rho - fRMin) ;
683  distRMax = std::fabs(rho - fRMax) ;
684  distZ    = std::fabs(std::fabs(p.z()) - fDz) ;
685
686  if (distRMin < distRMax) // First minimum
687  {
688    if ( distZ < distRMin )
689    {
690       distMin = distZ ;
691       side    = kNZ ;
692    }
693    else
694    {
695      distMin = distRMin ;
696      side    = kNRMin   ;
697    }
698  }
699  else
700  {
701    if ( distZ < distRMax )
702    {
703      distMin = distZ ;
704      side    = kNZ   ;
705    }
706    else
707    {
708      distMin = distRMax ;
709      side    = kNRMax   ;
710    }
711  }   
712  if (!fPhiFullTube  &&  rho ) // Protected against (0,0,z)
713  {
714    phi = std::atan2(p.y(),p.x()) ;
715
716    if ( phi < 0 )  { phi += twopi; }
717
718    if ( fSPhi < 0 )
719    {
720      distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ;
721    }
722    else
723    {
724      distSPhi = std::fabs(phi - fSPhi)*rho ;
725    }
726    distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ;
727                                     
728    if (distSPhi < distEPhi) // Find new minimum
729    {
730      if ( distSPhi < distMin )
731      {
732        side = kNSPhi ;
733      }
734    }
735    else
736    {
737      if ( distEPhi < distMin )
738      {
739        side = kNEPhi ;
740      }
741    }
742  }   
743  switch ( side )
744  {
745    case kNRMin : // Inner radius
746    {                     
747      norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, 0) ;
748      break ;
749    }
750    case kNRMax : // Outer radius
751    {                 
752      norm = G4ThreeVector(p.x()/rho, p.y()/rho, 0) ;
753      break ;
754    }
755    case kNZ : //    + or - dz
756    {                             
757      if ( p.z() > 0 )  { norm = G4ThreeVector(0,0,1) ; }
758      else              { norm = G4ThreeVector(0,0,-1); }
759      break ;
760    }
761    case kNSPhi:
762    {
763      norm = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0) ;
764      break ;
765    }
766    case kNEPhi:
767    {
768      norm = G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0) ;
769      break;
770    }
771    default:
772    {
773      DumpInfo();
774      G4Exception("G4Tubs::ApproxSurfaceNormal()", "Notification", JustWarning,
775                  "Undefined side for valid surface normal to solid.");
776      break ;
777    }   
778  }               
779  return norm;
780}
781
782////////////////////////////////////////////////////////////////////
783//
784//
785// Calculate distance to shape from outside, along normalised vector
786// - return kInfinity if no intersection, or intersection distance <= tolerance
787//
788// - Compute the intersection with the z planes
789//        - if at valid r, phi, return
790//
791// -> If point is outer outer radius, compute intersection with rmax
792//        - if at valid phi,z return
793//
794// -> Compute intersection with inner radius, taking largest +ve root
795//        - if valid (in z,phi), save intersction
796//
797//    -> If phi segmented, compute intersections with phi half planes
798//        - return smallest of valid phi intersections and
799//          inner radius intersection
800//
801// NOTE:
802// - 'if valid' implies tolerant checking of intersection points
803
804G4double G4Tubs::DistanceToIn( const G4ThreeVector& p,
805                               const G4ThreeVector& v  ) const
806{
807  G4double snxt = kInfinity ;      // snxt = default return value
808  G4double tolORMin2, tolIRMax2 ;  // 'generous' radii squared
809  G4double tolORMax2, tolIRMin2, tolODz, tolIDz ;
810
811  static const G4double halfCarTolerance = 0.5*kCarTolerance;
812  static const G4double halfRadTolerance = 0.5*kRadTolerance;
813
814  // Intersection point variables
815  //
816  G4double Dist, s, xi, yi, zi, rho2, inum, iden, cosPsi, Comp ;
817  G4double t1, t2, t3, b, c, d ;     // Quadratic solver variables
818 
819  // Calculate tolerant rmin and rmax
820
821  if (fRMin > kRadTolerance)
822  {
823    tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ;
824    tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ;
825  }
826  else
827  {
828    tolORMin2 = 0.0 ;
829    tolIRMin2 = 0.0 ;
830  }
831  tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ;
832  tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ;
833
834  // Intersection with Z surfaces
835
836  tolIDz = fDz - halfCarTolerance ;
837  tolODz = fDz + halfCarTolerance ;
838
839  if (std::fabs(p.z()) >= tolIDz)
840  {
841    if ( p.z()*v.z() < 0 )    // at +Z going in -Z or visa versa
842    {
843      s = (std::fabs(p.z()) - fDz)/std::fabs(v.z()) ;   // Z intersect distance
844
845      if(s < 0.0)  { s = 0.0; }
846
847      xi   = p.x() + s*v.x() ;                // Intersection coords
848      yi   = p.y() + s*v.y() ;
849      rho2 = xi*xi + yi*yi ;
850
851      // Check validity of intersection
852
853      if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
854      {
855        if (!fPhiFullTube && rho2)
856        {
857          // Psi = angle made with central (average) phi of shape
858          //
859          inum   = xi*cosCPhi + yi*sinCPhi ;
860          iden   = std::sqrt(rho2) ;
861          cosPsi = inum/iden ;
862          if (cosPsi >= cosHDPhiIT)  { return s ; }
863        }
864        else
865        {
866          return s ;
867        }
868      }
869    }
870    else
871    {
872      if ( snxt<halfCarTolerance )  { snxt=0; }
873      return snxt ;  // On/outside extent, and heading away
874                     // -> cannot intersect
875    }
876  }
877
878  // -> Can not intersect z surfaces
879  //
880  // Intersection with rmax (possible return) and rmin (must also check phi)
881  //
882  // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
883  //
884  // Intersects with x^2+y^2=R^2
885  //
886  // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
887  //            t1                t2                t3
888
889  t1 = 1.0 - v.z()*v.z() ;
890  t2 = p.x()*v.x() + p.y()*v.y() ;
891  t3 = p.x()*p.x() + p.y()*p.y() ;
892
893  if ( t1 > 0 )        // Check not || to z axis
894  {
895    b = t2/t1 ;
896    c = t3 - fRMax*fRMax ;
897    if ((t3 >= tolORMax2) && (t2<0))   // This also handles the tangent case
898    {
899      // Try outer cylinder intersection
900      //          c=(t3-fRMax*fRMax)/t1;
901
902      c /= t1 ;
903      d = b*b - c ;
904
905      if (d >= 0)  // If real root
906      {
907        s = -b - std::sqrt(d) ;
908        if (s >= 0)  // If 'forwards'
909        {
910          // Check z intersection
911          //
912          zi = p.z() + s*v.z() ;
913          if (std::fabs(zi)<=tolODz)
914          {
915            // Z ok. Check phi intersection if reqd
916            //
917            if (fPhiFullTube)
918            {
919              return s ;
920            }
921            else
922            {
923              xi     = p.x() + s*v.x() ;
924              yi     = p.y() + s*v.y() ;
925              cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ;
926              if (cosPsi >= cosHDPhiIT)  { return s ; }
927            }
928          }  //  end if std::fabs(zi)
929        }    //  end if (s>=0)
930      }      //  end if (d>=0)
931    }        //  end if (r>=fRMax)
932    else 
933    {
934      // Inside outer radius :
935      // check not inside, and heading through tubs (-> 0 to in)
936
937      if ((t3 > tolIRMin2) && (t2 < 0) && (std::fabs(p.z()) <= tolIDz))
938      {
939        // Inside both radii, delta r -ve, inside z extent
940
941        if (!fPhiFullTube)
942        {
943          inum   = p.x()*cosCPhi + p.y()*sinCPhi ;
944          iden   = std::sqrt(t3) ;
945          cosPsi = inum/iden ;
946          if (cosPsi >= cosHDPhiIT)
947          {
948            // In the old version, the small negative tangent for the point
949            // on surface was not taken in account, and returning 0.0 ...
950            // New version: check the tangent for the point on surface and
951            // if no intersection, return kInfinity, if intersection instead
952            // return s.
953            //
954            c = t3-fRMax*fRMax; 
955            if ( c<=0.0 )
956            {
957              return 0.0;
958            }
959            else
960            {
961              c = c/t1 ;
962              d = b*b-c;
963              if ( d>=0.0 )
964              {
965                snxt = c/(-b+std::sqrt(d)); // using safe solution
966                                            // for quadratic equation
967                if ( snxt < halfCarTolerance ) { snxt=0; }
968                return snxt ;
969              }     
970              else
971              {
972                return kInfinity;
973              }
974            }
975          } 
976        }
977        else
978        {   
979          // In the old version, the small negative tangent for the point
980          // on surface was not taken in account, and returning 0.0 ...
981          // New version: check the tangent for the point on surface and
982          // if no intersection, return kInfinity, if intersection instead
983          // return s.
984          //
985          c = t3 - fRMax*fRMax; 
986          if ( c<=0.0 )
987          {
988            return 0.0;
989          }
990          else
991          {
992            c = c/t1 ;
993            d = b*b-c;
994            if ( d>=0.0 )
995            {
996              snxt= c/(-b+std::sqrt(d)); // using safe solution
997                                         // for quadratic equation
998              if ( snxt < halfCarTolerance ) { snxt=0; }
999              return snxt ;
1000            }     
1001            else
1002            {
1003              return kInfinity;
1004            }
1005          }
1006        } // end if   (!fPhiFullTube)
1007      }   // end if   (t3>tolIRMin2)
1008    }     // end if   (Inside Outer Radius)
1009    if ( fRMin )    // Try inner cylinder intersection
1010    {
1011      c = (t3 - fRMin*fRMin)/t1 ;
1012      d = b*b - c ;
1013      if ( d >= 0.0 )  // If real root
1014      {
1015        // Always want 2nd root - we are outside and know rmax Hit was bad
1016        // - If on surface of rmin also need farthest root
1017
1018        s = -b + std::sqrt(d) ;
1019        if (s >= -halfCarTolerance)  // check forwards
1020        {
1021          // Check z intersection
1022          //
1023          if(s < 0.0)  { s = 0.0; }
1024          zi = p.z() + s*v.z() ;
1025          if (std::fabs(zi) <= tolODz)
1026          {
1027            // Z ok. Check phi
1028            //
1029            if ( fPhiFullTube )
1030            {
1031              return s ; 
1032            }
1033            else
1034            {
1035              xi     = p.x() + s*v.x() ;
1036              yi     = p.y() + s*v.y() ;
1037              cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ;
1038              if (cosPsi >= cosHDPhiIT)
1039              {
1040                // Good inner radius isect
1041                // - but earlier phi isect still possible
1042
1043                snxt = s ;
1044              }
1045            }
1046          }        //    end if std::fabs(zi)
1047        }          //    end if (s>=0)
1048      }            //    end if (d>=0)
1049    }              //    end if (fRMin)
1050  }
1051
1052  // Phi segment intersection
1053  //
1054  // o Tolerant of points inside phi planes by up to kCarTolerance*0.5
1055  //
1056  // o NOTE: Large duplication of code between sphi & ephi checks
1057  //         -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
1058  //            intersection check <=0 -> >=0
1059  //         -> use some form of loop Construct ?
1060  //
1061  if ( !fPhiFullTube )
1062  {
1063    // First phi surface (Starting phi)
1064    //
1065    Comp    = v.x()*sinSPhi - v.y()*cosSPhi ;
1066                   
1067    if ( Comp < 0 )  // Component in outwards normal dirn
1068    {
1069      Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ;
1070
1071      if ( Dist < halfCarTolerance )
1072      {
1073        s = Dist/Comp ;
1074
1075        if (s < snxt)
1076        {
1077          if ( s < 0 )  { s = 0.0; }
1078          zi = p.z() + s*v.z() ;
1079          if ( std::fabs(zi) <= tolODz )
1080          {
1081            xi   = p.x() + s*v.x() ;
1082            yi   = p.y() + s*v.y() ;
1083            rho2 = xi*xi + yi*yi ;
1084
1085            if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1086              || ( (rho2 >  tolORMin2) && (rho2 <  tolIRMin2)
1087                && ( v.y()*cosSPhi - v.x()*sinSPhi >  0 )
1088                && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 )     )
1089              || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1090                && (v.y()*cosSPhi - v.x()*sinSPhi > 0)
1091                && (v.x()*cosSPhi + v.y()*sinSPhi < 0) )    )
1092            {
1093              // z and r intersections good
1094              // - check intersecting with correct half-plane
1095              //
1096              if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = s; }
1097            }
1098          }
1099        }
1100      }   
1101    }
1102     
1103    // Second phi surface (Ending phi)
1104
1105    Comp    = -(v.x()*sinEPhi - v.y()*cosEPhi) ;
1106       
1107    if (Comp < 0 )  // Component in outwards normal dirn
1108    {
1109      Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ;
1110
1111      if ( Dist < halfCarTolerance )
1112      {
1113        s = Dist/Comp ;
1114
1115        if (s < snxt)
1116        {
1117          if ( s < 0 )  { s = 0; }
1118          zi = p.z() + s*v.z() ;
1119          if ( std::fabs(zi) <= tolODz )
1120          {
1121            xi   = p.x() + s*v.x() ;
1122            yi   = p.y() + s*v.y() ;
1123            rho2 = xi*xi + yi*yi ;
1124            if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1125                || ( (rho2 > tolORMin2)  && (rho2 < tolIRMin2)
1126                  && (v.x()*sinEPhi - v.y()*cosEPhi >  0)
1127                  && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) )
1128                || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1129                  && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1130                  && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) )
1131            {
1132              // z and r intersections good
1133              // - check intersecting with correct half-plane
1134              //
1135              if ( (yi*cosCPhi-xi*sinCPhi) >= 0 ) { snxt = s; }
1136            }                         //?? >=-halfCarTolerance
1137          }
1138        }
1139      }
1140    }         //  Comp < 0
1141  }           //  !fPhiFullTube
1142  if ( snxt<halfCarTolerance )  { snxt=0; }
1143  return snxt ;
1144}
1145 
1146//////////////////////////////////////////////////////////////////
1147//
1148// Calculate distance to shape from outside, along normalised vector
1149// - return kInfinity if no intersection, or intersection distance <= tolerance
1150//
1151// - Compute the intersection with the z planes
1152//        - if at valid r, phi, return
1153//
1154// -> If point is outer outer radius, compute intersection with rmax
1155//        - if at valid phi,z return
1156//
1157// -> Compute intersection with inner radius, taking largest +ve root
1158//        - if valid (in z,phi), save intersction
1159//
1160//    -> If phi segmented, compute intersections with phi half planes
1161//        - return smallest of valid phi intersections and
1162//          inner radius intersection
1163//
1164// NOTE:
1165// - Precalculations for phi trigonometry are Done `just in time'
1166// - `if valid' implies tolerant checking of intersection points
1167//   Calculate distance (<= actual) to closest surface of shape from outside
1168// - Calculate distance to z, radial planes
1169// - Only to phi planes if outside phi extent
1170// - Return 0 if point inside
1171
1172G4double G4Tubs::DistanceToIn( const G4ThreeVector& p ) const
1173{
1174  G4double safe=0.0, rho, safe1, safe2, safe3 ;
1175  G4double safePhi, cosPsi ;
1176
1177  rho   = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1178  safe1 = fRMin - rho ;
1179  safe2 = rho - fRMax ;
1180  safe3 = std::fabs(p.z()) - fDz ;
1181
1182  if ( safe1 > safe2 ) { safe = safe1; }
1183  else                 { safe = safe2; }
1184  if ( safe3 > safe )  { safe = safe3; }
1185
1186  if ( (!fPhiFullTube) && (rho) )
1187  {
1188    // Psi=angle from central phi to point
1189    //
1190    cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ;
1191   
1192    if ( cosPsi < std::cos(fDPhi*0.5) )
1193    {
1194      // Point lies outside phi range
1195
1196      if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 )
1197      {
1198        safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ;
1199      }
1200      else
1201      {
1202        safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ;
1203      }
1204      if ( safePhi > safe )  { safe = safePhi; }
1205    }
1206  }
1207  if ( safe < 0 )  { safe = 0; }
1208  return safe ;
1209}
1210
1211//////////////////////////////////////////////////////////////////////////////
1212//
1213// Calculate distance to surface of shape from `inside', allowing for tolerance
1214// - Only Calc rmax intersection if no valid rmin intersection
1215
1216G4double G4Tubs::DistanceToOut( const G4ThreeVector& p,
1217                                const G4ThreeVector& v,
1218                                const G4bool calcNorm,
1219                                      G4bool *validNorm,
1220                                      G4ThreeVector *n    ) const
1221{ 
1222  ESide side=kNull , sider=kNull, sidephi=kNull ;
1223  G4double snxt, sr=kInfinity, sphi=kInfinity, pdist ;
1224  G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ;
1225
1226  static const G4double halfCarTolerance = kCarTolerance*0.5;
1227  static const G4double halfAngTolerance = kAngTolerance*0.5;
1228 
1229  // Vars for phi intersection:
1230
1231  G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ;
1232 
1233  // Z plane intersection
1234
1235  if (v.z() > 0 )
1236  {
1237    pdist = fDz - p.z() ;
1238    if ( pdist > halfCarTolerance )
1239    {
1240      snxt = pdist/v.z() ;
1241      side = kPZ ;
1242    }
1243    else
1244    {
1245      if (calcNorm)
1246      {
1247        *n         = G4ThreeVector(0,0,1) ;
1248        *validNorm = true ;
1249      }
1250      return snxt = 0 ;
1251    }
1252  }
1253  else if ( v.z() < 0 )
1254  {
1255    pdist = fDz + p.z() ;
1256
1257    if ( pdist > halfCarTolerance )
1258    {
1259      snxt = -pdist/v.z() ;
1260      side = kMZ ;
1261    }
1262    else
1263    {
1264      if (calcNorm)
1265      {
1266        *n         = G4ThreeVector(0,0,-1) ;
1267        *validNorm = true ;
1268      }
1269      return snxt = 0.0 ;
1270    }
1271  }
1272  else
1273  {
1274    snxt = kInfinity ;    // Travel perpendicular to z axis
1275    side = kNull;
1276  }
1277
1278  // Radial Intersections
1279  //
1280  // Find intersection with cylinders at rmax/rmin
1281  // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1282  //
1283  // Intersects with x^2+y^2=R^2
1284  //
1285  // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
1286  //
1287  //            t1                t2                    t3
1288
1289  t1   = 1.0 - v.z()*v.z() ;      // since v normalised
1290  t2   = p.x()*v.x() + p.y()*v.y() ;
1291  t3   = p.x()*p.x() + p.y()*p.y() ;
1292
1293  if ( snxt > 10*(fDz+fRMax) )  { roi2 = 2*fRMax*fRMax; }
1294  else  { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; }        // radius^2 on +-fDz
1295
1296  if ( t1 > 0 ) // Check not parallel
1297  {
1298    // Calculate sr, r exit distance
1299     
1300    if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) )
1301    {
1302      // Delta r not negative => leaving via rmax
1303
1304      deltaR = t3 - fRMax*fRMax ;
1305
1306      // NOTE: Should use rho-fRMax<-kRadTolerance*0.5
1307      // - avoid sqrt for efficiency
1308
1309      if ( deltaR < -kRadTolerance*fRMax )
1310      {
1311        b     = t2/t1 ;
1312        c     = deltaR/t1 ;
1313        d2    = b*b-c;
1314        if( d2 >= 0 ) { sr = -b + std::sqrt(d2); }
1315        else          { sr = 0.; }
1316        sider = kRMax ;
1317      }
1318      else
1319      {
1320        // On tolerant boundary & heading outwards (or perpendicular to)
1321        // outer radial surface -> leaving immediately
1322
1323        if ( calcNorm ) 
1324        {
1325          *n         = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1326          *validNorm = true ;
1327        }
1328        return snxt = 0 ; // Leaving by rmax immediately
1329      }
1330    }             
1331    else if ( t2 < 0. ) // i.e.  t2 < 0; Possible rmin intersection
1332    {
1333      roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement
1334
1335      if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) )
1336      {
1337        deltaR = t3 - fRMin*fRMin ;
1338        b      = t2/t1 ;
1339        c      = deltaR/t1 ;
1340        d2     = b*b - c ;
1341
1342        if ( d2 >= 0 )   // Leaving via rmin
1343        {
1344          // NOTE: SHould use rho-rmin>kRadTolerance*0.5
1345          // - avoid sqrt for efficiency
1346
1347          if (deltaR > kRadTolerance*fRMin)
1348          {
1349            sr    = -b-std::sqrt(d2) ;
1350            sider = kRMin ;
1351          }
1352          else
1353          {
1354            if ( calcNorm ) { *validNorm = false; }  // Concave side
1355            return snxt = 0.0;
1356          }
1357        }
1358        else    // No rmin intersect -> must be rmax intersect
1359        {
1360          deltaR = t3 - fRMax*fRMax ;
1361          c     = deltaR/t1 ;
1362          d2    = b*b-c;
1363          if( d2 >=0. )
1364          {
1365            sr     = -b + std::sqrt(d2) ;
1366            sider  = kRMax ;
1367          }
1368          else // Case: On the border+t2<kRadTolerance
1369               //       (v is perpendicular to the surface)
1370          {
1371            if (calcNorm)
1372            {
1373              *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1374              *validNorm = true ;
1375            }
1376            return snxt = 0.0;
1377          }
1378        }
1379      }
1380      else if ( roi2 > fRMax*(fRMax + kRadTolerance) )
1381           // No rmin intersect -> must be rmax intersect
1382      {
1383        deltaR = t3 - fRMax*fRMax ;
1384        b      = t2/t1 ;
1385        c      = deltaR/t1;
1386        d2     = b*b-c;
1387        if( d2 >= 0 )
1388        {
1389          sr     = -b + std::sqrt(d2) ;
1390          sider  = kRMax ;
1391        }
1392        else // Case: On the border+t2<kRadTolerance
1393             //       (v is perpendicular to the surface)
1394        {
1395          if (calcNorm)
1396          {
1397            *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1398            *validNorm = true ;
1399          }
1400          return snxt = 0.0;
1401        }
1402      }
1403    }
1404   
1405    // Phi Intersection
1406
1407    if ( !fPhiFullTube )
1408    {
1409      // add angle calculation with correction
1410      // of the difference in domain of atan2 and Sphi
1411      //
1412      vphi = std::atan2(v.y(),v.x()) ;
1413     
1414      if ( vphi < fSPhi - halfAngTolerance  )             { vphi += twopi; }
1415      else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; }
1416
1417
1418      if ( p.x() || p.y() )  // Check if on z axis (rho not needed later)
1419      {
1420        // pDist -ve when inside
1421
1422        pDistS = p.x()*sinSPhi - p.y()*cosSPhi ;
1423        pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ;
1424
1425        // Comp -ve when in direction of outwards normal
1426
1427        compS   = -sinSPhi*v.x() + cosSPhi*v.y() ;
1428        compE   =  sinEPhi*v.x() - cosEPhi*v.y() ;
1429       
1430        sidephi = kNull;
1431       
1432        if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance)
1433                              && (pDistE <= halfCarTolerance) ) )
1434         || ( (fDPhi >  pi) && !((pDistS >  halfCarTolerance)
1435                              && (pDistE >  halfCarTolerance) ) )  )
1436        {
1437          // Inside both phi *full* planes
1438         
1439          if ( compS < 0 )
1440          {
1441            sphi = pDistS/compS ;
1442           
1443            if (sphi >= -halfCarTolerance)
1444            {
1445              xi = p.x() + sphi*v.x() ;
1446              yi = p.y() + sphi*v.y() ;
1447             
1448              // Check intersecting with correct half-plane
1449              // (if not -> no intersect)
1450              //
1451              if( (std::abs(xi)<=kCarTolerance)&&(std::abs(yi)<=kCarTolerance) )
1452              {
1453                sidephi = kSPhi;
1454                if (((fSPhi-halfAngTolerance)<=vphi)
1455                   &&((fSPhi+fDPhi+halfAngTolerance)>=vphi))
1456                {
1457                  sphi = kInfinity;
1458                }
1459              }
1460              else if ( yi*cosCPhi-xi*sinCPhi >=0 )
1461              {
1462                sphi = kInfinity ;
1463              }
1464              else
1465              {
1466                sidephi = kSPhi ;
1467                if ( pDistS > -halfCarTolerance )
1468                {
1469                  sphi = 0.0 ; // Leave by sphi immediately
1470                }   
1471              }       
1472            }
1473            else
1474            {
1475              sphi = kInfinity ;
1476            }
1477          }
1478          else
1479          {
1480            sphi = kInfinity ;
1481          }
1482
1483          if ( compE < 0 )
1484          {
1485            sphi2 = pDistE/compE ;
1486           
1487            // Only check further if < starting phi intersection
1488            //
1489            if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) )
1490            {
1491              xi = p.x() + sphi2*v.x() ;
1492              yi = p.y() + sphi2*v.y() ;
1493             
1494              if ((std::abs(xi)<=kCarTolerance)&&(std::abs(yi)<=kCarTolerance))
1495              {
1496                // Leaving via ending phi
1497                //
1498                if( !((fSPhi-halfAngTolerance <= vphi)
1499                     &&(fSPhi+fDPhi+halfAngTolerance >= vphi)) )
1500                {
1501                  sidephi = kEPhi ;
1502                  if ( pDistE <= -halfCarTolerance )  { sphi = sphi2 ; }
1503                  else                                { sphi = 0.0 ;   }
1504                }
1505              } 
1506              else    // Check intersecting with correct half-plane
1507
1508              if ( (yi*cosCPhi-xi*sinCPhi) >= 0)
1509              {
1510                // Leaving via ending phi
1511                //
1512                sidephi = kEPhi ;
1513                if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; }
1514                else                               { sphi = 0.0 ;   }
1515              }
1516            }
1517          }
1518        }
1519        else
1520        {
1521          sphi = kInfinity ;
1522        }
1523      }
1524      else
1525      {
1526        // On z axis + travel not || to z axis -> if phi of vector direction
1527        // within phi of shape, Step limited by rmax, else Step =0
1528               
1529        if ( (fSPhi - halfAngTolerance <= vphi)
1530           && (vphi <= fSPhi + fDPhi + halfAngTolerance ) )
1531        {
1532          sphi = kInfinity ;
1533        }
1534        else
1535        {
1536          sidephi = kSPhi ; // arbitrary
1537          sphi    = 0.0 ;
1538        }
1539      }
1540      if (sphi < snxt)  // Order intersecttions
1541      {
1542        snxt = sphi ;
1543        side = sidephi ;
1544      }
1545    }
1546    if (sr < snxt)  // Order intersections
1547    {
1548      snxt = sr ;
1549      side = sider ;
1550    }
1551  }
1552  if (calcNorm)
1553  {
1554    switch(side)
1555    {
1556      case kRMax:
1557        // Note: returned vector not normalised
1558        // (divide by fRMax for unit vector)
1559        //
1560        xi = p.x() + snxt*v.x() ;
1561        yi = p.y() + snxt*v.y() ;
1562        *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ;
1563        *validNorm = true ;
1564        break ;
1565
1566      case kRMin:
1567        *validNorm = false ;  // Rmin is inconvex
1568        break ;
1569
1570      case kSPhi:
1571        if ( fDPhi <= pi )
1572        {
1573          *n         = G4ThreeVector(sinSPhi,-cosSPhi,0) ;
1574          *validNorm = true ;
1575        }
1576        else
1577        {
1578          *validNorm = false ;
1579        }
1580        break ;
1581
1582      case kEPhi:
1583        if (fDPhi <= pi)
1584        {
1585          *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ;
1586          *validNorm = true ;
1587        }
1588        else
1589        {
1590          *validNorm = false ;
1591        }
1592        break ;
1593
1594      case kPZ:
1595        *n         = G4ThreeVector(0,0,1) ;
1596        *validNorm = true ;
1597        break ;
1598
1599      case kMZ:
1600        *n         = G4ThreeVector(0,0,-1) ;
1601        *validNorm = true ;
1602        break ;
1603
1604      default:
1605        G4cout.precision(16) ;
1606        G4cout << G4endl ;
1607        DumpInfo();
1608        G4cout << "Position:"  << G4endl << G4endl ;
1609        G4cout << "p.x() = "   << p.x()/mm << " mm" << G4endl ;
1610        G4cout << "p.y() = "   << p.y()/mm << " mm" << G4endl ;
1611        G4cout << "p.z() = "   << p.z()/mm << " mm" << G4endl << G4endl ;
1612        G4cout << "Direction:" << G4endl << G4endl ;
1613        G4cout << "v.x() = "   << v.x() << G4endl ;
1614        G4cout << "v.y() = "   << v.y() << G4endl ;
1615        G4cout << "v.z() = "   << v.z() << G4endl << G4endl ;
1616        G4cout << "Proposed distance :" << G4endl << G4endl ;
1617        G4cout << "snxt = "    << snxt/mm << " mm" << G4endl << G4endl ;
1618        G4Exception("G4Tubs::DistanceToOut(p,v,..)","Notification",JustWarning,
1619                    "Undefined side for valid surface normal to solid.");
1620        break ;
1621    }
1622  }
1623  if ( snxt<halfCarTolerance )  { snxt=0 ; }
1624
1625  return snxt ;
1626}
1627
1628//////////////////////////////////////////////////////////////////////////
1629//
1630// Calculate distance (<=actual) to closest surface of shape from inside
1631
1632G4double G4Tubs::DistanceToOut( const G4ThreeVector& p ) const
1633{
1634  G4double safe=0.0, rho, safeR1, safeR2, safeZ, safePhi ;
1635  rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1636
1637#ifdef G4CSGDEBUG
1638  if( Inside(p) == kOutside )
1639  {
1640    G4cout.precision(16) ;
1641    G4cout << G4endl ;
1642    DumpInfo();
1643    G4cout << "Position:"  << G4endl << G4endl ;
1644    G4cout << "p.x() = "   << p.x()/mm << " mm" << G4endl ;
1645    G4cout << "p.y() = "   << p.y()/mm << " mm" << G4endl ;
1646    G4cout << "p.z() = "   << p.z()/mm << " mm" << G4endl << G4endl ;
1647    G4Exception("G4Tubs::DistanceToOut(p)", "Notification", JustWarning, 
1648                 "Point p is outside !?");
1649  }
1650#endif
1651
1652  if ( fRMin )
1653  {
1654    safeR1 = rho   - fRMin ;
1655    safeR2 = fRMax - rho ;
1656 
1657    if ( safeR1 < safeR2 ) { safe = safeR1 ; }
1658    else                   { safe = safeR2 ; }
1659  }
1660  else
1661  {
1662    safe = fRMax - rho ;
1663  }
1664  safeZ = fDz - std::fabs(p.z()) ;
1665
1666  if ( safeZ < safe )  { safe = safeZ ; }
1667
1668  // Check if phi divided, Calc distances closest phi plane
1669  //
1670  if ( !fPhiFullTube )
1671  {
1672    if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 )
1673    {
1674      safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ;
1675    }
1676    else
1677    {
1678      safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ;
1679    }
1680    if (safePhi < safe)  { safe = safePhi ; }
1681  }
1682  if ( safe < 0 )  { safe = 0 ; }
1683
1684  return safe ; 
1685}
1686
1687/////////////////////////////////////////////////////////////////////////
1688//
1689// Create a List containing the transformed vertices
1690// Ordering [0-3] -fDz cross section
1691//          [4-7] +fDz cross section such that [0] is below [4],
1692//                                             [1] below [5] etc.
1693// Note:
1694//  Caller has deletion resposibility
1695//  Potential improvement: For last slice, use actual ending angle
1696//                         to avoid rounding error problems.
1697
1698G4ThreeVectorList*
1699G4Tubs::CreateRotatedVertices( const G4AffineTransform& pTransform ) const
1700{
1701  G4ThreeVectorList* vertices ;
1702  G4ThreeVector vertex0, vertex1, vertex2, vertex3 ;
1703  G4double meshAngle, meshRMax, crossAngle,
1704           cosCrossAngle, sinCrossAngle, sAngle;
1705  G4double rMaxX, rMaxY, rMinX, rMinY, meshRMin ;
1706  G4int crossSection, noCrossSections;
1707
1708  // Compute no of cross-sections necessary to mesh tube
1709  //
1710  noCrossSections = G4int(fDPhi/kMeshAngleDefault) + 1 ;
1711
1712  if ( noCrossSections < kMinMeshSections )
1713  {
1714    noCrossSections = kMinMeshSections ;
1715  }
1716  else if (noCrossSections>kMaxMeshSections)
1717  {
1718    noCrossSections = kMaxMeshSections ;
1719  }
1720  // noCrossSections = 4 ;
1721
1722  meshAngle = fDPhi/(noCrossSections - 1) ;
1723  // meshAngle = fDPhi/(noCrossSections) ;
1724
1725  meshRMax  = (fRMax+100*kCarTolerance)/std::cos(meshAngle*0.5) ;
1726  meshRMin = fRMin - 100*kCarTolerance ; 
1727 
1728  // If complete in phi, set start angle such that mesh will be at fRMax
1729  // on the x axis. Will give better extent calculations when not rotated.
1730
1731  if (fPhiFullTube && (fSPhi == 0) )  { sAngle = -meshAngle*0.5 ; }
1732  else                                { sAngle =  fSPhi ; }
1733   
1734  vertices = new G4ThreeVectorList();
1735  vertices->reserve(noCrossSections*4);
1736   
1737  if ( vertices )
1738  {
1739    for (crossSection = 0 ; crossSection < noCrossSections ; crossSection++ )
1740    {
1741      // Compute coordinates of cross section at section crossSection
1742
1743      crossAngle    = sAngle + crossSection*meshAngle ;
1744      cosCrossAngle = std::cos(crossAngle) ;
1745      sinCrossAngle = std::sin(crossAngle) ;
1746
1747      rMaxX = meshRMax*cosCrossAngle ;
1748      rMaxY = meshRMax*sinCrossAngle ;
1749
1750      if(meshRMin <= 0.0)
1751      {
1752        rMinX = 0.0 ;
1753        rMinY = 0.0 ;
1754      }
1755      else
1756      {
1757        rMinX = meshRMin*cosCrossAngle ;
1758        rMinY = meshRMin*sinCrossAngle ;
1759      }
1760      vertex0 = G4ThreeVector(rMinX,rMinY,-fDz) ;
1761      vertex1 = G4ThreeVector(rMaxX,rMaxY,-fDz) ;
1762      vertex2 = G4ThreeVector(rMaxX,rMaxY,+fDz) ;
1763      vertex3 = G4ThreeVector(rMinX,rMinY,+fDz) ;
1764
1765      vertices->push_back(pTransform.TransformPoint(vertex0)) ;
1766      vertices->push_back(pTransform.TransformPoint(vertex1)) ;
1767      vertices->push_back(pTransform.TransformPoint(vertex2)) ;
1768      vertices->push_back(pTransform.TransformPoint(vertex3)) ;
1769    }
1770  }
1771  else
1772  {
1773    DumpInfo();
1774    G4Exception("G4Tubs::CreateRotatedVertices()",
1775                "FatalError", FatalException,
1776                "Error in allocation of vertices. Out of memory !");
1777  }
1778  return vertices ;
1779}
1780
1781//////////////////////////////////////////////////////////////////////////
1782//
1783// Stream object contents to an output stream
1784
1785G4GeometryType G4Tubs::GetEntityType() const
1786{
1787  return G4String("G4Tubs");
1788}
1789
1790//////////////////////////////////////////////////////////////////////////
1791//
1792// Stream object contents to an output stream
1793
1794std::ostream& G4Tubs::StreamInfo( std::ostream& os ) const
1795{
1796  os << "-----------------------------------------------------------\n"
1797     << "    *** Dump for solid - " << GetName() << " ***\n"
1798     << "    ===================================================\n"
1799     << " Solid type: G4Tubs\n"
1800     << " Parameters: \n"
1801     << "    inner radius : " << fRMin/mm << " mm \n"
1802     << "    outer radius : " << fRMax/mm << " mm \n"
1803     << "    half length Z: " << fDz/mm << " mm \n"
1804     << "    starting phi : " << fSPhi/degree << " degrees \n"
1805     << "    delta phi    : " << fDPhi/degree << " degrees \n"
1806     << "-----------------------------------------------------------\n";
1807
1808  return os;
1809}
1810
1811/////////////////////////////////////////////////////////////////////////
1812//
1813// GetPointOnSurface
1814
1815G4ThreeVector G4Tubs::GetPointOnSurface() const
1816{
1817  G4double xRand, yRand, zRand, phi, cosphi, sinphi, chose,
1818           aOne, aTwo, aThr, aFou;
1819  G4double rRand;
1820
1821  aOne = 2.*fDz*fDPhi*fRMax;
1822  aTwo = 2.*fDz*fDPhi*fRMin;
1823  aThr = 0.5*fDPhi*(fRMax*fRMax-fRMin*fRMin);
1824  aFou = 2.*fDz*(fRMax-fRMin);
1825
1826  phi    = RandFlat::shoot(fSPhi, fSPhi+fDPhi);
1827  cosphi = std::cos(phi);
1828  sinphi = std::sin(phi);
1829
1830  rRand  = RandFlat::shoot(fRMin,fRMax);
1831 
1832  if( (fSPhi == 0) && (fDPhi == twopi) ) { aFou = 0; }
1833 
1834  chose  = RandFlat::shoot(0.,aOne+aTwo+2.*aThr+2.*aFou);
1835
1836  if( (chose >=0) && (chose < aOne) )
1837  {
1838    xRand = fRMax*cosphi;
1839    yRand = fRMax*sinphi;
1840    zRand = RandFlat::shoot(-1.*fDz,fDz);
1841    return G4ThreeVector  (xRand, yRand, zRand);
1842  }
1843  else if( (chose >= aOne) && (chose < aOne + aTwo) )
1844  {
1845    xRand = fRMin*cosphi;
1846    yRand = fRMin*sinphi;
1847    zRand = RandFlat::shoot(-1.*fDz,fDz);
1848    return G4ThreeVector  (xRand, yRand, zRand);
1849  }
1850  else if( (chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr) )
1851  {
1852    xRand = rRand*cosphi;
1853    yRand = rRand*sinphi;
1854    zRand = fDz;
1855    return G4ThreeVector  (xRand, yRand, zRand);
1856  }
1857  else if( (chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + 2.*aThr) )
1858  {
1859    xRand = rRand*cosphi;
1860    yRand = rRand*sinphi;
1861    zRand = -1.*fDz;
1862    return G4ThreeVector  (xRand, yRand, zRand);
1863  }
1864  else if( (chose >= aOne + aTwo + 2.*aThr)
1865        && (chose < aOne + aTwo + 2.*aThr + aFou) )
1866  {
1867    xRand = rRand*std::cos(fSPhi);
1868    yRand = rRand*std::sin(fSPhi);
1869    zRand = RandFlat::shoot(-1.*fDz,fDz);
1870    return G4ThreeVector  (xRand, yRand, zRand);
1871  }
1872  else
1873  {
1874    xRand = rRand*std::cos(fSPhi+fDPhi);
1875    yRand = rRand*std::sin(fSPhi+fDPhi);
1876    zRand = RandFlat::shoot(-1.*fDz,fDz);
1877    return G4ThreeVector  (xRand, yRand, zRand);
1878  }
1879}
1880
1881///////////////////////////////////////////////////////////////////////////
1882//
1883// Methods for visualisation
1884
1885void G4Tubs::DescribeYourselfTo ( G4VGraphicsScene& scene ) const 
1886{
1887  scene.AddSolid (*this) ;
1888}
1889
1890G4Polyhedron* G4Tubs::CreatePolyhedron () const 
1891{
1892  return new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi) ;
1893}
1894
1895G4NURBS* G4Tubs::CreateNURBS () const 
1896{
1897  G4NURBS* pNURBS ;
1898  if (fRMin != 0) 
1899  {
1900    if (fPhiFullTube) 
1901    {
1902      pNURBS = new G4NURBStube (fRMin,fRMax,fDz) ;
1903    }
1904    else 
1905    {
1906      pNURBS = new G4NURBStubesector (fRMin,fRMax,fDz,fSPhi,fSPhi+fDPhi) ;
1907    }
1908  }
1909  else 
1910  {
1911    if (fPhiFullTube) 
1912    {
1913      pNURBS = new G4NURBScylinder (fRMax,fDz) ;
1914    }
1915    else 
1916    {
1917      const G4double epsilon = 1.e-4 ; // Cylinder sector not yet available!
1918      pNURBS = new G4NURBStubesector (epsilon,fRMax,fDz,fSPhi,fSPhi+fDPhi) ;
1919    }
1920  }
1921  return pNURBS ;
1922}
Note: See TracBrowser for help on using the repository browser.