Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4Orb.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // $Id: G4Orb.cc 69788 2013-05-15 12:06:57Z gcosmo $
27 //
28 // class G4Orb
29 //
30 // Implementation for G4Orb class
31 //
32 // History:
33 //
34 // 05.04.12 M.Kelsey - GetPointOnSurface() throw flat in cos(theta)
35 // 30.06.04 V.Grichine - bug fixed in DistanceToIn(p,v) on Rmax surface
36 // 20.08.03 V.Grichine - created
37 //
39 
40 #include <assert.h>
41 
42 #include "G4Orb.hh"
43 
44 #include "G4VoxelLimits.hh"
45 #include "G4AffineTransform.hh"
46 #include "G4GeometryTolerance.hh"
47 
48 #include "G4VPVParameterisation.hh"
49 
50 #include "Randomize.hh"
51 
52 #include "meshdefs.hh"
53 
54 #include "G4VGraphicsScene.hh"
55 #include "G4Polyhedron.hh"
56 #include "G4NURBS.hh"
57 #include "G4NURBSbox.hh"
58 
59 using namespace CLHEP;
60 
61 // Private enum: Not for external use - used by distanceToOut
62 
63 enum ESide {kNull,kRMax};
64 
65 // used by normal
66 
67 enum ENorm {kNRMax};
68 
69 
71 //
72 // constructor - check positive radius
73 //
74 
75 G4Orb::G4Orb( const G4String& pName, G4double pRmax )
76 : G4CSGSolid(pName), fRmax(pRmax)
77 {
78 
79  const G4double fEpsilon = 2.e-11; // relative tolerance of fRmax
80 
81  G4double kRadTolerance
83 
84  // Check radius
85  //
86  if ( pRmax < 10*kCarTolerance )
87  {
88  G4Exception("G4Orb::G4Orb()", "GeomSolids0002", FatalException,
89  "Invalid radius > 10*kCarTolerance.");
90  }
91  fRmaxTolerance = std::max( kRadTolerance, fEpsilon*fRmax);
92 
93 }
94 
96 //
97 // Fake default constructor - sets only member data and allocates memory
98 // for usage restricted to object persistency.
99 //
100 G4Orb::G4Orb( __void__& a )
101  : G4CSGSolid(a), fRmax(0.), fRmaxTolerance(0.)
102 {
103 }
104 
106 //
107 // Destructor
108 
110 {
111 }
112 
114 //
115 // Copy constructor
116 
117 G4Orb::G4Orb(const G4Orb& rhs)
118  : G4CSGSolid(rhs), fRmax(rhs.fRmax), fRmaxTolerance(rhs.fRmaxTolerance)
119 {
120 }
121 
123 //
124 // Assignment operator
125 
127 {
128  // Check assignment to self
129  //
130  if (this == &rhs) { return *this; }
131 
132  // Copy base class data
133  //
135 
136  // Copy data
137  //
138  fRmax = rhs.fRmax;
139  fRmaxTolerance = rhs.fRmaxTolerance;
140 
141  return *this;
142 }
143 
145 //
146 // Dispatch to parameterisation for replication mechanism dimension
147 // computation & modification.
148 
150  const G4int n,
151  const G4VPhysicalVolume* pRep )
152 {
153  p->ComputeDimensions(*this,n,pRep);
154 }
155 
157 //
158 // Calculate extent under transform and specified limit
159 
161  const G4VoxelLimits& pVoxelLimit,
162  const G4AffineTransform& pTransform,
163  G4double& pMin, G4double& pMax ) const
164 {
165  // Compute x/y/z mins and maxs for bounding box respecting limits,
166  // with early returns if outside limits. Then switch() on pAxis,
167  // and compute exact x and y limit for x/y case
168 
169  G4double xoffset,xMin,xMax;
170  G4double yoffset,yMin,yMax;
171  G4double zoffset,zMin,zMax;
172 
173  G4double diff1,diff2,delta,maxDiff,newMin,newMax;
174  G4double xoff1,xoff2,yoff1,yoff2;
175 
176  xoffset=pTransform.NetTranslation().x();
177  xMin=xoffset-fRmax;
178  xMax=xoffset+fRmax;
179 
180  if (pVoxelLimit.IsXLimited())
181  {
182  if ( (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance)
183  || (xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance) )
184  {
185  return false;
186  }
187  else
188  {
189  if (xMin<pVoxelLimit.GetMinXExtent())
190  {
191  xMin=pVoxelLimit.GetMinXExtent();
192  }
193  if (xMax>pVoxelLimit.GetMaxXExtent())
194  {
195  xMax=pVoxelLimit.GetMaxXExtent();
196  }
197  }
198  }
199  yoffset=pTransform.NetTranslation().y();
200  yMin=yoffset-fRmax;
201  yMax=yoffset+fRmax;
202 
203  if (pVoxelLimit.IsYLimited())
204  {
205  if ( (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance)
206  || (yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance) )
207  {
208  return false;
209  }
210  else
211  {
212  if (yMin<pVoxelLimit.GetMinYExtent())
213  {
214  yMin=pVoxelLimit.GetMinYExtent();
215  }
216  if (yMax>pVoxelLimit.GetMaxYExtent())
217  {
218  yMax=pVoxelLimit.GetMaxYExtent();
219  }
220  }
221  }
222  zoffset=pTransform.NetTranslation().z();
223  zMin=zoffset-fRmax;
224  zMax=zoffset+fRmax;
225 
226  if (pVoxelLimit.IsZLimited())
227  {
228  if ( (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance)
229  || (zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance) )
230  {
231  return false;
232  }
233  else
234  {
235  if (zMin<pVoxelLimit.GetMinZExtent())
236  {
237  zMin=pVoxelLimit.GetMinZExtent();
238  }
239  if (zMax>pVoxelLimit.GetMaxZExtent())
240  {
241  zMax=pVoxelLimit.GetMaxZExtent();
242  }
243  }
244  }
245 
246  // Known to cut sphere
247 
248  switch (pAxis)
249  {
250  case kXAxis:
251  yoff1=yoffset-yMin;
252  yoff2=yMax-yoffset;
253 
254  if ( yoff1 >= 0 && yoff2 >= 0 )
255  {
256  // Y limits cross max/min x => no change
257  //
258  pMin=xMin;
259  pMax=xMax;
260  }
261  else
262  {
263  // Y limits don't cross max/min x => compute max delta x,
264  // hence new mins/maxs
265  //
266  delta=fRmax*fRmax-yoff1*yoff1;
267  diff1=(delta>0.) ? std::sqrt(delta) : 0.;
268  delta=fRmax*fRmax-yoff2*yoff2;
269  diff2=(delta>0.) ? std::sqrt(delta) : 0.;
270  maxDiff=(diff1>diff2) ? diff1:diff2;
271  newMin=xoffset-maxDiff;
272  newMax=xoffset+maxDiff;
273  pMin=(newMin<xMin) ? xMin : newMin;
274  pMax=(newMax>xMax) ? xMax : newMax;
275  }
276  break;
277  case kYAxis:
278  xoff1=xoffset-xMin;
279  xoff2=xMax-xoffset;
280  if (xoff1>=0&&xoff2>=0)
281  {
282  // X limits cross max/min y => no change
283  //
284  pMin=yMin;
285  pMax=yMax;
286  }
287  else
288  {
289  // X limits don't cross max/min y => compute max delta y,
290  // hence new mins/maxs
291  //
292  delta=fRmax*fRmax-xoff1*xoff1;
293  diff1=(delta>0.) ? std::sqrt(delta) : 0.;
294  delta=fRmax*fRmax-xoff2*xoff2;
295  diff2=(delta>0.) ? std::sqrt(delta) : 0.;
296  maxDiff=(diff1>diff2) ? diff1:diff2;
297  newMin=yoffset-maxDiff;
298  newMax=yoffset+maxDiff;
299  pMin=(newMin<yMin) ? yMin : newMin;
300  pMax=(newMax>yMax) ? yMax : newMax;
301  }
302  break;
303  case kZAxis:
304  pMin=zMin;
305  pMax=zMax;
306  break;
307  default:
308  break;
309  }
310  pMin -= fRmaxTolerance;
311  pMax += fRmaxTolerance;
312 
313  return true;
314 
315 }
316 
318 //
319 // Return whether point inside/outside/on surface
320 // Split into radius checks
321 //
322 
324 {
325  G4double rad2,tolRMax;
326  EInside in;
327 
328 
329  rad2 = p.x()*p.x()+p.y()*p.y()+p.z()*p.z();
330 
331  G4double radius = std::sqrt(rad2);
332 
333  // G4double radius = std::sqrt(rad2);
334  // Check radial surface
335  // sets `in'
336 
337  tolRMax = fRmax - fRmaxTolerance*0.5;
338 
339  if ( radius <= tolRMax ) { in = kInside; }
340  else
341  {
342  tolRMax = fRmax + fRmaxTolerance*0.5;
343  if ( radius <= tolRMax ) { in = kSurface; }
344  else { in = kOutside; }
345  }
346  return in;
347 }
348 
350 //
351 // Return unit normal of surface closest to p
352 // - note if point on z axis, ignore phi divided sides
353 // - unsafe if point close to z axis a rmin=0 - no explicit checks
354 
356 {
357  ENorm side = kNRMax;
359  G4double radius = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
360 
361  switch (side)
362  {
363  case kNRMax:
364  norm = G4ThreeVector(p.x()/radius,p.y()/radius,p.z()/radius);
365  break;
366  default: // Should never reach this case ...
367  DumpInfo();
368  G4Exception("G4Orb::SurfaceNormal()", "GeomSolids1002", JustWarning,
369  "Undefined side for valid surface normal to solid.");
370  break;
371  }
372 
373  return norm;
374 }
375 
377 //
378 // Calculate distance to shape from outside, along normalised vector
379 // - return kInfinity if no intersection, or intersection distance <= tolerance
380 //
381 // -> If point is outside outer radius, compute intersection with rmax
382 // - if no intersection return
383 // - if valid phi,theta return intersection Dist
384 
386  const G4ThreeVector& v ) const
387 {
388  G4double snxt = kInfinity; // snxt = default return value
389 
390  G4double radius, pDotV3d; // , tolORMax2, tolIRMax2;
391  G4double c, d2, sd = kInfinity;
392 
393  const G4double dRmax = 100.*fRmax;
394 
395  // General Precalcs
396 
397  radius = std::sqrt(p.x()*p.x() + p.y()*p.y() + p.z()*p.z());
398  pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z();
399 
400  // Radial Precalcs
401 
402  // tolORMax2 = (fRmax+fRmaxTolerance*0.5)*(fRmax+fRmaxTolerance*0.5);
403  // tolIRMax2 = (fRmax-fRmaxTolerance*0.5)*(fRmax-fRmaxTolerance*0.5);
404 
405  // Outer spherical shell intersection
406  // - Only if outside tolerant fRmax
407  // - Check for if inside and outer G4Orb heading through solid (-> 0)
408  // - No intersect -> no intersection with G4Orb
409  //
410  // Shell eqn: x^2+y^2+z^2 = RSPH^2
411  //
412  // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
413  //
414  // => (px^2+py^2+pz^2) +2sd(pxvx+pyvy+pzvz)+sd^2(vx^2+vy^2+vz^2)=R^2
415  // => rad2 +2sd(pDotV3d) +sd^2 =R^2
416  //
417  // => sd=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
418 
419  c = (radius - fRmax)*(radius + fRmax);
420 
421  if( radius > fRmax-fRmaxTolerance*0.5 ) // not inside in terms of Inside(p)
422  {
423  if ( c > fRmaxTolerance*fRmax )
424  {
425  // If outside tolerant boundary of outer G4Orb in terms of c
426  // [ should be std::sqrt(rad2) - fRmax > fRmaxTolerance*0.5 ]
427 
428  d2 = pDotV3d*pDotV3d - c;
429 
430  if ( d2 >= 0 )
431  {
432  sd = -pDotV3d - std::sqrt(d2);
433  if ( sd >= 0 )
434  {
435  if ( sd > dRmax ) // Avoid rounding errors due to precision issues seen on
436  { // 64 bits systems. Split long distances and recompute
437  G4double fTerm = sd - std::fmod(sd,dRmax);
438  sd = fTerm + DistanceToIn(p+fTerm*v,v);
439  }
440  return snxt = sd;
441  }
442  }
443  else // No intersection with G4Orb
444  {
445  return snxt = kInfinity;
446  }
447  }
448  else // not outside in terms of c
449  {
450  if ( c > -fRmaxTolerance*fRmax ) // on surface
451  {
452  d2 = pDotV3d*pDotV3d - c;
453  if ( (d2 < fRmaxTolerance*fRmax) || (pDotV3d >= 0) )
454  {
455  return snxt = kInfinity;
456  }
457  else
458  {
459  return snxt = 0.;
460  }
461  }
462  }
463  }
464 #ifdef G4CSGDEBUG
465  else // inside ???
466  {
467  G4Exception("G4Orb::DistanceToIn(p,v)", "GeomSolids1002",
468  JustWarning, "Point p is inside !?");
469  }
470 #endif
471 
472  return snxt;
473 }
474 
476 //
477 // Calculate distance (<= actual) to closest surface of shape from outside
478 // - Calculate distance to radial plane
479 // - Return 0 if point inside
480 
482 {
483  G4double safe = 0.0,
484  radius = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
485  safe = radius - fRmax;
486  if( safe < 0 ) { safe = 0.; }
487  return safe;
488 }
489 
491 //
492 // Calculate distance to surface of shape from `inside', allowing for tolerance
493 //
494 
496  const G4ThreeVector& v,
497  const G4bool calcNorm,
498  G4bool *validNorm,
499  G4ThreeVector *n ) const
500 {
501  G4double snxt = kInfinity; // ??? snxt is default return value
502  ESide side = kNull;
503 
504  G4double rad2,pDotV3d;
505  G4double xi,yi,zi; // Intersection point
506  G4double c,d2;
507 
508  rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z();
509  pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z();
510 
511  // Radial Intersection from G4Orb::DistanceToIn
512  //
513  // Outer spherical shell intersection
514  // - Only if outside tolerant fRmax
515  // - Check for if inside and outer G4Orb heading through solid (-> 0)
516  // - No intersect -> no intersection with G4Orb
517  //
518  // Shell eqn: x^2+y^2+z^2=RSPH^2
519  //
520  // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
521  //
522  // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
523  // => rad2 +2s(pDotV3d) +s^2 =R^2
524  //
525  // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
526 
527  const G4double Rmax_plus = fRmax + fRmaxTolerance*0.5;
528  G4double radius = std::sqrt(rad2);
529 
530  if ( radius <= Rmax_plus )
531  {
532  c = (radius - fRmax)*(radius + fRmax);
533 
534  if ( c < fRmaxTolerance*fRmax )
535  {
536  // Within tolerant Outer radius
537  //
538  // The test is
539  // radius - fRmax < 0.5*fRmaxTolerance
540  // => radius < fRmax + 0.5*kRadTol
541  // => rad2 < (fRmax + 0.5*kRadTol)^2
542  // => rad2 < fRmax^2 + 2.*0.5*fRmax*kRadTol + 0.25*kRadTol*kRadTol
543  // => rad2 - fRmax^2 <~ fRmax*kRadTol
544 
545  d2 = pDotV3d*pDotV3d - c;
546 
547  if( ( c > -fRmaxTolerance*fRmax) && // on tolerant surface
548  ( ( pDotV3d >= 0 ) || ( d2 < 0 )) ) // leaving outside from Rmax
549  // not re-entering
550  {
551  if(calcNorm)
552  {
553  *validNorm = true;
554  *n = G4ThreeVector(p.x()/fRmax,p.y()/fRmax,p.z()/fRmax);
555  }
556  return snxt = 0;
557  }
558  else
559  {
560  snxt = -pDotV3d + std::sqrt(d2); // second root since inside Rmax
561  side = kRMax;
562  }
563  }
564  }
565  else // p is outside ???
566  {
567  G4cout << G4endl;
568  DumpInfo();
569  std::ostringstream message;
570  G4int oldprc = message.precision(16);
571  message << "Logic error: snxt = kInfinity ???" << G4endl
572  << "Position:" << G4endl << G4endl
573  << "p.x() = " << p.x()/mm << " mm" << G4endl
574  << "p.y() = " << p.y()/mm << " mm" << G4endl
575  << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl
576  << "Rp = "<< std::sqrt( p.x()*p.x()+p.y()*p.y()+p.z()*p.z() )/mm
577  << " mm" << G4endl << G4endl
578  << "Direction:" << G4endl << G4endl
579  << "v.x() = " << v.x() << G4endl
580  << "v.y() = " << v.y() << G4endl
581  << "v.z() = " << v.z() << G4endl << G4endl
582  << "Proposed distance :" << G4endl << G4endl
583  << "snxt = " << snxt/mm << " mm" << G4endl;
584  message.precision(oldprc);
585  G4Exception("G4Orb::DistanceToOut(p,v,..)", "GeomSolids1002",
586  JustWarning, message);
587  }
588  if (calcNorm) // Output switch operator
589  {
590  switch( side )
591  {
592  case kRMax:
593  xi=p.x()+snxt*v.x();
594  yi=p.y()+snxt*v.y();
595  zi=p.z()+snxt*v.z();
596  *n=G4ThreeVector(xi/fRmax,yi/fRmax,zi/fRmax);
597  *validNorm=true;
598  break;
599  default:
600  G4cout << G4endl;
601  DumpInfo();
602  std::ostringstream message;
603  G4int oldprc = message.precision(16);
604  message << "Undefined side for valid surface normal to solid."
605  << G4endl
606  << "Position:" << G4endl << G4endl
607  << "p.x() = " << p.x()/mm << " mm" << G4endl
608  << "p.y() = " << p.y()/mm << " mm" << G4endl
609  << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl
610  << "Direction:" << G4endl << G4endl
611  << "v.x() = " << v.x() << G4endl
612  << "v.y() = " << v.y() << G4endl
613  << "v.z() = " << v.z() << G4endl << G4endl
614  << "Proposed distance :" << G4endl << G4endl
615  << "snxt = " << snxt/mm << " mm" << G4endl;
616  message.precision(oldprc);
617  G4Exception("G4Orb::DistanceToOut(p,v,..)","GeomSolids1002",
618  JustWarning, message);
619  break;
620  }
621  }
622  return snxt;
623 }
624 
626 //
627 // Calculate distance (<=actual) to closest surface of shape from inside
628 
630 {
631  G4double safe=0.0,radius = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
632 
633 #ifdef G4CSGDEBUG
634  if( Inside(p) == kOutside )
635  {
636  G4int oldprc = G4cout.precision(16);
637  G4cout << G4endl;
638  DumpInfo();
639  G4cout << "Position:" << G4endl << G4endl;
640  G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
641  G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
642  G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
643  G4cout.precision(oldprc);
644  G4Exception("G4Orb::DistanceToOut(p)", "GeomSolids1002",
645  JustWarning, "Point p is outside !?" );
646  }
647 #endif
648 
649  safe = fRmax - radius;
650  if ( safe < 0. ) safe = 0.;
651  return safe;
652 }
653 
655 //
656 // G4EntityType
657 
659 {
660  return G4String("G4Orb");
661 }
662 
664 //
665 // Make a clone of the object
666 //
668 {
669  return new G4Orb(*this);
670 }
671 
673 //
674 // Stream object contents to an output stream
675 
676 std::ostream& G4Orb::StreamInfo( std::ostream& os ) const
677 {
678  G4int oldprc = os.precision(16);
679  os << "-----------------------------------------------------------\n"
680  << " *** Dump for solid - " << GetName() << " ***\n"
681  << " ===================================================\n"
682  << " Solid type: G4Orb\n"
683  << " Parameters: \n"
684 
685  << " outer radius: " << fRmax/mm << " mm \n"
686  << "-----------------------------------------------------------\n";
687  os.precision(oldprc);
688 
689  return os;
690 }
691 
693 //
694 // GetPointOnSurface
695 
697 {
698  // generate a random number from zero to 2pi...
699  //
700  G4double phi = RandFlat::shoot(0.,2.*pi);
701  G4double cosphi = std::cos(phi);
702  G4double sinphi = std::sin(phi);
703 
704  // generate a random point uniform in area
705  G4double costheta = RandFlat::shoot(-1.,1.);
706  G4double sintheta = std::sqrt(1.-sqr(costheta));
707 
708  return G4ThreeVector (fRmax*sintheta*cosphi,
709  fRmax*sintheta*sinphi, fRmax*costheta);
710 }
711 
713 //
714 // Methods for visualisation
715 
717 {
718  scene.AddSolid (*this);
719 }
720 
722 {
723  return new G4PolyhedronSphere (0., fRmax, 0., 2*pi, 0., pi);
724 }
725 
727 {
728  return new G4NURBSbox (fRmax, fRmax, fRmax); // Box for now!!!
729 }