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

Last change on this file since 1174 was 1058, checked in by garnier, 17 years ago

file release beta

File size: 18.9 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.24 2007/05/18 07:38:01 gcosmo Exp $
27// GEANT4 tag $Name: geant4-09-02-ref-02 $
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 // Check radial surface
302 // sets `in'
303
304 tolRMax = fRmax - fRmaxTolerance*0.5 ;
305
306 if ( rad2 <= tolRMax*tolRMax ) in = kInside ;
307 else
308 {
309 tolRMax = fRmax + fRmaxTolerance*0.5 ;
310 if ( rad2 <= tolRMax*tolRMax ) in = kSurface ;
311 else in = kOutside ;
312 }
313 return in;
314}
315
316/////////////////////////////////////////////////////////////////////
317//
318// Return unit normal of surface closest to p
319// - note if point on z axis, ignore phi divided sides
320// - unsafe if point close to z axis a rmin=0 - no explicit checks
321
322G4ThreeVector G4Orb::SurfaceNormal( const G4ThreeVector& p ) const
323{
324 ENorm side = kNRMax;
325 G4ThreeVector norm;
326 G4double rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
327
328 switch (side)
329 {
330 case kNRMax:
331 norm = G4ThreeVector(p.x()/rad,p.y()/rad,p.z()/rad);
332 break;
333 default:
334 DumpInfo();
335#ifdef G4CSGDEBUG
336 G4Exception("G4Orb::SurfaceNormal()", "Notification", JustWarning,
337 "Undefined side for valid surface normal to solid.");
338#endif
339 break;
340 }
341
342 return norm;
343}
344
345///////////////////////////////////////////////////////////////////////////////
346//
347// Calculate distance to shape from outside, along normalised vector
348// - return kInfinity if no intersection, or intersection distance <= tolerance
349//
350// -> If point is outside outer radius, compute intersection with rmax
351// - if no intersection return
352// - if valid phi,theta return intersection Dist
353
354G4double G4Orb::DistanceToIn( const G4ThreeVector& p,
355 const G4ThreeVector& v ) const
356{
357 G4double snxt = kInfinity ; // snxt = default return value
358
359 G4double rad2, pDotV3d, tolORMax2, tolIRMax2 ;
360 G4double c, d2, s = kInfinity ;
361
362 // General Precalcs
363
364 rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z() ;
365 pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z() ;
366
367 // Radial Precalcs
368
369 tolORMax2 = (fRmax+fRmaxTolerance*0.5)*(fRmax+fRmaxTolerance*0.5) ;
370 tolIRMax2 = (fRmax-fRmaxTolerance*0.5)*(fRmax-fRmaxTolerance*0.5) ;
371
372 // Outer spherical shell intersection
373 // - Only if outside tolerant fRmax
374 // - Check for if inside and outer G4Orb heading through solid (-> 0)
375 // - No intersect -> no intersection with G4Orb
376 //
377 // Shell eqn: x^2+y^2+z^2 = RSPH^2
378 //
379 // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
380 //
381 // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
382 // => rad2 +2s(pDotV3d) +s^2 =R^2
383 //
384 // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
385
386 c = rad2 - fRmax*fRmax ;
387
388 if ( c > fRmaxTolerance*fRmax )
389 {
390 // If outside tolerant boundary of outer G4Orb
391 // [ should be std::sqrt(rad2) - fRmax > fRmaxTolerance*0.5 ]
392
393 d2 = pDotV3d*pDotV3d - c ;
394
395 if ( d2 >= 0 )
396 {
397 s = -pDotV3d - std::sqrt(d2) ;
398
399 if (s >= 0 ) return snxt = s;
400
401 }
402 else // No intersection with G4Orb
403 {
404 return snxt = kInfinity;
405 }
406 }
407 else
408 {
409 if ( c > -fRmaxTolerance*fRmax ) // on surface
410 {
411 d2 = pDotV3d*pDotV3d - c ;
412 // if ( pDotV3d >= 0 ) return snxt = kInfinity;
413 if ( d2 < fRmaxTolerance*fRmax || pDotV3d >= 0 ) return snxt = kInfinity;
414 else return snxt = 0.;
415 }
416 else // inside ???
417 {
418 G4Exception("G4Orb::DistanceToIn(p,v)", "Notification",
419 JustWarning, "Point p is inside !?");
420 }
421 }
422 return snxt;
423}
424
425//////////////////////////////////////////////////////////////////////
426//
427// Calculate distance (<= actual) to closest surface of shape from outside
428// - Calculate distance to radial plane
429// - Return 0 if point inside
430
431G4double G4Orb::DistanceToIn( const G4ThreeVector& p ) const
432{
433 G4double safe=0.0, rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
434 safe = rad - fRmax;
435 if( safe < 0 ) safe = 0. ;
436 return safe;
437}
438
439/////////////////////////////////////////////////////////////////////
440//
441// Calculate distance to surface of shape from `inside', allowing for tolerance
442//
443
444G4double G4Orb::DistanceToOut( const G4ThreeVector& p,
445 const G4ThreeVector& v,
446 const G4bool calcNorm,
447 G4bool *validNorm,
448 G4ThreeVector *n ) const
449{
450 G4double snxt = kInfinity; // ??? snxt is default return value
451 ESide side = kNull;
452
453 G4double rad2,pDotV3d;
454 G4double xi,yi,zi; // Intersection point
455 G4double c,d2;
456
457 rad2 = p.x()*p.x() + p.y()*p.y() + p.z()*p.z();
458 pDotV3d = p.x()*v.x() + p.y()*v.y() + p.z()*v.z();
459
460 // Radial Intersection from G4Orb::DistanceToIn
461 //
462 // Outer spherical shell intersection
463 // - Only if outside tolerant fRmax
464 // - Check for if inside and outer G4Orb heading through solid (-> 0)
465 // - No intersect -> no intersection with G4Orb
466 //
467 // Shell eqn: x^2+y^2+z^2=RSPH^2
468 //
469 // => (px+svx)^2+(py+svy)^2+(pz+svz)^2=R^2
470 //
471 // => (px^2+py^2+pz^2) +2s(pxvx+pyvy+pzvz)+s^2(vx^2+vy^2+vz^2)=R^2
472 // => rad2 +2s(pDotV3d) +s^2 =R^2
473 //
474 // => s=-pDotV3d+-std::sqrt(pDotV3d^2-(rad2-R^2))
475
476 const G4double Rmax_plus = fRmax + fRmaxTolerance*0.5;
477
478 if( rad2 <= Rmax_plus*Rmax_plus )
479 {
480 c = rad2-fRmax*fRmax ;
481
482 if ( c < fRmaxTolerance*fRmax)
483 {
484 // Within tolerant Outer radius
485 //
486 // The test is
487 // rad - fRmax < 0.5*fRmaxTolerance
488 // => rad < fRmax + 0.5*kRadTol
489 // => rad2 < (fRmax + 0.5*kRadTol)^2
490 // => rad2 < fRmax^2 + 2.*0.5*fRmax*kRadTol + 0.25*kRadTol*kRadTol
491 // => rad2 - fRmax^2 <~ fRmax*kRadTol
492
493 d2 = pDotV3d*pDotV3d - c;
494
495 if( ( c > -fRmaxTolerance*fRmax) && // on tolerant surface
496 ( ( pDotV3d >= 0 ) || ( d2 < 0 )) ) // leaving outside from Rmax
497 // not re-entering
498 {
499 if(calcNorm)
500 {
501 *validNorm = true ;
502 *n = G4ThreeVector(p.x()/fRmax,p.y()/fRmax,p.z()/fRmax) ;
503 }
504 return snxt = 0;
505 }
506 else
507 {
508 snxt = -pDotV3d + std::sqrt(d2); // second root since inside Rmax
509 side = kRMax ;
510 }
511 }
512 }
513 else // p is outside ???
514 {
515 G4cout.precision(16);
516 G4cout << G4endl;
517 DumpInfo();
518 G4cout << "Position:" << G4endl << G4endl;
519 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
520 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
521 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
522 G4cout << "Rp = "<< std::sqrt( p.x()*p.x()+p.y()*p.y()+p.z()*p.z() )/mm << " mm"
523 << G4endl << G4endl;
524 G4cout << "Direction:" << G4endl << G4endl;
525 G4cout << "v.x() = " << v.x() << G4endl;
526 G4cout << "v.y() = " << v.y() << G4endl;
527 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
528 G4cout << "Proposed distance :" << G4endl << G4endl;
529 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
530 G4Exception("G4Orb::DistanceToOut(p,v,..)", "Notification",
531 JustWarning, "Logic error: snxt = kInfinity ???");
532 }
533 if (calcNorm) // Output switch operator
534 {
535 switch( side )
536 {
537 case kRMax:
538 xi=p.x()+snxt*v.x();
539 yi=p.y()+snxt*v.y();
540 zi=p.z()+snxt*v.z();
541 *n=G4ThreeVector(xi/fRmax,yi/fRmax,zi/fRmax);
542 *validNorm=true;
543 break;
544 default:
545 G4cout.precision(16);
546 G4cout << G4endl;
547 DumpInfo();
548 G4cout << "Position:" << G4endl << G4endl;
549 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
550 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
551 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
552 G4cout << "Direction:" << G4endl << G4endl;
553 G4cout << "v.x() = " << v.x() << G4endl;
554 G4cout << "v.y() = " << v.y() << G4endl;
555 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
556 G4cout << "Proposed distance :" << G4endl << G4endl;
557 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
558 G4Exception("G4Orb::DistanceToOut(p,v,..)","Notification",JustWarning,
559 "Undefined side for valid surface normal to solid.");
560 break;
561 }
562 }
563 return snxt;
564}
565
566/////////////////////////////////////////////////////////////////////////
567//
568// Calculate distance (<=actual) to closest surface of shape from inside
569
570G4double G4Orb::DistanceToOut( const G4ThreeVector& p ) const
571{
572 G4double safe=0.0,rad = std::sqrt(p.x()*p.x()+p.y()*p.y()+p.z()*p.z());
573
574#ifdef G4CSGDEBUG
575 if( Inside(p) == kOutside )
576 {
577 G4cout.precision(16) ;
578 G4cout << G4endl ;
579 DumpInfo();
580 G4cout << "Position:" << G4endl << G4endl ;
581 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
582 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
583 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
584 G4Exception("G4Orb::DistanceToOut(p)", "Notification", JustWarning,
585 "Point p is outside !?" );
586 }
587#endif
588
589 safe = fRmax - rad;
590 if ( safe < 0. ) safe = 0.;
591 return safe;
592}
593
594//////////////////////////////////////////////////////////////////////////
595//
596// G4EntityType
597
598G4GeometryType G4Orb::GetEntityType() const
599{
600 return G4String("G4Orb");
601}
602
603//////////////////////////////////////////////////////////////////////////
604//
605// Stream object contents to an output stream
606
607std::ostream& G4Orb::StreamInfo( std::ostream& os ) const
608{
609 os << "-----------------------------------------------------------\n"
610 << " *** Dump for solid - " << GetName() << " ***\n"
611 << " ===================================================\n"
612 << " Solid type: G4Orb\n"
613 << " Parameters: \n"
614
615 << " outer radius: " << fRmax/mm << " mm \n"
616 << "-----------------------------------------------------------\n";
617
618 return os;
619}
620
621/////////////////////////////////////////////////////////////////////////
622//
623// GetPointOnSurface
624
625G4ThreeVector G4Orb::GetPointOnSurface() const
626{
627 // generate a random number from zero to 2pi...
628 //
629 G4double phi = RandFlat::shoot(0.,2.*pi);
630 G4double cosphi = std::cos(phi);
631 G4double sinphi = std::sin(phi);
632
633 G4double theta = RandFlat::shoot(0.,pi);
634 G4double costheta = std::cos(theta);
635 G4double sintheta = std::sqrt(1.-sqr(costheta));
636
637 return G4ThreeVector (fRmax*sintheta*cosphi,
638 fRmax*sintheta*sinphi, fRmax*costheta);
639}
640
641////////////////////////////////////////////////////////////////////////
642//
643// Methods for visualisation
644
645void G4Orb::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
646{
647 scene.AddSolid (*this);
648}
649
650G4Polyhedron* G4Orb::CreatePolyhedron () const
651{
652 return new G4PolyhedronSphere (0., fRmax, 0., 2*pi, 0., pi);
653}
654
655G4NURBS* G4Orb::CreateNURBS () const
656{
657 return new G4NURBSbox (fRmax, fRmax, fRmax); // Box for now!!!
658}
Note: See TracBrowser for help on using the repository browser.