source: trunk/source/geometry/solids/CSG/src/G4Orb.cc@ 1230

Last change on this file since 1230 was 1228, checked in by garnier, 16 years ago

update geant4.9.3 tag

File size: 19.3 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// $Id: G4Orb.cc,v 1.30 2009/11/30 10:20:38 gcosmo Exp $
27// GEANT4 tag $Name: geant4-09-03 $
28//
29// class G4Orb
30//
31// Implementation for G4Orb class
32//
33// History:
34//
35// 30.06.04 V.Grichine - bug fixed in DistanceToIn(p,v) on Rmax surface
36// 20.08.03 V.Grichine - created
37//
38//////////////////////////////////////////////////////////////
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
59using namespace CLHEP;
60
61// Private enum: Not for external use - used by distanceToOut
62
63enum ESide {kNull,kRMax};
64
65// used by normal
66
67enum ENorm {kNRMax};
68
69
70const G4double G4Orb::fEpsilon = 2.e-11; // relative tolerance of fRmax
71
72////////////////////////////////////////////////////////////////////////
73//
74// constructor - check positive radius
75//
76
77G4Orb::G4Orb( const G4String& pName,G4double pRmax )
78: G4CSGSolid(pName)
79{
80
81 G4double kRadTolerance
82 = G4GeometryTolerance::GetInstance()->GetRadialTolerance();
83
84 // Check radius
85 //
86 if (pRmax >= 10*kCarTolerance )
87 {
88 fRmax = pRmax;
89 }
90 else
91 {
92 G4Exception("G4Orb::G4Orb()", "InvalidSetup", FatalException,
93 "Invalid radius > 10*kCarTolerance.");
94 }
95 fRmaxTolerance = std::max( kRadTolerance, fEpsilon*fRmax);
96
97}
98
99///////////////////////////////////////////////////////////////////////
100//
101// Fake default constructor - sets only member data and allocates memory
102// for usage restricted to object persistency.
103//
104G4Orb::G4Orb( __void__& a )
105 : G4CSGSolid(a)
106{
107}
108
109/////////////////////////////////////////////////////////////////////
110//
111// Destructor
112
113G4Orb::~G4Orb()
114{
115}
116
117//////////////////////////////////////////////////////////////////////////
118//
119// Dispatch to parameterisation for replication mechanism dimension
120// computation & modification.
121
122void G4Orb::ComputeDimensions( G4VPVParameterisation* p,
123 const G4int n,
124 const G4VPhysicalVolume* pRep)
125{
126 p->ComputeDimensions(*this,n,pRep);
127}
128
129////////////////////////////////////////////////////////////////////////////
130//
131// Calculate extent under transform and specified limit
132
133G4bool G4Orb::CalculateExtent( const EAxis pAxis,
134 const G4VoxelLimits& pVoxelLimit,
135 const G4AffineTransform& pTransform,
136 G4double& pMin, G4double& pMax ) const
137{
138 // Compute x/y/z mins and maxs for bounding box respecting limits,
139 // with early returns if outside limits. Then switch() on pAxis,
140 // and compute exact x and y limit for x/y case
141
142 G4double xoffset,xMin,xMax;
143 G4double yoffset,yMin,yMax;
144 G4double zoffset,zMin,zMax;
145
146 G4double diff1,diff2,maxDiff,newMin,newMax;
147 G4double xoff1,xoff2,yoff1,yoff2;
148
149 xoffset=pTransform.NetTranslation().x();
150 xMin=xoffset-fRmax;
151 xMax=xoffset+fRmax;
152
153 if (pVoxelLimit.IsXLimited())
154 {
155 if ( (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance)
156 || (xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance) )
157 {
158 return false;
159 }
160 else
161 {
162 if (xMin<pVoxelLimit.GetMinXExtent())
163 {
164 xMin=pVoxelLimit.GetMinXExtent();
165 }
166 if (xMax>pVoxelLimit.GetMaxXExtent())
167 {
168 xMax=pVoxelLimit.GetMaxXExtent();
169 }
170 }
171 }
172 yoffset=pTransform.NetTranslation().y();
173 yMin=yoffset-fRmax;
174 yMax=yoffset+fRmax;
175
176 if (pVoxelLimit.IsYLimited())
177 {
178 if ( (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance)
179 || (yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance) )
180 {
181 return false;
182 }
183 else
184 {
185 if (yMin<pVoxelLimit.GetMinYExtent())
186 {
187 yMin=pVoxelLimit.GetMinYExtent();
188 }
189 if (yMax>pVoxelLimit.GetMaxYExtent())
190 {
191 yMax=pVoxelLimit.GetMaxYExtent();
192 }
193 }
194 }
195 zoffset=pTransform.NetTranslation().z();
196 zMin=zoffset-fRmax;
197 zMax=zoffset+fRmax;
198
199 if (pVoxelLimit.IsZLimited())
200 {
201 if ( (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance)
202 || (zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance) )
203 {
204 return false;
205 }
206 else
207 {
208 if (zMin<pVoxelLimit.GetMinZExtent())
209 {
210 zMin=pVoxelLimit.GetMinZExtent();
211 }
212 if (zMax>pVoxelLimit.GetMaxZExtent())
213 {
214 zMax=pVoxelLimit.GetMaxZExtent();
215 }
216 }
217 }
218
219 // Known to cut sphere
220
221 switch (pAxis)
222 {
223 case kXAxis:
224 yoff1=yoffset-yMin;
225 yoff2=yMax-yoffset;
226
227 if ( yoff1 >= 0 && yoff2 >= 0 )
228 {
229 // Y limits cross max/min x => no change
230 //
231 pMin=xMin;
232 pMax=xMax;
233 }
234 else
235 {
236 // Y limits don't cross max/min x => compute max delta x,
237 // hence new mins/maxs
238 //
239 diff1=std::sqrt(fRmax*fRmax-yoff1*yoff1);
240 diff2=std::sqrt(fRmax*fRmax-yoff2*yoff2);
241 maxDiff=(diff1>diff2) ? diff1:diff2;
242 newMin=xoffset-maxDiff;
243 newMax=xoffset+maxDiff;
244 pMin=(newMin<xMin) ? xMin : newMin;
245 pMax=(newMax>xMax) ? xMax : newMax;
246 }
247 break;
248 case kYAxis:
249 xoff1=xoffset-xMin;
250 xoff2=xMax-xoffset;
251 if (xoff1>=0&&xoff2>=0)
252 {
253 // X limits cross max/min y => no change
254 //
255 pMin=yMin;
256 pMax=yMax;
257 }
258 else
259 {
260 // X limits don't cross max/min y => compute max delta y,
261 // hence new mins/maxs
262 //
263 diff1=std::sqrt(fRmax*fRmax-xoff1*xoff1);
264 diff2=std::sqrt(fRmax*fRmax-xoff2*xoff2);
265 maxDiff=(diff1>diff2) ? diff1:diff2;
266 newMin=yoffset-maxDiff;
267 newMax=yoffset+maxDiff;
268 pMin=(newMin<yMin) ? yMin : newMin;
269 pMax=(newMax>yMax) ? yMax : newMax;
270 }
271 break;
272 case kZAxis:
273 pMin=zMin;
274 pMax=zMax;
275 break;
276 default:
277 break;
278 }
279 pMin -= fRmaxTolerance;
280 pMax += fRmaxTolerance;
281
282 return true;
283
284}
285
286///////////////////////////////////////////////////////////////////////////
287//
288// Return whether point inside/outside/on surface
289// Split into radius checks
290//
291
292EInside G4Orb::Inside( const G4ThreeVector& p ) const
293{
294 G4double rad2,tolRMax;
295 EInside in;
296
297
298 rad2 = p.x()*p.x()+p.y()*p.y()+p.z()*p.z() ;
299
300 G4double rad = std::sqrt(rad2);
301
302 // G4double rad = std::sqrt(rad2);
303 // Check radial surface
304 // sets `in'
305
306 tolRMax = fRmax - fRmaxTolerance*0.5 ;
307
308 if ( rad <= tolRMax ) { in = kInside ; }
309 else
310 {
311 tolRMax = fRmax + fRmaxTolerance*0.5 ;
312 if ( rad <= tolRMax ) { in = kSurface ; }
313 else { in = kOutside ; }
314 }
315 return in;
316}
317
318/////////////////////////////////////////////////////////////////////
319//
320// Return unit normal of surface closest to p
321// - note if point on z axis, ignore phi divided sides
322// - unsafe if point close to z axis a rmin=0 - no explicit checks
323
324G4ThreeVector G4Orb::SurfaceNormal( const G4ThreeVector& p ) const
325{
326 ENorm side = kNRMax;
327 G4ThreeVector norm;
328 G4double rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
329
330 switch (side)
331 {
332 case kNRMax:
333 norm = G4ThreeVector(p.x()/rad,p.y()/rad,p.z()/rad);
334 break;
335 default:
336 DumpInfo();
337#ifdef G4CSGDEBUG
338 G4Exception("G4Orb::SurfaceNormal()", "Notification", JustWarning,
339 "Undefined side for valid surface normal to solid.");
340#endif
341 break;
342 }
343
344 return norm;
345}
346
347///////////////////////////////////////////////////////////////////////////////
348//
349// Calculate distance to shape from outside, along normalised vector
350// - return kInfinity if no intersection, or intersection distance <= tolerance
351//
352// -> If point is outside outer radius, compute intersection with rmax
353// - if no intersection return
354// - if valid phi,theta return intersection Dist
355
356G4double G4Orb::DistanceToIn( const G4ThreeVector& p,
357 const G4ThreeVector& v ) const
358{
359 G4double snxt = kInfinity ; // snxt = default return value
360
361 G4double rad2, pDotV3d, tolORMax2, tolIRMax2 ;
362 G4double c, d2, s = kInfinity ;
363
364 const G4double dRmax = 100.*fRmax;
365
366 // General Precalcs
367
368 rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z() ;
369 pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z() ;
370
371 // Radial Precalcs
372
373 tolORMax2 = (fRmax+fRmaxTolerance*0.5)*(fRmax+fRmaxTolerance*0.5) ;
374 tolIRMax2 = (fRmax-fRmaxTolerance*0.5)*(fRmax-fRmaxTolerance*0.5) ;
375
376 // Outer spherical shell intersection
377 // - Only if outside tolerant fRmax
378 // - Check for if inside and outer G4Orb heading through solid (-> 0)
379 // - No intersect -> no intersection with G4Orb
380 //
381 // Shell eqn: x^2+y^2+z^2 = RSPH^2
382 //
383 // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
384 //
385 // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
386 // => rad2 +2s(pDotV3d) +s^2 =R^2
387 //
388 // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
389
390
391 G4double rad = std::sqrt(rad2);
392 c = (rad - fRmax)*(rad + fRmax);
393
394 if ( c > fRmaxTolerance*fRmax )
395 {
396 // If outside tolerant boundary of outer G4Orb
397 // [ should be std::sqrt(rad2) - fRmax > fRmaxTolerance*0.5 ]
398
399 d2 = pDotV3d*pDotV3d - c ;
400
401 if ( d2 >= 0 )
402 {
403 s = -pDotV3d - std::sqrt(d2) ;
404 if ( s >= 0 )
405 {
406 if ( s>dRmax ) // Avoid rounding errors due to precision issues seen on
407 { // 64 bits systems. Split long distances and recompute
408 G4double fTerm = s-std::fmod(s,dRmax);
409 s = fTerm + DistanceToIn(p+fTerm*v,v);
410 }
411 return snxt = s;
412 }
413 }
414 else // No intersection with G4Orb
415 {
416 return snxt = kInfinity;
417 }
418 }
419 else
420 {
421 if ( c > -fRmaxTolerance*fRmax ) // on surface
422 {
423 d2 = pDotV3d*pDotV3d - c ;
424 if ( (d2 < fRmaxTolerance*fRmax) || (pDotV3d >= 0) )
425 {
426 return snxt = kInfinity;
427 }
428 else
429 {
430 return snxt = 0.;
431 }
432 }
433#ifdef G4CSGDEBUG
434 else // inside ???
435 {
436 G4Exception("G4Orb::DistanceToIn(p,v)", "Notification",
437 JustWarning, "Point p is inside !?");
438 }
439#endif
440 }
441 return snxt;
442}
443
444//////////////////////////////////////////////////////////////////////
445//
446// Calculate distance (<= actual) to closest surface of shape from outside
447// - Calculate distance to radial plane
448// - Return 0 if point inside
449
450G4double G4Orb::DistanceToIn( const G4ThreeVector& p ) const
451{
452 G4double safe = 0.0,
453 rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
454 safe = rad - fRmax;
455 if( safe < 0 ) { safe = 0.; }
456 return safe;
457}
458
459/////////////////////////////////////////////////////////////////////
460//
461// Calculate distance to surface of shape from `inside', allowing for tolerance
462//
463
464G4double G4Orb::DistanceToOut( const G4ThreeVector& p,
465 const G4ThreeVector& v,
466 const G4bool calcNorm,
467 G4bool *validNorm,
468 G4ThreeVector *n ) const
469{
470 G4double snxt = kInfinity; // ??? snxt is default return value
471 ESide side = kNull;
472
473 G4double rad2,pDotV3d;
474 G4double xi,yi,zi; // Intersection point
475 G4double c,d2;
476
477 rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z();
478 pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z();
479
480 // Radial Intersection from G4Orb::DistanceToIn
481 //
482 // Outer spherical shell intersection
483 // - Only if outside tolerant fRmax
484 // - Check for if inside and outer G4Orb heading through solid (-> 0)
485 // - No intersect -> no intersection with G4Orb
486 //
487 // Shell eqn: x^2+y^2+z^2=RSPH^2
488 //
489 // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
490 //
491 // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
492 // => rad2 +2s(pDotV3d) +s^2 =R^2
493 //
494 // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
495
496 const G4double Rmax_plus = fRmax + fRmaxTolerance*0.5;
497 G4double rad = std::sqrt(rad2);
498
499 if ( rad <= Rmax_plus )
500 {
501 c = (rad - fRmax)*(rad + fRmax);
502
503 if ( c < fRmaxTolerance*fRmax )
504 {
505 // Within tolerant Outer radius
506 //
507 // The test is
508 // rad - fRmax < 0.5*fRmaxTolerance
509 // => rad < fRmax + 0.5*kRadTol
510 // => rad2 < (fRmax + 0.5*kRadTol)^2
511 // => rad2 < fRmax^2 + 2.*0.5*fRmax*kRadTol + 0.25*kRadTol*kRadTol
512 // => rad2 - fRmax^2 <~ fRmax*kRadTol
513
514 d2 = pDotV3d*pDotV3d - c;
515
516 if( ( c > -fRmaxTolerance*fRmax) && // on tolerant surface
517 ( ( pDotV3d >= 0 ) || ( d2 < 0 )) ) // leaving outside from Rmax
518 // not re-entering
519 {
520 if(calcNorm)
521 {
522 *validNorm = true ;
523 *n = G4ThreeVector(p.x()/fRmax,p.y()/fRmax,p.z()/fRmax) ;
524 }
525 return snxt = 0;
526 }
527 else
528 {
529 snxt = -pDotV3d + std::sqrt(d2); // second root since inside Rmax
530 side = kRMax ;
531 }
532 }
533 }
534 else // p is outside ???
535 {
536 G4cout.precision(16);
537 G4cout << G4endl;
538 DumpInfo();
539 G4cout << "Position:" << G4endl << G4endl;
540 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
541 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
542 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
543 G4cout << "Rp = "<< std::sqrt( p.x()*p.x()+p.y()*p.y()+p.z()*p.z() )/mm << " mm"
544 << G4endl << G4endl;
545 G4cout << "Direction:" << G4endl << G4endl;
546 G4cout << "v.x() = " << v.x() << G4endl;
547 G4cout << "v.y() = " << v.y() << G4endl;
548 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
549 G4cout << "Proposed distance :" << G4endl << G4endl;
550 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
551 G4Exception("G4Orb::DistanceToOut(p,v,..)", "Notification",
552 JustWarning, "Logic error: snxt = kInfinity ???");
553 }
554 if (calcNorm) // Output switch operator
555 {
556 switch( side )
557 {
558 case kRMax:
559 xi=p.x()+snxt*v.x();
560 yi=p.y()+snxt*v.y();
561 zi=p.z()+snxt*v.z();
562 *n=G4ThreeVector(xi/fRmax,yi/fRmax,zi/fRmax);
563 *validNorm=true;
564 break;
565 default:
566 G4cout.precision(16);
567 G4cout << G4endl;
568 DumpInfo();
569 G4cout << "Position:" << G4endl << G4endl;
570 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
571 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
572 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
573 G4cout << "Direction:" << G4endl << G4endl;
574 G4cout << "v.x() = " << v.x() << G4endl;
575 G4cout << "v.y() = " << v.y() << G4endl;
576 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
577 G4cout << "Proposed distance :" << G4endl << G4endl;
578 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
579 G4Exception("G4Orb::DistanceToOut(p,v,..)","Notification",JustWarning,
580 "Undefined side for valid surface normal to solid.");
581 break;
582 }
583 }
584 return snxt;
585}
586
587/////////////////////////////////////////////////////////////////////////
588//
589// Calculate distance (<=actual) to closest surface of shape from inside
590
591G4double G4Orb::DistanceToOut( const G4ThreeVector& p ) const
592{
593 G4double safe=0.0,rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
594
595#ifdef G4CSGDEBUG
596 if( Inside(p) == kOutside )
597 {
598 G4cout.precision(16) ;
599 G4cout << G4endl ;
600 DumpInfo();
601 G4cout << "Position:" << G4endl << G4endl ;
602 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
603 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
604 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
605 G4Exception("G4Orb::DistanceToOut(p)", "Notification", JustWarning,
606 "Point p is outside !?" );
607 }
608#endif
609
610 safe = fRmax - rad;
611 if ( safe < 0. ) safe = 0.;
612 return safe;
613}
614
615//////////////////////////////////////////////////////////////////////////
616//
617// G4EntityType
618
619G4GeometryType G4Orb::GetEntityType() const
620{
621 return G4String("G4Orb");
622}
623
624//////////////////////////////////////////////////////////////////////////
625//
626// Stream object contents to an output stream
627
628std::ostream& G4Orb::StreamInfo( std::ostream& os ) const
629{
630 os << "-----------------------------------------------------------\n"
631 << " *** Dump for solid - " << GetName() << " ***\n"
632 << " ===================================================\n"
633 << " Solid type: G4Orb\n"
634 << " Parameters: \n"
635
636 << " outer radius: " << fRmax/mm << " mm \n"
637 << "-----------------------------------------------------------\n";
638
639 return os;
640}
641
642/////////////////////////////////////////////////////////////////////////
643//
644// GetPointOnSurface
645
646G4ThreeVector G4Orb::GetPointOnSurface() const
647{
648 // generate a random number from zero to 2pi...
649 //
650 G4double phi = RandFlat::shoot(0.,2.*pi);
651 G4double cosphi = std::cos(phi);
652 G4double sinphi = std::sin(phi);
653
654 G4double theta = RandFlat::shoot(0.,pi);
655 G4double costheta = std::cos(theta);
656 G4double sintheta = std::sqrt(1.-sqr(costheta));
657
658 return G4ThreeVector (fRmax*sintheta*cosphi,
659 fRmax*sintheta*sinphi, fRmax*costheta);
660}
661
662////////////////////////////////////////////////////////////////////////
663//
664// Methods for visualisation
665
666void G4Orb::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
667{
668 scene.AddSolid (*this);
669}
670
671G4Polyhedron* G4Orb::CreatePolyhedron () const
672{
673 return new G4PolyhedronSphere (0., fRmax, 0., 2*pi, 0., pi);
674}
675
676G4NURBS* G4Orb::CreateNURBS () const
677{
678 return new G4NURBSbox (fRmax, fRmax, fRmax); // Box for now!!!
679}
Note: See TracBrowser for help on using the repository browser.