Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4SubtractionSolid.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 of methods for the class G4IntersectionSolid
27//
28// 22.07.11 T.Nikitina: added detection of infinite loop in DistanceToIn(p,v)
29// 19.10.98 V.Grichine: new algorithm of DistanceToIn(p,v)
30// 14.10.98 V.Grichine: implementation of the first version
31// --------------------------------------------------------------------
32
33#include "G4SubtractionSolid.hh"
34
35#include "G4SystemOfUnits.hh"
36#include "G4VoxelLimits.hh"
39
40#include "G4VGraphicsScene.hh"
41#include "G4Polyhedron.hh"
44
46#include "G4AutoLock.hh"
47
48#include <sstream>
49
50namespace
51{
53}
54
55//////////////////////////////////////////////////////////////////////////
56//
57// Transfer all data members to G4BooleanSolid which is responsible
58// for them. pName will be in turn sent to G4VSolid
59
61 G4VSolid* pSolidA ,
62 G4VSolid* pSolidB )
63 : G4BooleanSolid(pName,pSolidA,pSolidB)
64{
65}
66
67//////////////////////////////////////////////////////////////////////////
68//
69// Constructor
70
72 G4VSolid* pSolidA ,
73 G4VSolid* pSolidB ,
74 G4RotationMatrix* rotMatrix,
75 const G4ThreeVector& transVector )
76 : G4BooleanSolid(pName,pSolidA,pSolidB,rotMatrix,transVector)
77{
78}
79
80//////////////////////////////////////////////////////////////////////////
81//
82// Constructor
83
85 G4VSolid* pSolidA ,
86 G4VSolid* pSolidB ,
87 const G4Transform3D& transform )
88 : G4BooleanSolid(pName,pSolidA,pSolidB,transform)
89{
90}
91
92//////////////////////////////////////////////////////////////////////////
93//
94// Fake default constructor - sets only member data and allocates memory
95// for usage restricted to object persistency.
96
101
102//////////////////////////////////////////////////////////////////////////
103//
104// Copy constructor
105
107
108//////////////////////////////////////////////////////////////////////////
109//
110// Assignment operator
111
114{
115 // Check assignment to self
116 //
117 if (this == &rhs) { return *this; }
118
119 // Copy base class data
120 //
122
123 return *this;
124}
125
126//////////////////////////////////////////////////////////////////////////
127//
128// Get bounding box
129
130void
132 G4ThreeVector& pMax) const
133{
134 // Since it is unclear how the shape of the first solid will be changed
135 // after subtraction, just return its original bounding box.
136 //
137 fPtrSolidA->BoundingLimits(pMin,pMax);
138
139 // Check correctness of the bounding box
140 //
141 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
142 {
143 std::ostringstream message;
144 message << "Bad bounding box (min >= max) for solid: "
145 << GetName() << " !"
146 << "\npMin = " << pMin
147 << "\npMax = " << pMax;
148 G4Exception("G4SubtractionSolid::BoundingLimits()", "GeomMgt0001",
149 JustWarning, message);
150 DumpInfo();
151 }
152}
153
154//////////////////////////////////////////////////////////////////////////
155//
156// Calculate extent under transform and specified limit
157
158G4bool
160 const G4VoxelLimits& pVoxelLimit,
161 const G4AffineTransform& pTransform,
162 G4double& pMin,
163 G4double& pMax ) const
164{
165 // Since we cannot be sure how much the second solid subtracts
166 // from the first, we must use the first solid's extent!
167
168 return fPtrSolidA->CalculateExtent( pAxis, pVoxelLimit,
169 pTransform, pMin, pMax );
170}
171
172//////////////////////////////////////////////////////////////////////////
173//
174// Touching ? Empty subtraction ?
175
177{
178 EInside positionA = fPtrSolidA->Inside(p);
179 if (positionA == kOutside) { return positionA; } // outside A
180
181 EInside positionB = fPtrSolidB->Inside(p);
182 if (positionB == kOutside) { return positionA; }
183
184 if (positionB == kInside) { return kOutside; }
185 if (positionA == kInside) { return kSurface; } // surface B
186
187 // Point is on both surfaces
188 //
189 static const G4double rtol = 1000*kCarTolerance;
190
191 return ((fPtrSolidA->SurfaceNormal(p) -
192 fPtrSolidB->SurfaceNormal(p)).mag2() > rtol) ? kSurface : kOutside;
193}
194
195//////////////////////////////////////////////////////////////////////////
196//
197// SurfaceNormal
198
201{
202 G4ThreeVector normal;
203
204 EInside InsideA = fPtrSolidA->Inside(p);
205 EInside InsideB = fPtrSolidB->Inside(p);
206
207 if( InsideA == kOutside )
208 {
209#ifdef G4BOOLDEBUG
210 G4cout << "WARNING - Invalid call [1] in "
211 << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
212 << " Point p is outside !" << G4endl;
213 G4cout << " p = " << p << G4endl;
214 G4cerr << "WARNING - Invalid call [1] in "
215 << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
216 << " Point p is outside !" << G4endl;
217 G4cerr << " p = " << p << G4endl;
218#endif
219 normal = fPtrSolidA->SurfaceNormal(p) ;
220 }
221 else if( InsideA == kSurface &&
222 InsideB != kInside )
223 {
224 normal = fPtrSolidA->SurfaceNormal(p) ;
225 }
226 else if( InsideA == kInside &&
227 InsideB != kOutside )
228 {
229 normal = -fPtrSolidB->SurfaceNormal(p) ;
230 }
231 else
232 {
233 if ( fPtrSolidA->DistanceToOut(p) <= fPtrSolidB->DistanceToIn(p) )
234 {
235 normal = fPtrSolidA->SurfaceNormal(p) ;
236 }
237 else
238 {
239 normal = -fPtrSolidB->SurfaceNormal(p) ;
240 }
241#ifdef G4BOOLDEBUG
242 if(Inside(p) == kInside)
243 {
244 G4cout << "WARNING - Invalid call [2] in "
245 << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
246 << " Point p is inside !" << G4endl;
247 G4cout << " p = " << p << G4endl;
248 G4cerr << "WARNING - Invalid call [2] in "
249 << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
250 << " Point p is inside !" << G4endl;
251 G4cerr << " p = " << p << G4endl;
252 }
253#endif
254 }
255 return normal;
256}
257
258//////////////////////////////////////////////////////////////////////////
259//
260// The same algorithm as in DistanceToIn(p)
261
264 const G4ThreeVector& v ) const
265{
266 G4double dist = 0.0, dist2 = 0.0, disTmp = 0.0;
267
268#ifdef G4BOOLDEBUG
269 if( Inside(p) == kInside )
270 {
271 G4cout << "WARNING - Invalid call in "
272 << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
273 << " Point p is inside !" << G4endl;
274 G4cout << " p = " << p << G4endl;
275 G4cout << " v = " << v << G4endl;
276 G4cerr << "WARNING - Invalid call in "
277 << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
278 << " Point p is inside !" << G4endl;
279 G4cerr << " p = " << p << G4endl;
280 G4cerr << " v = " << v << G4endl;
281 }
282#endif
283
284 // if( // ( fPtrSolidA->Inside(p) != kOutside) && // case1:p in both A&B
285 if ( fPtrSolidB->Inside(p) != kOutside ) // start: out of B
286 {
287 dist = fPtrSolidB->DistanceToOut(p,v) ; // ,calcNorm,validNorm,n) ;
288
289 if( fPtrSolidA->Inside(p+dist*v) != kInside )
290 {
291 G4int count1=0;
292 do // Loop checking, 13.08.2015, G.Cosmo
293 {
294 disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
295
296 if(disTmp == kInfinity)
297 {
298 return kInfinity ;
299 }
300 dist += disTmp ;
301
302 if( Inside(p+dist*v) == kOutside )
303 {
304 disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
305 dist2 = dist+disTmp;
306 if (dist == dist2) { return dist; } // no progress
307 dist = dist2 ;
308 ++count1;
309 if( count1 > 1000 ) // Infinite loop detected
310 {
311 G4String nameB = fPtrSolidB->GetName();
312 if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
313 {
314 nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
315 ->GetConstituentMovedSolid()->GetName();
316 }
317 std::ostringstream message;
318 message << "Illegal condition caused by solids: "
319 << fPtrSolidA->GetName() << " and " << nameB << G4endl;
320 message.precision(16);
321 message << "Looping detected in point " << p+dist*v
322 << ", from original point " << p
323 << " and direction " << v << G4endl
324 << "Computed candidate distance: " << dist << "*mm. ";
325 message.precision(6);
326 DumpInfo();
327 G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
328 "GeomSolids1001", JustWarning, message,
329 "Returning candidate distance.");
330 return dist;
331 }
332 }
333 }
334 while( Inside(p+dist*v) == kOutside ) ;
335 }
336 }
337 else // p outside A, start in A
338 {
339 dist = fPtrSolidA->DistanceToIn(p,v) ;
340
341 if( dist == kInfinity ) // past A, hence past A\B
342 {
343 return kInfinity ;
344 }
345
346 G4int count2=0;
347 while( Inside(p+dist*v) == kOutside ) // pushing loop
348 {
349 disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
350 dist += disTmp ;
351
352 if( Inside(p+dist*v) == kOutside )
353 {
354 disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
355
356 if(disTmp == kInfinity) // past A, hence past A\B
357 {
358 return kInfinity ;
359 }
360 dist2 = dist+disTmp;
361 if (dist == dist2) { return dist; } // no progress
362 dist = dist2 ;
363 ++count2;
364 if( count2 > 1000 ) // Infinite loop detected
365 {
366 G4String nameB = fPtrSolidB->GetName();
367 if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
368 {
369 nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
370 ->GetConstituentMovedSolid()->GetName();
371 }
372 std::ostringstream message;
373 message << "Illegal condition caused by solids: "
374 << fPtrSolidA->GetName() << " and " << nameB << G4endl;
375 message.precision(16);
376 message << "Looping detected in point " << p+dist*v
377 << ", from original point " << p
378 << " and direction " << v << G4endl
379 << "Computed candidate distance: " << dist << "*mm. ";
380 message.precision(6);
381 DumpInfo();
382 G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
383 "GeomSolids1001", JustWarning, message,
384 "Returning candidate distance.");
385 return dist;
386 }
387 }
388 } // Loop checking, 13.08.2015, G.Cosmo
389 }
390
391 return dist ;
392}
393
394//////////////////////////////////////////////////////////////////////////
395//
396// Approximate nearest distance from the point p to the intersection of
397// two solids. It is usually underestimated from the point of view of
398// isotropic safety
399
402{
403 G4double dist = 0.0;
404
405#ifdef G4BOOLDEBUG
406 if( Inside(p) == kInside )
407 {
408 G4cout << "WARNING - Invalid call in "
409 << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
410 << " Point p is inside !" << G4endl;
411 G4cout << " p = " << p << G4endl;
412 G4cerr << "WARNING - Invalid call in "
413 << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
414 << " Point p is inside !" << G4endl;
415 G4cerr << " p = " << p << G4endl;
416 }
417#endif
418
419 if( ( fPtrSolidA->Inside(p) != kOutside) && // case 1
420 ( fPtrSolidB->Inside(p) != kOutside) )
421 {
422 dist = fPtrSolidB->DistanceToOut(p);
423 }
424 else
425 {
426 dist = fPtrSolidA->DistanceToIn(p);
427 }
428
429 return dist;
430}
431
432//////////////////////////////////////////////////////////////////////////
433//
434// The same algorithm as DistanceToOut(p)
435
438 const G4ThreeVector& v,
439 const G4bool calcNorm,
440 G4bool* validNorm,
441 G4ThreeVector* n ) const
442{
443#ifdef G4BOOLDEBUG
444 if( Inside(p) == kOutside )
445 {
446 G4cout << "Position:" << G4endl << G4endl;
447 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
448 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
449 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
450 G4cout << "Direction:" << G4endl << G4endl;
451 G4cout << "v.x() = " << v.x() << G4endl;
452 G4cout << "v.y() = " << v.y() << G4endl;
453 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
454 G4cout << "WARNING - Invalid call in "
455 << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
456 << " Point p is outside !" << G4endl;
457 G4cout << " p = " << p << G4endl;
458 G4cout << " v = " << v << G4endl;
459 G4cerr << "WARNING - Invalid call in "
460 << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
461 << " Point p is outside !" << G4endl;
462 G4cerr << " p = " << p << G4endl;
463 G4cerr << " v = " << v << G4endl;
464 }
465#endif
466
467 G4double distout;
468 G4double distA = fPtrSolidA->DistanceToOut(p,v,calcNorm,validNorm,n) ;
469 G4double distB = fPtrSolidB->DistanceToIn(p,v) ;
470 if(distB < distA)
471 {
472 if(calcNorm)
473 {
474 *n = -(fPtrSolidB->SurfaceNormal(p+distB*v)) ;
475 *validNorm = false ;
476 }
477 distout= distB ;
478 }
479 else
480 {
481 distout= distA ;
482 }
483 return distout;
484}
485
486//////////////////////////////////////////////////////////////////////////
487//
488// Inverted algorithm of DistanceToIn(p)
489
492{
493 G4double dist=0.0;
494
495 if( Inside(p) == kOutside )
496 {
497#ifdef G4BOOLDEBUG
498 G4cout << "WARNING - Invalid call in "
499 << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
500 << " Point p is outside" << G4endl;
501 G4cout << " p = " << p << G4endl;
502 G4cerr << "WARNING - Invalid call in "
503 << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
504 << " Point p is outside" << G4endl;
505 G4cerr << " p = " << p << G4endl;
506#endif
507 }
508 else
509 {
510 dist= std::min(fPtrSolidA->DistanceToOut(p),
511 fPtrSolidB->DistanceToIn(p) ) ;
512 }
513 return dist;
514}
515
516//////////////////////////////////////////////////////////////////////////
517//
518//
519
521{
522 return {"G4SubtractionSolid"};
523}
524
525//////////////////////////////////////////////////////////////////////////
526//
527// Make a clone of the object
528
530{
531 return new G4SubtractionSolid(*this);
532}
533
534//////////////////////////////////////////////////////////////////////////
535//
536// ComputeDimensions
537
538void
540 const G4int,
541 const G4VPhysicalVolume* )
542{
543 DumpInfo();
544 G4Exception("G4SubtractionSolid::ComputeDimensions()",
545 "GeomSolids0001", FatalException,
546 "Method not applicable in this context!");
547}
548
549//////////////////////////////////////////////////////////////////////////
550//
551// DescribeYourselfTo
552
553void
555{
556 scene.AddSolid (*this);
557}
558
559//////////////////////////////////////////////////////////////////////////
560//
561// CreatePolyhedron
562
564{
565 if (fExternalBoolProcessor == nullptr)
566 {
567 HepPolyhedronProcessor processor;
568 // Stack components and components of components recursively
569 // See G4BooleanSolid::StackPolyhedron
570 G4Polyhedron* top = StackPolyhedron(processor, this);
571 auto result = new G4Polyhedron(*top);
572 if (processor.execute(*result))
573 {
574 return result;
575 }
576 return nullptr;
577 }
578 else
579 {
580 return fExternalBoolProcessor->Process(this);
581 }
582}
583
584//////////////////////////////////////////////////////////////////////////
585//
586// GetCubicVolume
587//
588
590{
591 if( fCubicVolume >= 0. )
592 {
593 return fCubicVolume;
594 }
595 G4RecursiveAutoLock l(&subMutex);
596 G4ThreeVector bminA, bmaxA, bminB, bmaxB;
597 fPtrSolidA->BoundingLimits(bminA, bmaxA);
598 fPtrSolidB->BoundingLimits(bminB, bmaxB);
599 G4bool noIntersection =
600 bminA.x() >= bmaxB.x() || bminA.y() >= bmaxB.y() || bminA.z() >= bmaxB.z() ||
601 bminB.x() >= bmaxA.x() || bminB.y() >= bmaxA.y() || bminB.z() >= bmaxA.z();
602
603 if (noIntersection)
604 {
605 fCubicVolume = fPtrSolidA->GetCubicVolume();
606 }
607 else
608 {
609 if (GetNumOfConstituents() > 10)
610 {
612 }
613 else
614 {
615 G4IntersectionSolid intersectVol("Temporary-Intersection-for-Subtraction",
618 intersectVol.SetCubVolEpsilon(GetCubVolEpsilon());
619
620 G4double cubVolumeA = fPtrSolidA->GetCubicVolume();
621 fCubicVolume = cubVolumeA - intersectVol.GetCubicVolume();
622 if (fCubicVolume < 0.01*cubVolumeA)
623 {
625 }
626 }
627 }
628 l.unlock();
629 return fCubicVolume;
630}
G4TemplateAutoLock< G4RecursiveMutex > G4RecursiveAutoLock
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
CLHEP::HepRotation G4RotationMatrix
#define G4MUTEX_INITIALIZER
std::recursive_mutex G4RecursiveMutex
CLHEP::Hep3Vector G4ThreeVector
HepGeom::Transform3D G4Transform3D
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4String G4GeometryType
Definition G4VSolid.hh:70
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
double z() const
double x() const
double y() const
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4VSolid * fPtrSolidA
G4BooleanSolid & operator=(const G4BooleanSolid &rhs)
void SetCubVolEpsilon(G4double ep)
G4VSolid * fPtrSolidB
G4double GetCubVolEpsilon() const
G4double GetCubicVolume() override
G4BooleanSolid(const G4String &pName, G4VSolid *pSolidA, G4VSolid *pSolidB)
G4int GetCubVolStatistics() const
G4int GetNumOfConstituents() const override
static G4VBooleanProcessor * fExternalBoolProcessor
G4Polyhedron * StackPolyhedron(HepPolyhedronProcessor &, const G4VSolid *) const
void SetCubVolStatistics(G4int st)
G4DisplacedSolid is a solid that has been shifted from its original frame of reference to a new one....
G4IntersectionSolid is a solid describing the Boolean intersection of two solids.
G4SubtractionSolid is a solid describing the Boolean subtraction of two solids.
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
G4double GetCubicVolume() final
G4VSolid * Clone() const override
G4SubtractionSolid & operator=(const G4SubtractionSolid &rhs)
EInside Inside(const G4ThreeVector &p) const override
G4GeometryType GetEntityType() const override
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep) override
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4SubtractionSolid(const G4String &pName, G4VSolid *pSolidA, G4VSolid *pSolidB)
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
G4Polyhedron * CreatePolyhedron() const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
virtual void AddSolid(const G4Box &)=0
G4VPVParameterisation ia an abstract base class for Parameterisation, able to compute the transformat...
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...
bool execute(HepPolyhedron &)
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