source: trunk/source/geometry/solids/CSG/src/G4Box.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: 27.6 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: G4Box.cc,v 1.49 2010/05/25 10:14:41 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
29//
30//
31//
32// Implementation for G4Box class
33//
34// 24.06.98 - V.Grichine: insideEdge in DistanceToIn(p,v)
35// 20.09.98 - V.Grichine: new algorithm of DistanceToIn(p,v)
36// 07.05.00 - V.Grichine: d= DistanceToIn(p,v), if d<e/2, d=0
37// 09.06.00 - V.Grichine: safety in DistanceToIn(p) against Inside(p)=kOutside
38// and information before exception in DistanceToOut(p,v,...)
39// 15.11.00 - D.Williams, V.Grichine: bug fixed in CalculateExtent - change
40// algorithm for rotated vertices
41// --------------------------------------------------------------------
42
43#include "G4Box.hh"
44
45#include "G4VoxelLimits.hh"
46#include "G4AffineTransform.hh"
47#include "Randomize.hh"
48
49#include "G4VPVParameterisation.hh"
50
51#include "G4VGraphicsScene.hh"
52#include "G4Polyhedron.hh"
53#include "G4NURBS.hh"
54#include "G4NURBSbox.hh"
55#include "G4VisExtent.hh"
56
57////////////////////////////////////////////////////////////////////////
58//
59// Constructor - check & set half widths
60
61G4Box::G4Box(const G4String& pName,
62 G4double pX,
63 G4double pY,
64 G4double pZ)
65 : G4CSGSolid(pName)
66{
67 if ( (pX > 2*kCarTolerance)
68 && (pY > 2*kCarTolerance)
69 && (pZ > 2*kCarTolerance) ) // limit to thickness of surfaces
70 {
71 fDx = pX ;
72 fDy = pY ;
73 fDz = pZ ;
74 }
75 else
76 {
77 G4cerr << "ERROR - G4Box()::G4Box(): " << GetName() << G4endl
78 << " Dimensions too small ! - "
79 << pX << ", " << pY << ", " << pZ << G4endl;
80 G4Exception("G4Box::G4Box()", "InvalidSetup",
81 FatalException, "Invalid dimensions. Too small.");
82 }
83}
84
85//////////////////////////////////////////////////////////////////////////
86//
87// Fake default constructor - sets only member data and allocates memory
88// for usage restricted to object persistency.
89
90G4Box::G4Box( __void__& a )
91 : G4CSGSolid(a)
92{
93}
94
95//////////////////////////////////////////////////////////////////////////
96//
97// Destructor
98
99G4Box::~G4Box()
100{
101}
102
103//////////////////////////////////////////////////////////////////////////////
104
105void G4Box::SetXHalfLength(G4double dx)
106{
107 if(dx > 2*kCarTolerance) // limit to thickness of surfaces
108 {
109 fDx = dx;
110 }
111 else
112 {
113 G4cerr << "ERROR - G4Box()::SetXHalfLength(): " << GetName() << G4endl
114 << " Dimension X too small ! - "
115 << dx << G4endl;
116 G4Exception("G4Box::SetXHalfLength()", "InvalidSetup",
117 FatalException, "Invalid dimensions. Too small.");
118 }
119 fCubicVolume= 0.;
120 fSurfaceArea= 0.;
121 fpPolyhedron = 0;
122}
123
124void G4Box::SetYHalfLength(G4double dy)
125{
126 if(dy > 2*kCarTolerance) // limit to thickness of surfaces
127 {
128 fDy = dy;
129 }
130 else
131 {
132 G4cerr << "ERROR - G4Box()::SetYHalfLength(): " << GetName() << G4endl
133 << " Dimension Y too small ! - "
134 << dy << G4endl;
135 G4Exception("G4Box::SetYHalfLength()", "InvalidSetup",
136 FatalException, "Invalid dimensions. Too small.");
137 }
138 fCubicVolume= 0.;
139 fSurfaceArea= 0.;
140 fpPolyhedron = 0;
141}
142
143void G4Box::SetZHalfLength(G4double dz)
144{
145 if(dz > 2*kCarTolerance) // limit to thickness of surfaces
146 {
147 fDz = dz;
148 }
149 else
150 {
151 G4cerr << "ERROR - G4Box()::SetZHalfLength(): " << GetName() << G4endl
152 << " Dimension Z too small ! - "
153 << dz << G4endl;
154 G4Exception("G4Box::SetZHalfLength()", "InvalidSetup",
155 FatalException, "Invalid dimensions. Too small.");
156 }
157 fCubicVolume= 0.;
158 fSurfaceArea= 0.;
159 fpPolyhedron = 0;
160}
161
162////////////////////////////////////////////////////////////////////////
163//
164// Dispatch to parameterisation for replication mechanism dimension
165// computation & modification.
166
167void G4Box::ComputeDimensions(G4VPVParameterisation* p,
168 const G4int n,
169 const G4VPhysicalVolume* pRep)
170{
171 p->ComputeDimensions(*this,n,pRep);
172}
173
174//////////////////////////////////////////////////////////////////////////
175//
176// Calculate extent under transform and specified limit
177
178G4bool G4Box::CalculateExtent(const EAxis pAxis,
179 const G4VoxelLimits& pVoxelLimit,
180 const G4AffineTransform& pTransform,
181 G4double& pMin, G4double& pMax) const
182{
183 if (!pTransform.IsRotated())
184 {
185 // Special case handling for unrotated boxes
186 // Compute x/y/z mins and maxs respecting limits, with early returns
187 // if outside limits. Then switch() on pAxis
188
189 G4double xoffset,xMin,xMax;
190 G4double yoffset,yMin,yMax;
191 G4double zoffset,zMin,zMax;
192
193 xoffset = pTransform.NetTranslation().x() ;
194 xMin = xoffset - fDx ;
195 xMax = xoffset + fDx ;
196
197 if (pVoxelLimit.IsXLimited())
198 {
199 if ((xMin > pVoxelLimit.GetMaxXExtent()+kCarTolerance) ||
200 (xMax < pVoxelLimit.GetMinXExtent()-kCarTolerance)) { return false ; }
201 else
202 {
203 xMin = std::max(xMin, pVoxelLimit.GetMinXExtent());
204 xMax = std::min(xMax, pVoxelLimit.GetMaxXExtent());
205 }
206 }
207 yoffset = pTransform.NetTranslation().y() ;
208 yMin = yoffset - fDy ;
209 yMax = yoffset + fDy ;
210
211 if (pVoxelLimit.IsYLimited())
212 {
213 if ((yMin > pVoxelLimit.GetMaxYExtent()+kCarTolerance) ||
214 (yMax < pVoxelLimit.GetMinYExtent()-kCarTolerance)) { return false ; }
215 else
216 {
217 yMin = std::max(yMin, pVoxelLimit.GetMinYExtent());
218 yMax = std::min(yMax, pVoxelLimit.GetMaxYExtent());
219 }
220 }
221 zoffset = pTransform.NetTranslation().z() ;
222 zMin = zoffset - fDz ;
223 zMax = zoffset + fDz ;
224
225 if (pVoxelLimit.IsZLimited())
226 {
227 if ((zMin > pVoxelLimit.GetMaxZExtent()+kCarTolerance) ||
228 (zMax < pVoxelLimit.GetMinZExtent()-kCarTolerance)) { return false ; }
229 else
230 {
231 zMin = std::max(zMin, pVoxelLimit.GetMinZExtent());
232 zMax = std::min(zMax, pVoxelLimit.GetMaxZExtent());
233 }
234 }
235 switch (pAxis)
236 {
237 case kXAxis:
238 pMin = xMin ;
239 pMax = xMax ;
240 break ;
241 case kYAxis:
242 pMin=yMin;
243 pMax=yMax;
244 break;
245 case kZAxis:
246 pMin=zMin;
247 pMax=zMax;
248 break;
249 default:
250 break;
251 }
252 pMin -= kCarTolerance ;
253 pMax += kCarTolerance ;
254
255 return true;
256 }
257 else // General rotated case - create and clip mesh to boundaries
258 {
259 G4bool existsAfterClip = false ;
260 G4ThreeVectorList* vertices ;
261
262 pMin = +kInfinity ;
263 pMax = -kInfinity ;
264
265 // Calculate rotated vertex coordinates
266
267 vertices = CreateRotatedVertices(pTransform) ;
268 ClipCrossSection(vertices,0,pVoxelLimit,pAxis,pMin,pMax) ;
269 ClipCrossSection(vertices,4,pVoxelLimit,pAxis,pMin,pMax) ;
270 ClipBetweenSections(vertices,0,pVoxelLimit,pAxis,pMin,pMax) ;
271
272 if (pVoxelLimit.IsLimited(pAxis) == false)
273 {
274 if ( (pMin != kInfinity) || (pMax != -kInfinity) )
275 {
276 existsAfterClip = true ;
277
278 // Add 2*tolerance to avoid precision troubles
279
280 pMin -= kCarTolerance;
281 pMax += kCarTolerance;
282 }
283 }
284 else
285 {
286 G4ThreeVector clipCentre(
287 ( pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
288 ( pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
289 ( pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5);
290
291 if ( (pMin != kInfinity) || (pMax != -kInfinity) )
292 {
293 existsAfterClip = true ;
294
295
296 // Check to see if endpoints are in the solid
297
298 clipCentre(pAxis) = pVoxelLimit.GetMinExtent(pAxis);
299
300 if (Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside)
301 {
302 pMin = pVoxelLimit.GetMinExtent(pAxis);
303 }
304 else
305 {
306 pMin -= kCarTolerance;
307 }
308 clipCentre(pAxis) = pVoxelLimit.GetMaxExtent(pAxis);
309
310 if (Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside)
311 {
312 pMax = pVoxelLimit.GetMaxExtent(pAxis);
313 }
314 else
315 {
316 pMax += kCarTolerance;
317 }
318 }
319
320 // Check for case where completely enveloping clipping volume
321 // If point inside then we are confident that the solid completely
322 // envelopes the clipping volume. Hence set min/max extents according
323 // to clipping volume extents along the specified axis.
324
325 else if (Inside(pTransform.Inverse().TransformPoint(clipCentre))
326 != kOutside)
327 {
328 existsAfterClip = true ;
329 pMin = pVoxelLimit.GetMinExtent(pAxis) ;
330 pMax = pVoxelLimit.GetMaxExtent(pAxis) ;
331 }
332 }
333 delete vertices;
334 return existsAfterClip;
335 }
336}
337
338/////////////////////////////////////////////////////////////////////////
339//
340// Return whether point inside/outside/on surface, using tolerance
341
342EInside G4Box::Inside(const G4ThreeVector& p) const
343{
344 static const G4double delta=0.5*kCarTolerance;
345 EInside in = kOutside ;
346 G4ThreeVector q(std::fabs(p.x()), std::fabs(p.y()), std::fabs(p.z()));
347
348 if ( q.x() <= (fDx - delta) )
349 {
350 if (q.y() <= (fDy - delta) )
351 {
352 if ( q.z() <= (fDz - delta) ) { in = kInside ; }
353 else if ( q.z() <= (fDz + delta) ) { in = kSurface ; }
354 }
355 else if ( q.y() <= (fDy + delta) )
356 {
357 if ( q.z() <= (fDz + delta) ) { in = kSurface ; }
358 }
359 }
360 else if ( q.x() <= (fDx + delta) )
361 {
362 if ( q.y() <= (fDy + delta) )
363 {
364 if ( q.z() <= (fDz + delta) ) { in = kSurface ; }
365 }
366 }
367 return in ;
368}
369
370///////////////////////////////////////////////////////////////////////
371//
372// Calculate side nearest to p, and return normal
373// If two sides are equidistant, normal of first side (x/y/z)
374// encountered returned
375
376G4ThreeVector G4Box::SurfaceNormal( const G4ThreeVector& p) const
377{
378 G4double distx, disty, distz ;
379 G4ThreeVector norm(0.,0.,0.);
380
381 // Calculate distances as if in 1st octant
382
383 distx = std::fabs(std::fabs(p.x()) - fDx) ;
384 disty = std::fabs(std::fabs(p.y()) - fDy) ;
385 distz = std::fabs(std::fabs(p.z()) - fDz) ;
386
387 // New code for particle on surface including edges and corners with specific
388 // normals
389
390 static const G4double delta = 0.5*kCarTolerance;
391 const G4ThreeVector nX = G4ThreeVector( 1.0, 0,0 );
392 const G4ThreeVector nmX = G4ThreeVector(-1.0, 0,0 );
393 const G4ThreeVector nY = G4ThreeVector( 0, 1.0,0 );
394 const G4ThreeVector nmY = G4ThreeVector( 0,-1.0,0 );
395 const G4ThreeVector nZ = G4ThreeVector( 0, 0, 1.0);
396 const G4ThreeVector nmZ = G4ThreeVector( 0, 0,- 1.0);
397
398 G4ThreeVector normX(0.,0.,0.), normY(0.,0.,0.), normZ(0.,0.,0.);
399 G4ThreeVector sumnorm(0., 0., 0.);
400 G4int noSurfaces=0;
401
402 if (distx <= delta) // on X/mX surface and around
403 {
404 noSurfaces ++;
405 if ( p.x() >= 0. ) { normX= nX ; } // on +X surface : (1,0,0)
406 else { normX= nmX; } // (-1,0,0)
407 sumnorm= normX;
408 }
409
410 if (disty <= delta) // on one of the +Y or -Y surfaces
411 {
412 noSurfaces ++;
413 if ( p.y() >= 0. ) { normY= nY; } // on +Y surface
414 else { normY= nmY; }
415 sumnorm += normY;
416 }
417
418 if (distz <= delta) // on one of the +Z or -Z surfaces
419 {
420 noSurfaces ++;
421 if ( p.z() >= 0. ) { normZ= nZ; } // on +Z surface
422 else { normZ= nmZ; }
423 sumnorm += normZ;
424 }
425
426 static const G4double invSqrt2 = 1.0 / std::sqrt(2.0);
427 static const G4double invSqrt3 = 1.0 / std::sqrt(3.0);
428
429 if( noSurfaces > 0 )
430 {
431 if( noSurfaces == 1 )
432 {
433 norm= sumnorm;
434 }
435 else
436 {
437 // norm = sumnorm . unit();
438 if( noSurfaces == 2 )
439 {
440 // 2 surfaces -> on edge
441 norm = invSqrt2 * sumnorm;
442 }
443 else
444 {
445 // 3 surfaces (on corner)
446 norm = invSqrt3 * sumnorm;
447 }
448 }
449 }
450 else
451 {
452#ifdef G4CSGDEBUG
453 G4Exception("G4Box::SurfaceNormal(p)", "Notification", JustWarning,
454 "Point p is not on surface !?" );
455#endif
456 norm = ApproxSurfaceNormal(p);
457 }
458
459 return norm;
460}
461
462//////////////////////////////////////////////////////////////////////////
463//
464// Algorithm for SurfaceNormal() following the original specification
465// for points not on the surface
466
467G4ThreeVector G4Box::ApproxSurfaceNormal( const G4ThreeVector& p ) const
468{
469 G4double distx, disty, distz ;
470 G4ThreeVector norm(0.,0.,0.);
471
472 // Calculate distances as if in 1st octant
473
474 distx = std::fabs(std::fabs(p.x()) - fDx) ;
475 disty = std::fabs(std::fabs(p.y()) - fDy) ;
476 distz = std::fabs(std::fabs(p.z()) - fDz) ;
477
478 if ( distx <= disty )
479 {
480 if ( distx <= distz ) // Closest to X
481 {
482 if ( p.x() < 0 ) { norm = G4ThreeVector(-1.0,0,0) ; }
483 else { norm = G4ThreeVector( 1.0,0,0) ; }
484 }
485 else // Closest to Z
486 {
487 if ( p.z() < 0 ) { norm = G4ThreeVector(0,0,-1.0) ; }
488 else { norm = G4ThreeVector(0,0, 1.0) ; }
489 }
490 }
491 else
492 {
493 if ( disty <= distz ) // Closest to Y
494 {
495 if ( p.y() < 0 ) { norm = G4ThreeVector(0,-1.0,0) ; }
496 else { norm = G4ThreeVector(0, 1.0,0) ; }
497 }
498 else // Closest to Z
499 {
500 if ( p.z() < 0 ) { norm = G4ThreeVector(0,0,-1.0) ; }
501 else { norm = G4ThreeVector(0,0, 1.0) ; }
502 }
503 }
504 return norm;
505}
506
507///////////////////////////////////////////////////////////////////////////
508//
509// Calculate distance to box from an outside point
510// - return kInfinity if no intersection.
511//
512// ALGORITHM:
513//
514// Check that if point lies outside x/y/z extent of box, travel is towards
515// the box (ie. there is a possibility of an intersection)
516//
517// Calculate pairs of minimum and maximum distances for x/y/z travel for
518// intersection with the box's x/y/z extent.
519// If there is a valid intersection, it is given by the maximum min distance
520// (ie. distance to satisfy x/y/z intersections) *if* <= minimum max distance
521// (ie. distance after which 1+ of x/y/z intersections not satisfied)
522//
523// NOTE:
524//
525// `Inside' safe - meaningful answers given if point is inside the exact
526// shape.
527
528G4double G4Box::DistanceToIn(const G4ThreeVector& p,
529 const G4ThreeVector& v) const
530{
531 G4double safx, safy, safz ;
532 G4double smin=0.0, sminy, sminz ; // , sminx ;
533 G4double smax=kInfinity, smaxy, smaxz ; // , smaxx ; // they always > 0
534 G4double stmp ;
535 G4double sOut=kInfinity, sOuty=kInfinity, sOutz=kInfinity ;
536
537 static const G4double delta = 0.5*kCarTolerance;
538
539 safx = std::fabs(p.x()) - fDx ; // minimum distance to x surface of shape
540 safy = std::fabs(p.y()) - fDy ;
541 safz = std::fabs(p.z()) - fDz ;
542
543 // Will we intersect?
544 // If safx/y/z is >-tol/2 the point is outside/on the box's x/y/z extent.
545 // If both p.x/y/z and v.x/y/z repectively are both positive/negative,
546 // travel is in a direction away from the shape.
547
548 if ( ((p.x()*v.x() >= 0.0) && (safx > -delta))
549 || ((p.y()*v.y() >= 0.0) && (safy > -delta))
550 || ((p.z()*v.z() >= 0.0) && (safz > -delta)) )
551 {
552 return kInfinity ; // travel away or parallel within tolerance
553 }
554
555 // Compute min / max distances for x/y/z travel:
556 // X Planes
557
558 if ( v.x() ) // != 0
559 {
560 stmp = 1.0/std::fabs(v.x()) ;
561
562 if (safx >= 0.0)
563 {
564 smin = safx*stmp ;
565 smax = (fDx+std::fabs(p.x()))*stmp ;
566 }
567 else
568 {
569 if (v.x() < 0) { sOut = (fDx + p.x())*stmp ; }
570 else { sOut = (fDx - p.x())*stmp ; }
571 }
572 }
573
574 // Y Planes
575
576 if ( v.y() ) // != 0
577 {
578 stmp = 1.0/std::fabs(v.y()) ;
579
580 if (safy >= 0.0)
581 {
582 sminy = safy*stmp ;
583 smaxy = (fDy+std::fabs(p.y()))*stmp ;
584
585 if (sminy > smin) { smin=sminy ; }
586 if (smaxy < smax) { smax=smaxy ; }
587
588 if (smin >= (smax-delta))
589 {
590 return kInfinity ; // touch XY corner
591 }
592 }
593 else
594 {
595 if (v.y() < 0) { sOuty = (fDy + p.y())*stmp ; }
596 else { sOuty = (fDy - p.y())*stmp ; }
597 if( sOuty < sOut ) { sOut = sOuty ; }
598 }
599 }
600
601 // Z planes
602
603 if ( v.z() ) // != 0
604 {
605 stmp = 1.0/std::fabs(v.z()) ;
606
607 if ( safz >= 0.0 )
608 {
609 sminz = safz*stmp ;
610 smaxz = (fDz+std::fabs(p.z()))*stmp ;
611
612 if (sminz > smin) { smin = sminz ; }
613 if (smaxz < smax) { smax = smaxz ; }
614
615 if (smin >= (smax-delta))
616 {
617 return kInfinity ; // touch ZX or ZY corners
618 }
619 }
620 else
621 {
622 if (v.z() < 0) { sOutz = (fDz + p.z())*stmp ; }
623 else { sOutz = (fDz - p.z())*stmp ; }
624 if( sOutz < sOut ) { sOut = sOutz ; }
625 }
626 }
627
628 if (sOut <= (smin + delta)) // travel over edge
629 {
630 return kInfinity ;
631 }
632 if (smin < delta) { smin = 0.0 ; }
633
634 return smin ;
635}
636
637//////////////////////////////////////////////////////////////////////////
638//
639// Appoximate distance to box.
640// Returns largest perpendicular distance to the closest x/y/z sides of
641// the box, which is the most fast estimation of the shortest distance to box
642// - If inside return 0
643
644G4double G4Box::DistanceToIn(const G4ThreeVector& p) const
645{
646 G4double safex, safey, safez, safe = 0.0 ;
647
648 safex = std::fabs(p.x()) - fDx ;
649 safey = std::fabs(p.y()) - fDy ;
650 safez = std::fabs(p.z()) - fDz ;
651
652 if (safex > safe) { safe = safex ; }
653 if (safey > safe) { safe = safey ; }
654 if (safez > safe) { safe = safez ; }
655
656 return safe ;
657}
658
659/////////////////////////////////////////////////////////////////////////
660//
661// Calculate distance to surface of box from inside
662// by calculating distances to box's x/y/z planes.
663// Smallest distance is exact distance to exiting.
664// - Eliminate one side of each pair by considering direction of v
665// - when leaving a surface & v.close, return 0
666
667G4double G4Box::DistanceToOut( const G4ThreeVector& p,const G4ThreeVector& v,
668 const G4bool calcNorm,
669 G4bool *validNorm,G4ThreeVector *n) const
670{
671 ESide side = kUndefined ;
672 G4double pdist,stmp,snxt=kInfinity;
673
674 static const G4double delta = 0.5*kCarTolerance;
675
676 if (calcNorm) { *validNorm = true ; } // All normals are valid
677
678 if (v.x() > 0) // X planes
679 {
680 pdist = fDx - p.x() ;
681
682 if (pdist > delta)
683 {
684 snxt = pdist/v.x() ;
685 side = kPX ;
686 }
687 else
688 {
689 if (calcNorm) { *n = G4ThreeVector(1,0,0) ; }
690 return snxt = 0 ;
691 }
692 }
693 else if (v.x() < 0)
694 {
695 pdist = fDx + p.x() ;
696
697 if (pdist > delta)
698 {
699 snxt = -pdist/v.x() ;
700 side = kMX ;
701 }
702 else
703 {
704 if (calcNorm) { *n = G4ThreeVector(-1,0,0) ; }
705 return snxt = 0 ;
706 }
707 }
708
709 if (v.y() > 0) // Y planes
710 {
711 pdist = fDy-p.y();
712
713 if (pdist > delta)
714 {
715 stmp = pdist/v.y();
716
717 if (stmp < snxt)
718 {
719 snxt = stmp;
720 side = kPY;
721 }
722 }
723 else
724 {
725 if (calcNorm) { *n = G4ThreeVector(0,1,0) ; }
726 return snxt = 0 ;
727 }
728 }
729 else if (v.y() < 0)
730 {
731 pdist = fDy + p.y() ;
732
733 if (pdist > delta)
734 {
735 stmp = -pdist/v.y();
736
737 if ( stmp < snxt )
738 {
739 snxt = stmp;
740 side = kMY;
741 }
742 }
743 else
744 {
745 if (calcNorm) { *n = G4ThreeVector(0,-1,0) ; }
746 return snxt = 0 ;
747 }
748 }
749
750 if (v.z() > 0) // Z planes
751 {
752 pdist = fDz-p.z();
753
754 if ( pdist > delta )
755 {
756 stmp = pdist/v.z();
757
758 if ( stmp < snxt )
759 {
760 snxt = stmp;
761 side = kPZ;
762 }
763 }
764 else
765 {
766 if (calcNorm) { *n = G4ThreeVector(0,0,1) ; }
767 return snxt = 0 ;
768 }
769 }
770 else if (v.z() < 0)
771 {
772 pdist = fDz + p.z();
773
774 if ( pdist > delta )
775 {
776 stmp = -pdist/v.z();
777
778 if ( stmp < snxt )
779 {
780 snxt = stmp;
781 side = kMZ;
782 }
783 }
784 else
785 {
786 if (calcNorm) { *n = G4ThreeVector(0,0,-1) ; }
787 return snxt = 0 ;
788 }
789 }
790
791 if (calcNorm)
792 {
793 switch (side)
794 {
795 case kPX:
796 *n=G4ThreeVector(1,0,0);
797 break;
798 case kMX:
799 *n=G4ThreeVector(-1,0,0);
800 break;
801 case kPY:
802 *n=G4ThreeVector(0,1,0);
803 break;
804 case kMY:
805 *n=G4ThreeVector(0,-1,0);
806 break;
807 case kPZ:
808 *n=G4ThreeVector(0,0,1);
809 break;
810 case kMZ:
811 *n=G4ThreeVector(0,0,-1);
812 break;
813 default:
814 G4cout.precision(16);
815 G4cout << G4endl;
816 DumpInfo();
817 G4cout << "Position:" << G4endl << G4endl;
818 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
819 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
820 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
821 G4cout << "Direction:" << G4endl << G4endl;
822 G4cout << "v.x() = " << v.x() << G4endl;
823 G4cout << "v.y() = " << v.y() << G4endl;
824 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
825 G4cout << "Proposed distance :" << G4endl << G4endl;
826 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl;
827 G4Exception("G4Box::DistanceToOut(p,v,..)","Notification",JustWarning,
828 "Undefined side for valid surface normal to solid.");
829 break;
830 }
831 }
832 return snxt;
833}
834
835////////////////////////////////////////////////////////////////////////////
836//
837// Calculate exact shortest distance to any boundary from inside
838// - If outside return 0
839
840G4double G4Box::DistanceToOut(const G4ThreeVector& p) const
841{
842 G4double safx1,safx2,safy1,safy2,safz1,safz2,safe=0.0;
843
844#ifdef G4CSGDEBUG
845 if( Inside(p) == kOutside )
846 {
847 G4cout.precision(16) ;
848 G4cout << G4endl ;
849 DumpInfo();
850 G4cout << "Position:" << G4endl << G4endl ;
851 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
852 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
853 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
854 G4Exception("G4Box::DistanceToOut(p)", "Notification", JustWarning,
855 "Point p is outside !?" );
856 }
857#endif
858
859 safx1 = fDx - p.x() ;
860 safx2 = fDx + p.x() ;
861 safy1 = fDy - p.y() ;
862 safy2 = fDy + p.y() ;
863 safz1 = fDz - p.z() ;
864 safz2 = fDz + p.z() ;
865
866 // shortest Dist to any boundary now MIN(safx1,safx2,safy1..)
867
868 if (safx2 < safx1) { safe = safx2; }
869 else { safe = safx1; }
870 if (safy1 < safe) { safe = safy1; }
871 if (safy2 < safe) { safe = safy2; }
872 if (safz1 < safe) { safe = safz1; }
873 if (safz2 < safe) { safe = safz2; }
874
875 if (safe < 0) { safe = 0 ; }
876 return safe ;
877}
878
879////////////////////////////////////////////////////////////////////////
880//
881// Create a List containing the transformed vertices
882// Ordering [0-3] -fDz cross section
883// [4-7] +fDz cross section such that [0] is below [4],
884// [1] below [5] etc.
885// Note:
886// Caller has deletion resposibility
887
888G4ThreeVectorList*
889G4Box::CreateRotatedVertices(const G4AffineTransform& pTransform) const
890{
891 G4ThreeVectorList* vertices = new G4ThreeVectorList();
892 vertices->reserve(8);
893
894 if (vertices)
895 {
896 G4ThreeVector vertex0(-fDx,-fDy,-fDz) ;
897 G4ThreeVector vertex1(fDx,-fDy,-fDz) ;
898 G4ThreeVector vertex2(fDx,fDy,-fDz) ;
899 G4ThreeVector vertex3(-fDx,fDy,-fDz) ;
900 G4ThreeVector vertex4(-fDx,-fDy,fDz) ;
901 G4ThreeVector vertex5(fDx,-fDy,fDz) ;
902 G4ThreeVector vertex6(fDx,fDy,fDz) ;
903 G4ThreeVector vertex7(-fDx,fDy,fDz) ;
904
905 vertices->push_back(pTransform.TransformPoint(vertex0));
906 vertices->push_back(pTransform.TransformPoint(vertex1));
907 vertices->push_back(pTransform.TransformPoint(vertex2));
908 vertices->push_back(pTransform.TransformPoint(vertex3));
909 vertices->push_back(pTransform.TransformPoint(vertex4));
910 vertices->push_back(pTransform.TransformPoint(vertex5));
911 vertices->push_back(pTransform.TransformPoint(vertex6));
912 vertices->push_back(pTransform.TransformPoint(vertex7));
913 }
914 else
915 {
916 DumpInfo();
917 G4Exception("G4Box::CreateRotatedVertices()",
918 "FatalError", FatalException,
919 "Error in allocation of vertices. Out of memory !");
920 }
921 return vertices;
922}
923
924//////////////////////////////////////////////////////////////////////////
925//
926// GetEntityType
927
928G4GeometryType G4Box::GetEntityType() const
929{
930 return G4String("G4Box");
931}
932
933//////////////////////////////////////////////////////////////////////////
934//
935// Stream object contents to an output stream
936
937std::ostream& G4Box::StreamInfo(std::ostream& os) const
938{
939 os << "-----------------------------------------------------------\n"
940 << " *** Dump for solid - " << GetName() << " ***\n"
941 << " ===================================================\n"
942 << " Solid type: G4Box\n"
943 << " Parameters: \n"
944 << " half length X: " << fDx/mm << " mm \n"
945 << " half length Y: " << fDy/mm << " mm \n"
946 << " half length Z: " << fDz/mm << " mm \n"
947 << "-----------------------------------------------------------\n";
948
949 return os;
950}
951
952/////////////////////////////////////////////////////////////////////////////////////
953//
954// GetPointOnSurface
955//
956// Return a point (G4ThreeVector) randomly and uniformly selected
957// on the solid surface
958
959G4ThreeVector G4Box::GetPointOnSurface() const
960{
961 G4double px, py, pz, select, sumS;
962 G4double Sxy = fDx*fDy, Sxz = fDx*fDz, Syz = fDy*fDz;
963
964 sumS = Sxy + Sxz + Syz;
965 select = sumS*G4UniformRand();
966
967 if( select < Sxy )
968 {
969 px = -fDx +2*fDx*G4UniformRand();
970 py = -fDy +2*fDy*G4UniformRand();
971
972 if(G4UniformRand() > 0.5) { pz = fDz; }
973 else { pz = -fDz; }
974 }
975 else if ( ( select - Sxy ) < Sxz )
976 {
977 px = -fDx +2*fDx*G4UniformRand();
978 pz = -fDz +2*fDz*G4UniformRand();
979
980 if(G4UniformRand() > 0.5) { py = fDy; }
981 else { py = -fDy; }
982 }
983 else
984 {
985 py = -fDy +2*fDy*G4UniformRand();
986 pz = -fDz +2*fDz*G4UniformRand();
987
988 if(G4UniformRand() > 0.5) { px = fDx; }
989 else { px = -fDx; }
990 }
991 return G4ThreeVector(px,py,pz);
992}
993
994//////////////////////////////////////////////////////////////////////////
995//
996// Methods for visualisation
997
998void G4Box::DescribeYourselfTo (G4VGraphicsScene& scene) const
999{
1000 scene.AddSolid (*this);
1001}
1002
1003G4VisExtent G4Box::GetExtent() const
1004{
1005 return G4VisExtent (-fDx, fDx, -fDy, fDy, -fDz, fDz);
1006}
1007
1008G4Polyhedron* G4Box::CreatePolyhedron () const
1009{
1010 return new G4PolyhedronBox (fDx, fDy, fDz);
1011}
1012
1013G4NURBS* G4Box::CreateNURBS () const
1014{
1015 return new G4NURBSbox (fDx, fDy, fDz);
1016}
Note: See TracBrowser for help on using the repository browser.