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

Last change on this file since 1350 was 1337, checked in by garnier, 15 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 19.5 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.31 2009/12/04 15:39:56 grichine Exp $
27// GEANT4 tag $Name: geant4-09-04-beta-01 $
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 rad, pDotV3d; // , tolORMax2, tolIRMax2;
362 G4double c, d2, s = kInfinity;
363
364 const G4double dRmax = 100.*fRmax;
365
366 // General Precalcs
367
368 rad = std::sqrt(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 c = (rad - fRmax)*(rad + fRmax);
391
392 if( rad > fRmax-fRmaxTolerance*0.5 ) // not inside in terms of Inside(p)
393 {
394 if ( c > fRmaxTolerance*fRmax )
395 {
396 // If outside tolerant boundary of outer G4Orb in terms of c
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 // not outside in terms of c
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 }
434 }
435#ifdef G4CSGDEBUG
436 else // inside ???
437 {
438 G4Exception("G4Orb::DistanceToIn(p,v)", "Notification",
439 JustWarning, "Point p is inside !?");
440 }
441#endif
442
443 return snxt;
444}
445
446//////////////////////////////////////////////////////////////////////
447//
448// Calculate distance (<= actual) to closest surface of shape from outside
449// - Calculate distance to radial plane
450// - Return 0 if point inside
451
452G4double G4Orb::DistanceToIn( const G4ThreeVector& p ) const
453{
454 G4double safe = 0.0,
455 rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
456 safe = rad - fRmax;
457 if( safe < 0 ) { safe = 0.; }
458 return safe;
459}
460
461/////////////////////////////////////////////////////////////////////
462//
463// Calculate distance to surface of shape from `inside', allowing for tolerance
464//
465
466G4double G4Orb::DistanceToOut( const G4ThreeVector& p,
467 const G4ThreeVector& v,
468 const G4bool calcNorm,
469 G4bool *validNorm,
470 G4ThreeVector *n ) const
471{
472 G4double snxt = kInfinity; // ??? snxt is default return value
473 ESide side = kNull;
474
475 G4double rad2,pDotV3d;
476 G4double xi,yi,zi; // Intersection point
477 G4double c,d2;
478
479 rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z();
480 pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z();
481
482 // Radial Intersection from G4Orb::DistanceToIn
483 //
484 // Outer spherical shell intersection
485 // - Only if outside tolerant fRmax
486 // - Check for if inside and outer G4Orb heading through solid (-> 0)
487 // - No intersect -> no intersection with G4Orb
488 //
489 // Shell eqn: x^2+y^2+z^2=RSPH^2
490 //
491 // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
492 //
493 // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
494 // => rad2 +2s(pDotV3d) +s^2 =R^2
495 //
496 // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
497
498 const G4double Rmax_plus = fRmax + fRmaxTolerance*0.5;
499 G4double rad = std::sqrt(rad2);
500
501 if ( rad <= Rmax_plus )
502 {
503 c = (rad - fRmax)*(rad + fRmax);
504
505 if ( c < fRmaxTolerance*fRmax )
506 {
507 // Within tolerant Outer radius
508 //
509 // The test is
510 // rad - fRmax < 0.5*fRmaxTolerance
511 // => rad < fRmax + 0.5*kRadTol
512 // => rad2 < (fRmax + 0.5*kRadTol)^2
513 // => rad2 < fRmax^2 + 2.*0.5*fRmax*kRadTol + 0.25*kRadTol*kRadTol
514 // => rad2 - fRmax^2 <~ fRmax*kRadTol
515
516 d2 = pDotV3d*pDotV3d - c;
517
518 if( ( c > -fRmaxTolerance*fRmax) && // on tolerant surface
519 ( ( pDotV3d >= 0 ) || ( d2 < 0 )) ) // leaving outside from Rmax
520 // not re-entering
521 {
522 if(calcNorm)
523 {
524 *validNorm = true;
525 *n = G4ThreeVector(p.x()/fRmax,p.y()/fRmax,p.z()/fRmax);
526 }
527 return snxt = 0;
528 }
529 else
530 {
531 snxt = -pDotV3d + std::sqrt(d2); // second root since inside Rmax
532 side = kRMax;
533 }
534 }
535 }
536 else // p is outside ???
537 {
538 G4cout.precision(16);
539 G4cout << G4endl;
540 DumpInfo();
541 G4cout << "Position:" << G4endl << G4endl;
542 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
543 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
544 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
545 G4cout << "Rp = "<< std::sqrt( p.x()*p.x()+p.y()*p.y()+p.z()*p.z() )/mm << " mm"
546 << G4endl << G4endl;
547 G4cout << "Direction:" << G4endl << G4endl;
548 G4cout << "v.x() = " << v.x() << G4endl;
549 G4cout << "v.y() = " << v.y() << G4endl;
550 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
551 G4cout << "Proposed distance :" << G4endl << G4endl;
552 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
553 G4Exception("G4Orb::DistanceToOut(p,v,..)", "Notification",
554 JustWarning, "Logic error: snxt = kInfinity ???");
555 }
556 if (calcNorm) // Output switch operator
557 {
558 switch( side )
559 {
560 case kRMax:
561 xi=p.x()+snxt*v.x();
562 yi=p.y()+snxt*v.y();
563 zi=p.z()+snxt*v.z();
564 *n=G4ThreeVector(xi/fRmax,yi/fRmax,zi/fRmax);
565 *validNorm=true;
566 break;
567 default:
568 G4cout.precision(16);
569 G4cout << G4endl;
570 DumpInfo();
571 G4cout << "Position:" << G4endl << G4endl;
572 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
573 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
574 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
575 G4cout << "Direction:" << G4endl << G4endl;
576 G4cout << "v.x() = " << v.x() << G4endl;
577 G4cout << "v.y() = " << v.y() << G4endl;
578 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
579 G4cout << "Proposed distance :" << G4endl << G4endl;
580 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
581 G4Exception("G4Orb::DistanceToOut(p,v,..)","Notification",JustWarning,
582 "Undefined side for valid surface normal to solid.");
583 break;
584 }
585 }
586 return snxt;
587}
588
589/////////////////////////////////////////////////////////////////////////
590//
591// Calculate distance (<=actual) to closest surface of shape from inside
592
593G4double G4Orb::DistanceToOut( const G4ThreeVector& p ) const
594{
595 G4double safe=0.0,rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
596
597#ifdef G4CSGDEBUG
598 if( Inside(p) == kOutside )
599 {
600 G4cout.precision(16);
601 G4cout << G4endl;
602 DumpInfo();
603 G4cout << "Position:" << G4endl << G4endl;
604 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
605 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
606 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
607 G4Exception("G4Orb::DistanceToOut(p)", "Notification", JustWarning,
608 "Point p is outside !?" );
609 }
610#endif
611
612 safe = fRmax - rad;
613 if ( safe < 0. ) safe = 0.;
614 return safe;
615}
616
617//////////////////////////////////////////////////////////////////////////
618//
619// G4EntityType
620
621G4GeometryType G4Orb::GetEntityType() const
622{
623 return G4String("G4Orb");
624}
625
626//////////////////////////////////////////////////////////////////////////
627//
628// Stream object contents to an output stream
629
630std::ostream& G4Orb::StreamInfo( std::ostream& os ) const
631{
632 os << "-----------------------------------------------------------\n"
633 << " *** Dump for solid - " << GetName() << " ***\n"
634 << " ===================================================\n"
635 << " Solid type: G4Orb\n"
636 << " Parameters: \n"
637
638 << " outer radius: " << fRmax/mm << " mm \n"
639 << "-----------------------------------------------------------\n";
640
641 return os;
642}
643
644/////////////////////////////////////////////////////////////////////////
645//
646// GetPointOnSurface
647
648G4ThreeVector G4Orb::GetPointOnSurface() const
649{
650 // generate a random number from zero to 2pi...
651 //
652 G4double phi = RandFlat::shoot(0.,2.*pi);
653 G4double cosphi = std::cos(phi);
654 G4double sinphi = std::sin(phi);
655
656 G4double theta = RandFlat::shoot(0.,pi);
657 G4double costheta = std::cos(theta);
658 G4double sintheta = std::sqrt(1.-sqr(costheta));
659
660 return G4ThreeVector (fRmax*sintheta*cosphi,
661 fRmax*sintheta*sinphi, fRmax*costheta);
662}
663
664////////////////////////////////////////////////////////////////////////
665//
666// Methods for visualisation
667
668void G4Orb::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
669{
670 scene.AddSolid (*this);
671}
672
673G4Polyhedron* G4Orb::CreatePolyhedron () const
674{
675 return new G4PolyhedronSphere (0., fRmax, 0., 2*pi, 0., pi);
676}
677
678G4NURBS* G4Orb::CreateNURBS () const
679{
680 return new G4NURBSbox (fRmax, fRmax, fRmax); // Box for now!!!
681}
Note: See TracBrowser for help on using the repository browser.