Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Box.cc
Go to the documentation of this file.
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 "G4QuickRand.hh"
42
44
45#include "G4VGraphicsScene.hh"
46#include "G4VisExtent.hh"
47#include "G4AutoLock.hh"
48
49namespace
50{
52}
53
54////////////////////////////////////////////////////////////////////////
55//
56// Constructor - check & set half widths
57
59 G4double pX,
60 G4double pY,
61 G4double pZ)
62 : G4CSGSolid(pName), fDx(pX), fDy(pY), fDz(pZ)
63{
64 delta = 0.5*kCarTolerance;
65 if (pX < 2*kCarTolerance ||
66 pY < 2*kCarTolerance ||
67 pZ < 2*kCarTolerance) // limit to thickness of surfaces
68 {
69 std::ostringstream message;
70 message << "Dimensions too small for Solid: " << GetName() << "!" << G4endl
71 << " hX, hY, hZ = " << pX << ", " << pY << ", " << pZ;
72 G4Exception("G4Box::G4Box()", "GeomSolids0002", FatalException, message);
73 }
74}
75
76//////////////////////////////////////////////////////////////////////////
77//
78// Fake default constructor - sets only member data and allocates memory
79// for usage restricted to object persistency
80
81G4Box::G4Box( __void__& a )
82 : G4CSGSolid(a)
83{
84}
85
86//////////////////////////////////////////////////////////////////////////
87//
88// Assignment operator
89
91{
92 // Check assignment to self
93 //
94 if (this == &rhs) { return *this; }
95
96 // Copy base class data
97 //
99
100 // Copy data
101 //
102 fDx = rhs.fDx;
103 fDy = rhs.fDy;
104 fDz = rhs.fDz;
105 delta = rhs.delta;
106
107 return *this;
108}
109
110//////////////////////////////////////////////////////////////////////////
111//
112// Set X dimension
113
115{
116 if(dx > 2*kCarTolerance) // limit to thickness of surfaces
117 {
118 fDx = dx;
119 }
120 else
121 {
122 std::ostringstream message;
123 message << "Dimension X too small for solid: " << GetName() << "!"
124 << G4endl
125 << " hX = " << dx;
126 G4Exception("G4Box::SetXHalfLength()", "GeomSolids0002",
127 FatalException, message);
128 }
129 fCubicVolume = 0.;
130 fSurfaceArea = 0.;
131 fRebuildPolyhedron = true;
132}
133
134//////////////////////////////////////////////////////////////////////////
135//
136// Set Y dimension
137
139{
140 if(dy > 2*kCarTolerance) // limit to thickness of surfaces
141 {
142 fDy = dy;
143 }
144 else
145 {
146 std::ostringstream message;
147 message << "Dimension Y too small for solid: " << GetName() << "!\n"
148 << " hY = " << dy;
149 G4Exception("G4Box::SetYHalfLength()", "GeomSolids0002",
150 FatalException, message);
151 }
152 fCubicVolume = 0.;
153 fSurfaceArea = 0.;
154 fRebuildPolyhedron = true;
155}
156
157//////////////////////////////////////////////////////////////////////////
158//
159// Set Z dimension
160
162{
163 if(dz > 2*kCarTolerance) // limit to thickness of surfaces
164 {
165 fDz = dz;
166 }
167 else
168 {
169 std::ostringstream message;
170 message << "Dimension Z too small for solid: " << GetName() << "!\n"
171 << " hZ = " << dz;
172 G4Exception("G4Box::SetZHalfLength()", "GeomSolids0002",
173 FatalException, message);
174 }
175 fCubicVolume = 0.;
176 fSurfaceArea = 0.;
177 fRebuildPolyhedron = true;
178}
179
180//////////////////////////////////////////////////////////////////////////
181//
182// Dispatch to parameterisation for replication mechanism dimension
183// computation & modification.
184
186 const G4int n,
187 const G4VPhysicalVolume* pRep)
188{
189 p->ComputeDimensions(*this,n,pRep);
190}
191
192//////////////////////////////////////////////////////////////////////////
193//
194// Get bounding box
195
197{
198 pMin.set(-fDx,-fDy,-fDz);
199 pMax.set( fDx, fDy, fDz);
200
201 // Check correctness of the bounding box
202 //
203 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
204 {
205 std::ostringstream message;
206 message << "Bad bounding box (min >= max) for solid: "
207 << GetName() << " !"
208 << "\npMin = " << pMin
209 << "\npMax = " << pMax;
210 G4Exception("G4Box::BoundingLimits()", "GeomMgt0001", JustWarning, message);
211 DumpInfo();
212 }
213}
214
215//////////////////////////////////////////////////////////////////////////
216//
217// Calculate extent under transform and specified limit
218
220 const G4VoxelLimits& pVoxelLimit,
221 const G4AffineTransform& pTransform,
222 G4double& pMin, G4double& pMax) const
223{
224 G4ThreeVector bmin, bmax;
225
226 // Get bounding box
227 BoundingLimits(bmin,bmax);
228
229 // Find extent
230 G4BoundingEnvelope bbox(bmin,bmax);
231 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
232}
233
234//////////////////////////////////////////////////////////////////////////
235//
236// Return whether point inside/outside/on surface, using tolerance
237
239{
240 G4double dist = std::max(std::max(
241 std::abs(p.x())-fDx,
242 std::abs(p.y())-fDy),
243 std::abs(p.z())-fDz);
244 return (dist > delta) ? kOutside :
245 ((dist > -delta) ? kSurface : kInside);
246}
247
248//////////////////////////////////////////////////////////////////////////
249//
250// Detect the side(s) and return corresponding normal
251
253{
254 G4double px = p.x(), py = p.y(), pz = p.z();
255 G4ThreeVector norm(0.,0.,0.);
256 if (std::abs(std::abs(px)-fDx) <= delta) { norm.setX(std::copysign(1.,px)); }
257 if (std::abs(std::abs(py)-fDy) <= delta) { norm.setY(std::copysign(1.,py)); }
258 if (std::abs(std::abs(pz)-fDz) <= delta) { norm.setZ(std::copysign(1.,pz)); }
259
260 G4double nside = norm.mag2(); // number of sides = magnitude squared
261 if (nside == 1)
262 {
263 return norm;
264 }
265 if (nside > 1)
266 {
267 return norm.unit(); // edge or corner
268 }
269
270 // Point is not on the surface
271 //
272#ifdef G4CSGDEBUG
273 std::ostringstream message;
274 G4int oldprc = message.precision(16);
275 message << "Point p is not on surface (!?) of solid: "
276 << GetName() << G4endl;
277 message << "Position:\n";
278 message << " p.x() = " << p.x()/mm << " mm\n";
279 message << " p.y() = " << p.y()/mm << " mm\n";
280 message << " p.z() = " << p.z()/mm << " mm";
281 G4cout.precision(oldprc);
282 G4Exception("G4Box::SurfaceNormal(p)", "GeomSolids1002",
283 JustWarning, message );
284 DumpInfo();
285#endif
286
287 return ApproxSurfaceNormal(p);
288}
289
290//////////////////////////////////////////////////////////////////////////
291//
292// Algorithm for SurfaceNormal() following the original specification
293// for points not on the surface
294
295G4ThreeVector G4Box::ApproxSurfaceNormal(const G4ThreeVector& p) const
296{
297 G4double distx = std::abs(p.x()) - fDx;
298 G4double disty = std::abs(p.y()) - fDy;
299 G4double distz = std::abs(p.z()) - fDz;
300
301 if (distx >= disty && distx >= distz)
302 {
303 return {std::copysign(1.,p.x()), 0., 0.};
304 }
305 if (disty >= distx && disty >= distz)
306 {
307 return {0., std::copysign(1.,p.y()), 0.};
308 }
309
310 return {0., 0., std::copysign(1.,p.z())};
311}
312
313//////////////////////////////////////////////////////////////////////////
314//
315// Calculate distance to box from an outside point
316// - return kInfinity if no intersection
317//
318
320 const G4ThreeVector& v) const
321{
322 // Check if point is on the surface and traveling away
323 //
324 if ((std::abs(p.x())-fDx) >= -delta && p.x()*v.x() >= 0) { return kInfinity; }
325 if ((std::abs(p.y())-fDy) >= -delta && p.y()*v.y() >= 0) { return kInfinity; }
326 if ((std::abs(p.z())-fDz) >= -delta && p.z()*v.z() >= 0) { return kInfinity; }
327
328 // Find intersection
329 //
330 G4double invx = (v.x() == 0) ? DBL_MAX : -1./v.x();
331 G4double dx = std::copysign(fDx,invx);
332 G4double txmin = (p.x() - dx)*invx;
333 G4double txmax = (p.x() + dx)*invx;
334
335 G4double invy = (v.y() == 0) ? DBL_MAX : -1./v.y();
336 G4double dy = std::copysign(fDy,invy);
337 G4double tymin = std::max(txmin,(p.y() - dy)*invy);
338 G4double tymax = std::min(txmax,(p.y() + dy)*invy);
339
340 G4double invz = (v.z() == 0) ? DBL_MAX : -1./v.z();
341 G4double dz = std::copysign(fDz,invz);
342 G4double tmin = std::max(tymin,(p.z() - dz)*invz);
343 G4double tmax = std::min(tymax,(p.z() + dz)*invz);
344
345 if (tmax <= tmin + delta) { return kInfinity; } // touch or no hit
346
347 return (tmin < delta) ? 0. : tmin;
348}
349
350//////////////////////////////////////////////////////////////////////////
351//
352// Appoximate distance to box.
353// Returns largest perpendicular distance to the closest x/y/z sides of
354// the box, which is the most fast estimation of the shortest distance to box
355// - If inside return 0
356
358{
359 G4double dist = std::max(std::max(
360 std::abs(p.x())-fDx,
361 std::abs(p.y())-fDy),
362 std::abs(p.z())-fDz);
363 return (dist > 0) ? dist : 0.;
364}
365
366//////////////////////////////////////////////////////////////////////////
367//
368// Calculate distance to surface of the box from inside and
369// find normal at exit point, if required
370// - when leaving the surface, return 0
371
373 const G4ThreeVector& v,
374 const G4bool calcNorm,
375 G4bool* validNorm, G4ThreeVector* n) const
376{
377 G4double px = p.x(), vx = v.x();
378 G4double py = p.y(), vy = v.y();
379 G4double pz = p.z(), vz = v.z();
380
381 if (!calcNorm) // calculation of normal is not needed
382 {
383 if ((std::abs(px) - fDx) >= -delta && px*vx > 0) { return 0.; }
384 if ((std::abs(py) - fDy) >= -delta && py*vy > 0) { return 0.; }
385 if ((std::abs(pz) - fDz) >= -delta && pz*vz > 0) { return 0.; }
386 G4double tx = (vx == 0) ? DBL_MAX : (std::copysign(fDx,vx) - px)/vx;
387 G4double ty = (vy == 0) ? DBL_MAX : (std::copysign(fDy,vy) - py)/vy;
388 G4double tz = (vz == 0) ? DBL_MAX : (std::copysign(fDz,vz) - pz)/vz;
389 G4double tmax = std::min(std::min(tx,ty),tz);
390 return tmax;
391 }
392
393 *validNorm = true;
394 // Check if point is on the surface and traveling away
395 if ((std::abs(px) - fDx) >= -delta && px*vx > 0)
396 {
397 n->set(std::copysign(1.,px), 0., 0.);
398 return 0.;
399 }
400 if ((std::abs(py) - fDy) >= -delta && py*vy > 0)
401 {
402 n->set(0., std::copysign(1.,py), 0.);
403 return 0.;
404 }
405 if ((std::abs(pz) - fDz) >= -delta && pz*vz > 0)
406 {
407 n->set(0., 0., std::copysign(1.,pz));
408 return 0.;
409 }
410
411 // Find intersection
412 G4double tx = (vx == 0) ? DBL_MAX : (std::copysign(fDx,vx) - px)/vx;
413 G4double ty = (vy == 0) ? DBL_MAX : (std::copysign(fDy,vy) - py)/vy;
414 G4double tz = (vz == 0) ? DBL_MAX : (std::copysign(fDz,vz) - pz)/vz;
415 G4double tmax = std::min(std::min(tx, ty), tz);
416
417 // Find normal
418 G4bool pickZ = (tmax == tz);
419 G4bool pickX = (!pickZ) && (tmax == tx);
420 G4bool pickY = (!pickZ) && (!pickX);
421 G4double nz = std::copysign((G4double)pickZ, vz);
422 G4double nx = std::copysign((G4double)pickX, vx);
423 G4double ny = std::copysign((G4double)pickY, vy);
424 n->set(nx, ny, nz);
425 return tmax;
426}
427
428////////////////////////////////////////////////////////////////////////////
429//
430// Calculate exact shortest distance to any boundary from inside
431// - if outside return 0
432
434{
435#ifdef G4CSGDEBUG
436 if( Inside(p) == kOutside )
437 {
438 std::ostringstream message;
439 G4int oldprc = message.precision(16);
440 message << "Point p is outside (!?) of solid: " << GetName() << G4endl;
441 message << "Position:\n";
442 message << " p.x() = " << p.x()/mm << " mm\n";
443 message << " p.y() = " << p.y()/mm << " mm\n";
444 message << " p.z() = " << p.z()/mm << " mm";
445 G4cout.precision(oldprc);
446 G4Exception("G4Box::DistanceToOut(p)", "GeomSolids1002",
447 JustWarning, message );
448 DumpInfo();
449 }
450#endif
451 G4double dist = std::min(std::min(
452 fDx-std::abs(p.x()),
453 fDy-std::abs(p.y())),
454 fDz-std::abs(p.z()));
455 return (dist > 0) ? dist : 0.;
456}
457
458//////////////////////////////////////////////////////////////////////////
459//
460// GetEntityType
461
463{
464 return {"G4Box"};
465}
466
467//////////////////////////////////////////////////////////////////////////
468//
469// IsFaceted
470
472{
473 return true;
474}
475
476//////////////////////////////////////////////////////////////////////////
477//
478// Stream object contents to an output stream
479
480std::ostream& G4Box::StreamInfo(std::ostream& os) const
481{
482 G4long oldprc = os.precision(16);
483 os << "-----------------------------------------------------------\n"
484 << " *** Dump for solid - " << GetName() << " ***\n"
485 << " ===================================================\n"
486 << "Solid type: G4Box\n"
487 << "Parameters: \n"
488 << " half length X: " << fDx/mm << " mm \n"
489 << " half length Y: " << fDy/mm << " mm \n"
490 << " half length Z: " << fDz/mm << " mm \n"
491 << "-----------------------------------------------------------\n";
492 os.precision(oldprc);
493 return os;
494}
495
496//////////////////////////////////////////////////////////////////////////
497//
498// Return a point randomly and uniformly selected on the surface
499
501{
502 G4double sxy = fDx*fDy, sxz = fDx*fDz, syz = fDy*fDz;
503 G4double select = (sxy + sxz + syz)*G4QuickRand();
504 G4double u = 2.*G4QuickRand() - 1.;
505 G4double v = 2.*G4QuickRand() - 1.;
506
507 G4double x, y, z;
508 if (select < sxy)
509 {
510 x = u*fDx;
511 y = v*fDy;
512 z = (select < 0.5*sxy) ? -fDz : fDz;
513 }
514 else if (select < sxy + sxz)
515 {
516 x = u*fDx;
517 y = (select < sxy + 0.5*sxz) ? -fDy : fDy;
518 z = v*fDz;
519 }
520 else
521 {
522 x = (select < sxy + sxz + 0.5*syz) ? -fDx : fDx;
523 y = u*fDy;
524 z = v*fDz;
525 }
526 return { x, y, z };
527}
528
529//////////////////////////////////////////////////////////////////////////
530//
531// Computes/returns volume capacity
532//
534{
535 if (fCubicVolume == 0)
536 {
537 G4AutoLock l(&boxMutex);
538 fCubicVolume = 8*fDx*fDy*fDz;
539 l.unlock();
540 }
541 return fCubicVolume;
542}
543
544//////////////////////////////////////////////////////////////////////////
545//
546// Computes/returns surface area
547//
549{
550 if (fSurfaceArea == 0)
551 {
552 G4AutoLock l(&boxMutex);
553 fSurfaceArea = 8*(fDx*fDy+fDx*fDz+fDy*fDz);
554 l.unlock();
555 }
556 return fSurfaceArea;
557}
558
559//////////////////////////////////////////////////////////////////////////
560//
561// Make a clone of the object
562//
564{
565 return new G4Box(*this);
566}
567
568//////////////////////////////////////////////////////////////////////////
569//
570// Methods for visualisation
571
573{
574 scene.AddSolid (*this);
575}
576
578{
579 return { -fDx, fDx, -fDy, fDy, -fDz, fDz };
580}
581
583{
584 return new G4PolyhedronBox (fDx, fDy, fDz);
585}
586#endif
G4TemplateAutoLock< G4Mutex > G4AutoLock
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4double G4QuickRand(uint32_t seed=0)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4String G4GeometryType
Definition G4VSolid.hh:70
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
double z() const
Hep3Vector unit() const
double x() const
void setY(double)
double mag2() const
double y() const
void setZ(double)
void set(double x, double y, double z)
void setX(double)
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4BoundingEnvelope is a helper class to facilitate calculation of the extent of a solid within the li...
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep) override
Definition G4Box.cc:185
G4Box(const G4String &pName, G4double pX, G4double pY, G4double pZ)
Definition G4Box.cc:58
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
Definition G4Box.cc:572
G4VSolid * Clone() const override
Definition G4Box.cc:563
G4Polyhedron * CreatePolyhedron() const override
Definition G4Box.cc:582
G4Box & operator=(const G4Box &rhs)
Definition G4Box.cc:90
G4GeometryType GetEntityType() const override
Definition G4Box.cc:462
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
Definition G4Box.cc:319
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
Definition G4Box.cc:252
G4VisExtent GetExtent() const override
Definition G4Box.cc:577
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
Definition G4Box.cc:372
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
Definition G4Box.cc:196
G4double GetCubicVolume() override
Definition G4Box.cc:533
void SetZHalfLength(G4double dz)
Definition G4Box.cc:161
EInside Inside(const G4ThreeVector &p) const override
Definition G4Box.cc:238
G4ThreeVector GetPointOnSurface() const override
Definition G4Box.cc:500
G4bool IsFaceted() const override
Definition G4Box.cc:471
void SetYHalfLength(G4double dy)
Definition G4Box.cc:138
void SetXHalfLength(G4double dx)
Definition G4Box.cc:114
std::ostream & StreamInfo(std::ostream &os) const override
Definition G4Box.cc:480
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const override
Definition G4Box.cc:219
G4double GetSurfaceArea() override
Definition G4Box.cc:548
G4double fSurfaceArea
Definition G4CSGSolid.hh:93
G4double fCubicVolume
Definition G4CSGSolid.hh:92
G4bool fRebuildPolyhedron
Definition G4CSGSolid.hh:94
G4CSGSolid(const G4String &pName)
Definition G4CSGSolid.cc:49
G4CSGSolid & operator=(const G4CSGSolid &rhs)
Definition G4CSGSolid.cc:89
virtual void AddSolid(const G4Box &)=0
G4VPVParameterisation ia an abstract base class for Parameterisation, able to compute the transformat...
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
G4VPhysicalVolume is an abstract base class for the representation of a positioned volume....
G4String GetName() const
G4VSolid(const G4String &name)
Definition G4VSolid.cc:59
void DumpInfo() const
G4double kCarTolerance
Definition G4VSolid.hh:418
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...
EAxis
Definition geomdefs.hh:54
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69
#define DBL_MAX
Definition templates.hh:62