source: trunk/source/geometry/solids/CSG/src/G4Box.cc @ 1315

Last change on this file since 1315 was 1315, checked in by garnier, 14 years ago

update geant4-09-04-beta-cand-01 interfaces-V09-03-09 vis-V09-03-08

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-cand-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.