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

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

geant4.8.2 beta

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