ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4Box.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4Box.cc
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 // Implementation for G4Box class
27 //
28 // 30.06.95 - P.Kent: First version
29 // 20.09.98 - V.Grichine: new algorithm of DistanceToIn(p,v)
30 // 18.04.17 - E.Tcherniaev: complete revision, speed-up
31 // --------------------------------------------------------------------
32 
33 #include "G4Box.hh"
34 
35 #if !defined(G4GEOM_USE_UBOX)
36 
37 #include "G4SystemOfUnits.hh"
38 #include "G4VoxelLimits.hh"
39 #include "G4AffineTransform.hh"
40 #include "G4BoundingEnvelope.hh"
41 #include "Randomize.hh"
42 
43 #include "G4VPVParameterisation.hh"
44 
45 #include "G4VGraphicsScene.hh"
46 #include "G4VisExtent.hh"
47 
49 //
50 // Constructor - check & set half widths
51 
52 G4Box::G4Box(const G4String& pName,
53  G4double pX,
54  G4double pY,
55  G4double pZ)
56  : G4CSGSolid(pName), fDx(pX), fDy(pY), fDz(pZ)
57 {
58  delta = 0.5*kCarTolerance;
59  if (pX < 2*kCarTolerance ||
60  pY < 2*kCarTolerance ||
61  pZ < 2*kCarTolerance) // limit to thickness of surfaces
62  {
63  std::ostringstream message;
64  message << "Dimensions too small for Solid: " << GetName() << "!" << G4endl
65  << " hX, hY, hZ = " << pX << ", " << pY << ", " << pZ;
66  G4Exception("G4Box::G4Box()", "GeomSolids0002", FatalException, message);
67  }
68 }
69 
71 //
72 // Fake default constructor - sets only member data and allocates memory
73 // for usage restricted to object persistency
74 
75 G4Box::G4Box( __void__& a )
76  : G4CSGSolid(a), delta(0.)
77 {
78 }
79 
81 //
82 // Destructor
83 
85 {
86 }
87 
89 //
90 // Copy constructor
91 
92 G4Box::G4Box(const G4Box& rhs)
93  : G4CSGSolid(rhs), fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz), delta(rhs.delta)
94 {
95 }
96 
98 //
99 // Assignment operator
100 
102 {
103  // Check assignment to self
104  //
105  if (this == &rhs) { return *this; }
106 
107  // Copy base class data
108  //
110 
111  // Copy data
112  //
113  fDx = rhs.fDx;
114  fDy = rhs.fDy;
115  fDz = rhs.fDz;
116  delta = rhs.delta;
117 
118  return *this;
119 }
120 
122 //
123 // Set X dimension
124 
126 {
127  if(dx > 2*kCarTolerance) // limit to thickness of surfaces
128  {
129  fDx = dx;
130  }
131  else
132  {
133  std::ostringstream message;
134  message << "Dimension X too small for solid: " << GetName() << "!"
135  << G4endl
136  << " hX = " << dx;
137  G4Exception("G4Box::SetXHalfLength()", "GeomSolids0002",
138  FatalException, message);
139  }
140  fCubicVolume = 0.;
141  fSurfaceArea = 0.;
142  fRebuildPolyhedron = true;
143 }
144 
146 //
147 // Set Y dimension
148 
150 {
151  if(dy > 2*kCarTolerance) // limit to thickness of surfaces
152  {
153  fDy = dy;
154  }
155  else
156  {
157  std::ostringstream message;
158  message << "Dimension Y too small for solid: " << GetName() << "!\n"
159  << " hY = " << dy;
160  G4Exception("G4Box::SetYHalfLength()", "GeomSolids0002",
161  FatalException, message);
162  }
163  fCubicVolume = 0.;
164  fSurfaceArea = 0.;
165  fRebuildPolyhedron = true;
166 }
167 
169 //
170 // Set Z dimension
171 
173 {
174  if(dz > 2*kCarTolerance) // limit to thickness of surfaces
175  {
176  fDz = dz;
177  }
178  else
179  {
180  std::ostringstream message;
181  message << "Dimension Z too small for solid: " << GetName() << "!\n"
182  << " hZ = " << dz;
183  G4Exception("G4Box::SetZHalfLength()", "GeomSolids0002",
184  FatalException, message);
185  }
186  fCubicVolume = 0.;
187  fSurfaceArea = 0.;
188  fRebuildPolyhedron = true;
189 }
190 
192 //
193 // Dispatch to parameterisation for replication mechanism dimension
194 // computation & modification.
195 
197  const G4int n,
198  const G4VPhysicalVolume* pRep)
199 {
200  p->ComputeDimensions(*this,n,pRep);
201 }
202 
204 //
205 // Get bounding box
206 
208 {
209  pMin.set(-fDx,-fDy,-fDz);
210  pMax.set( fDx, fDy, fDz);
211 
212  // Check correctness of the bounding box
213  //
214  if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
215  {
216  std::ostringstream message;
217  message << "Bad bounding box (min >= max) for solid: "
218  << GetName() << " !"
219  << "\npMin = " << pMin
220  << "\npMax = " << pMax;
221  G4Exception("G4Box::BoundingLimits()", "GeomMgt0001", JustWarning, message);
222  DumpInfo();
223  }
224 }
225 
227 //
228 // Calculate extent under transform and specified limit
229 
231  const G4VoxelLimits& pVoxelLimit,
232  const G4AffineTransform& pTransform,
233  G4double& pMin, G4double& pMax) const
234 {
235  G4ThreeVector bmin, bmax;
236 
237  // Get bounding box
238  BoundingLimits(bmin,bmax);
239 
240  // Find extent
241  G4BoundingEnvelope bbox(bmin,bmax);
242  return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
243 }
244 
246 //
247 // Return whether point inside/outside/on surface, using tolerance
248 
250 {
251  G4double dist = std::max(std::max(
252  std::abs(p.x())-fDx,
253  std::abs(p.y())-fDy),
254  std::abs(p.z())-fDz);
255  if (dist > delta) return kOutside;
256  return (dist > -delta) ? kSurface : kInside;
257 }
258 
260 //
261 // Detect the side(s) and return corresponding normal
262 
264 {
265  G4ThreeVector norm(0,0,0);
266  G4double px = p.x();
267  if (std::abs(std::abs(px) - fDx) <= delta) norm.setX(px < 0 ? -1. : 1.);
268  G4double py = p.y();
269  if (std::abs(std::abs(py) - fDy) <= delta) norm.setY(py < 0 ? -1. : 1.);
270  G4double pz = p.z();
271  if (std::abs(std::abs(pz) - fDz) <= delta) norm.setZ(pz < 0 ? -1. : 1.);
272 
273  G4double nside = norm.mag2(); // number of sides = magnitude squared
274  if (nside == 1)
275  return norm;
276  else if (nside > 1)
277  return norm.unit(); // edge or corner
278  else
279  {
280  // Point is not on the surface
281  //
282 #ifdef G4CSGDEBUG
283  std::ostringstream message;
284  G4int oldprc = message.precision(16);
285  message << "Point p is not on surface (!?) of solid: "
286  << GetName() << G4endl;
287  message << "Position:\n";
288  message << " p.x() = " << p.x()/mm << " mm\n";
289  message << " p.y() = " << p.y()/mm << " mm\n";
290  message << " p.z() = " << p.z()/mm << " mm";
291  G4cout.precision(oldprc);
292  G4Exception("G4Box::SurfaceNormal(p)", "GeomSolids1002",
293  JustWarning, message );
294  DumpInfo();
295 #endif
296  return ApproxSurfaceNormal(p);
297  }
298 }
299 
301 //
302 // Algorithm for SurfaceNormal() following the original specification
303 // for points not on the surface
304 
306 {
307  G4double distx = std::abs(p.x()) - fDx;
308  G4double disty = std::abs(p.y()) - fDy;
309  G4double distz = std::abs(p.z()) - fDz;
310 
311  if (distx >= disty && distx >= distz)
312  return G4ThreeVector(std::copysign(1.,p.x()), 0., 0.);
313  if (disty >= distx && disty >= distz)
314  return G4ThreeVector(0., std::copysign(1.,p.y()), 0.);
315  else
316  return G4ThreeVector(0., 0., std::copysign(1.,p.z()));
317 }
318 
320 //
321 // Calculate distance to box from an outside point
322 // - return kInfinity if no intersection
323 //
324 
326  const G4ThreeVector& v) const
327 {
328  // Check if point is on the surface and traveling away
329  //
330  if ((std::abs(p.x()) - fDx) >= -delta && p.x()*v.x() >= 0) return kInfinity;
331  if ((std::abs(p.y()) - fDy) >= -delta && p.y()*v.y() >= 0) return kInfinity;
332  if ((std::abs(p.z()) - fDz) >= -delta && p.z()*v.z() >= 0) return kInfinity;
333 
334  // Find intersection
335  //
336  G4double invx = (v.x() == 0) ? DBL_MAX : -1./v.x();
337  G4double dx = std::copysign(fDx,invx);
338  G4double txmin = (p.x() - dx)*invx;
339  G4double txmax = (p.x() + dx)*invx;
340 
341  G4double invy = (v.y() == 0) ? DBL_MAX : -1./v.y();
342  G4double dy = std::copysign(fDy,invy);
343  G4double tymin = std::max(txmin,(p.y() - dy)*invy);
344  G4double tymax = std::min(txmax,(p.y() + dy)*invy);
345 
346  G4double invz = (v.z() == 0) ? DBL_MAX : -1./v.z();
347  G4double dz = std::copysign(fDz,invz);
348  G4double tmin = std::max(tymin,(p.z() - dz)*invz);
349  G4double tmax = std::min(tymax,(p.z() + dz)*invz);
350 
351  if (tmax <= tmin + delta) return kInfinity; // touch or no hit
352  return (tmin < delta) ? 0. : tmin;
353 }
354 
356 //
357 // Appoximate distance to box.
358 // Returns largest perpendicular distance to the closest x/y/z sides of
359 // the box, which is the most fast estimation of the shortest distance to box
360 // - If inside return 0
361 
363 {
364  G4double dist = std::max(std::max(std::abs(p.x())-fDx,
365  std::abs(p.y())-fDy),
366  std::abs(p.z())-fDz);
367  return (dist > 0) ? dist : 0.;
368 }
369 
371 //
372 // Calculate distance to surface of the box from inside and
373 // find normal at exit point, if required
374 // - when leaving the surface, return 0
375 
377  const G4ThreeVector& v,
378  const G4bool calcNorm,
379  G4bool* validNorm, G4ThreeVector* n) const
380 {
381  // Check if point is on the surface and traveling away
382  //
383  if ((std::abs(p.x()) - fDx) >= -delta && p.x()*v.x() > 0)
384  {
385  if (calcNorm)
386  {
387  *validNorm = true;
388  n->set((p.x() < 0) ? -1. : 1., 0., 0.);
389  }
390  return 0.;
391  }
392  if ((std::abs(p.y()) - fDy) >= -delta && p.y()*v.y() > 0)
393  {
394  if (calcNorm)
395  {
396  *validNorm = true;
397  n->set(0., (p.y() < 0) ? -1. : 1., 0.);
398  }
399  return 0.;
400  }
401  if ((std::abs(p.z()) - fDz) >= -delta && p.z()*v.z() > 0)
402  {
403  if (calcNorm)
404  {
405  *validNorm = true;
406  n->set(0., 0., (p.z() < 0) ? -1. : 1.);
407  }
408  return 0.;
409  }
410 
411  // Find intersection
412  //
413  G4double vx = v.x();
414  G4double tx = (vx == 0) ? DBL_MAX : (std::copysign(fDx,vx) - p.x())/vx;
415 
416  G4double vy = v.y();
417  G4double ty = (vy == 0) ? tx : (std::copysign(fDy,vy) - p.y())/vy;
418  G4double txy = std::min(tx,ty);
419 
420  G4double vz = v.z();
421  G4double tz = (vz == 0) ? txy : (std::copysign(fDz,vz) - p.z())/vz;
422  G4double tmax = std::min(txy,tz);
423 
424  // Set normal, if required, and return distance
425  //
426  if (calcNorm)
427  {
428  *validNorm = true;
429  if (tmax == tx) n->set((v.x() < 0) ? -1. : 1., 0., 0.);
430  else if (tmax == ty) n->set(0., (v.y() < 0) ? -1. : 1., 0.);
431  else n->set(0., 0., (v.z() < 0) ? -1. : 1.);
432  }
433  return tmax;
434 }
435 
437 //
438 // Calculate exact shortest distance to any boundary from inside
439 // - if outside return 0
440 
442 {
443 #ifdef G4CSGDEBUG
444  if( Inside(p) == kOutside )
445  {
446  std::ostringstream message;
447  G4int oldprc = message.precision(16);
448  message << "Point p is outside (!?) of solid: " << GetName() << G4endl;
449  message << "Position:\n";
450  message << " p.x() = " << p.x()/mm << " mm\n";
451  message << " p.y() = " << p.y()/mm << " mm\n";
452  message << " p.z() = " << p.z()/mm << " mm";
453  G4cout.precision(oldprc);
454  G4Exception("G4Box::DistanceToOut(p)", "GeomSolids1002",
455  JustWarning, message );
456  DumpInfo();
457  }
458 #endif
459  G4double dist = std::min(std::min(fDx-std::abs(p.x()),
460  fDy-std::abs(p.y())),
461  fDz-std::abs(p.z()));
462  return (dist > 0) ? dist : 0.;
463 }
464 
466 //
467 // GetEntityType
468 
470 {
471  return G4String("G4Box");
472 }
473 
475 //
476 // Stream object contents to an output stream
477 
478 std::ostream& G4Box::StreamInfo(std::ostream& os) const
479 {
480  G4int oldprc = os.precision(16);
481  os << "-----------------------------------------------------------\n"
482  << " *** Dump for solid - " << GetName() << " ***\n"
483  << " ===================================================\n"
484  << "Solid type: G4Box\n"
485  << "Parameters: \n"
486  << " half length X: " << fDx/mm << " mm \n"
487  << " half length Y: " << fDy/mm << " mm \n"
488  << " half length Z: " << fDz/mm << " mm \n"
489  << "-----------------------------------------------------------\n";
490  os.precision(oldprc);
491  return os;
492 }
493 
495 //
496 // GetPointOnSurface
497 //
498 // Return a point (G4ThreeVector) randomly and uniformly selected
499 // on the solid surface
500 
502 {
503  G4double sxy = fDx*fDy, sxz = fDx*fDz, syz = fDy*fDz;
504  G4double select = (sxy + sxz + syz)*G4UniformRand();
505 
506  if (select < sxy)
507  return G4ThreeVector((2.*G4UniformRand() - 1.)*fDx,
508  (2.*G4UniformRand() - 1.)*fDy,
509  (select < 0.5*sxy) ? -fDz : fDz);
510 
511  if (select < sxy + sxz)
512  return G4ThreeVector((2.*G4UniformRand() - 1.)*fDx,
513  (select < sxy + 0.5*sxz) ? -fDy : fDy,
514  (2.*G4UniformRand() - 1.)*fDz);
515  else
516  return G4ThreeVector((select < sxy + sxz + 0.5*syz) ? -fDx : fDx,
517  (2.*G4UniformRand() - 1.)*fDy,
518  (2.*G4UniformRand() - 1.)*fDz);
519 }
520 
522 //
523 // Make a clone of the object
524 //
526 {
527  return new G4Box(*this);
528 }
529 
531 //
532 // Methods for visualisation
533 
535 {
536  scene.AddSolid (*this);
537 }
538 
540 {
541  return G4VisExtent (-fDx, fDx, -fDy, fDy, -fDz, fDz);
542 }
543 
545 {
546  return new G4PolyhedronBox (fDx, fDy, fDz);
547 }
548 #endif