Geant4  10.03
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 //
27 // $Id: G4SubtractionSolid.cc 101046 2016-11-04 10:44:26Z gcosmo $
28 //
29 // Implementation of methods for the class G4IntersectionSolid
30 //
31 // History:
32 //
33 // 14.10.98 V.Grichine: implementation of the first version
34 // 19.10.98 V.Grichine: new algorithm of DistanceToIn(p,v)
35 // 02.08.99 V.Grichine: bugs fixed in DistanceToOut(p,v,...)
36 // while -> do-while & surfaceA limitations
37 // 13.09.00 V.Grichine: bug fixed in SurfaceNormal(p), p can be inside
38 // 22.07.11 T.Nikitina: add detection of Infinite Loop in DistanceToIn(p,v)
39 //
40 // --------------------------------------------------------------------
41 
42 #include "G4SubtractionSolid.hh"
43 
44 #include "G4SystemOfUnits.hh"
45 #include "G4VoxelLimits.hh"
46 #include "G4VPVParameterisation.hh"
47 #include "G4GeometryTolerance.hh"
48 
49 #include "G4VGraphicsScene.hh"
50 #include "G4Polyhedron.hh"
51 #include "HepPolyhedronProcessor.h"
52 
53 #include <sstream>
54 
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 
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 
81 //
82 // Constructor
83 
85  G4VSolid* pSolidA ,
86  G4VSolid* pSolidB ,
87  const G4Transform3D& transform )
88  : G4BooleanSolid(pName,pSolidA,pSolidB,transform)
89 {
90 }
91 
93 //
94 // Fake default constructor - sets only member data and allocates memory
95 // for usage restricted to object persistency.
96 
98  : G4BooleanSolid(a)
99 {
100 }
101 
103 //
104 // Destructor
105 
107 {
108 }
109 
111 //
112 // Copy constructor
113 
115  : G4BooleanSolid (rhs)
116 {
117 }
118 
120 //
121 // Assignment operator
122 
125 {
126  // Check assignment to self
127  //
128  if (this == &rhs) { return *this; }
129 
130  // Copy base class data
131  //
133 
134  return *this;
135 }
136 
138 //
139 // Get bounding box
140 
141 void
143 {
144  // Since it is unclear how the shape of the first solid will be changed
145  // after subtraction, just return its original bounding box.
146  //
147  fPtrSolidA->Extent(pMin,pMax);
148 
149  // Check correctness of the bounding box
150  //
151  if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
152  {
153  std::ostringstream message;
154  message << "Bad bounding box (min >= max) for solid: "
155  << GetName() << " !"
156  << "\npMin = " << pMin
157  << "\npMax = " << pMax;
158  G4Exception("G4SubtractionSolid::Extent()", "GeomMgt0001",
159  JustWarning, message);
160  DumpInfo();
161  }
162 }
163 
165 //
166 // Calculate extent under transform and specified limit
167 
168 G4bool
170  const G4VoxelLimits& pVoxelLimit,
171  const G4AffineTransform& pTransform,
172  G4double& pMin,
173  G4double& pMax ) const
174 {
175  // Since we cannot be sure how much the second solid subtracts
176  // from the first, we must use the first solid's extent!
177 
178  return fPtrSolidA->CalculateExtent( pAxis, pVoxelLimit,
179  pTransform, pMin, pMax );
180 }
181 
183 //
184 // Touching ? Empty subtraction ?
185 
187 {
188  EInside positionA = fPtrSolidA->Inside(p);
189  if (positionA == kOutside) return kOutside;
190 
191  EInside positionB = fPtrSolidB->Inside(p);
192 
193  if(positionA == kInside && positionB == kOutside)
194  {
195  return kInside ;
196  }
197  else
198  {
199  static const G4double rtol
201  if(( positionA == kInside && positionB == kSurface) ||
202  ( positionB == kOutside && positionA == kSurface) ||
203  ( positionA == kSurface && positionB == kSurface &&
204  ( fPtrSolidA->SurfaceNormal(p) -
205  fPtrSolidB->SurfaceNormal(p) ).mag2() > rtol ) )
206  {
207  return kSurface;
208  }
209  else
210  {
211  return kOutside;
212  }
213  }
214 }
215 
217 //
218 // SurfaceNormal
219 
222 {
224  EInside insideThis= Inside(p);
225  if( insideThis == kOutside )
226  {
227 #ifdef G4BOOLDEBUG
228  G4cout << "WARNING - Invalid call [1] in "
229  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
230  << " Point p is outside !" << G4endl;
231  G4cout << " p = " << p << G4endl;
232  G4cerr << "WARNING - Invalid call [1] in "
233  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
234  << " Point p is outside !" << G4endl;
235  G4cerr << " p = " << p << G4endl;
236 #endif
237  }
238  else
239  {
240  EInside InsideA = fPtrSolidA->Inside(p);
241  EInside InsideB = fPtrSolidB->Inside(p);
242 
243  if( InsideA == kSurface &&
244  InsideB != kInside )
245  {
246  normal = fPtrSolidA->SurfaceNormal(p) ;
247  }
248  else if( InsideA == kInside &&
249  InsideB != kOutside )
250  {
251  normal = -fPtrSolidB->SurfaceNormal(p) ;
252  }
253  else
254  {
256  {
257  normal = fPtrSolidA->SurfaceNormal(p) ;
258  }
259  else
260  {
261  normal = -fPtrSolidB->SurfaceNormal(p) ;
262  }
263 #ifdef G4BOOLDEBUG
264  if(insideThis == kInside)
265  {
266  G4cout << "WARNING - Invalid call [2] in "
267  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
268  << " Point p is inside !" << G4endl;
269  G4cout << " p = " << p << G4endl;
270  G4cerr << "WARNING - Invalid call [2] in "
271  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
272  << " Point p is inside !" << G4endl;
273  G4cerr << " p = " << p << G4endl;
274  }
275 #endif
276  }
277  }
278  return normal;
279 }
280 
282 //
283 // The same algorithm as in DistanceToIn(p)
284 
285 G4double
287  const G4ThreeVector& v ) const
288 {
289  G4double dist = 0.0, dist2 = 0.0, disTmp = 0.0;
290 
291 #ifdef G4BOOLDEBUG
292  if( Inside(p) == kInside )
293  {
294  G4cout << "WARNING - Invalid call in "
295  << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
296  << " Point p is inside !" << G4endl;
297  G4cout << " p = " << p << G4endl;
298  G4cout << " v = " << v << G4endl;
299  G4cerr << "WARNING - Invalid call in "
300  << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
301  << " Point p is inside !" << G4endl;
302  G4cerr << " p = " << p << G4endl;
303  G4cerr << " v = " << v << G4endl;
304  }
305 #endif
306 
307  // if( // ( fPtrSolidA->Inside(p) != kOutside) && // case1:p in both A&B
308  if ( fPtrSolidB->Inside(p) != kOutside ) // start: out of B
309  {
310  dist = fPtrSolidB->DistanceToOut(p,v) ; // ,calcNorm,validNorm,n) ;
311 
312  if( fPtrSolidA->Inside(p+dist*v) != kInside )
313  {
314  G4int count1=0;
315  do // Loop checking, 13.08.2015, G.Cosmo
316  {
317  disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
318 
319  if(disTmp == kInfinity)
320  {
321  return kInfinity ;
322  }
323  dist += disTmp ;
324 
325  if( Inside(p+dist*v) == kOutside )
326  {
327  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
328  dist2 = dist+disTmp;
329  if (dist == dist2) { return dist; } // no progress
330  dist = dist2 ;
331  count1++;
332  if( count1 > 1000 ) // Infinite loop detected
333  {
334  G4String nameB = fPtrSolidB->GetName();
335  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
336  {
337  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
338  ->GetConstituentMovedSolid()->GetName();
339  }
340  std::ostringstream message;
341  message << "Illegal condition caused by solids: "
342  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
343  message.precision(16);
344  message << "Looping detected in point " << p+dist*v
345  << ", from original point " << p
346  << " and direction " << v << G4endl
347  << "Computed candidate distance: " << dist << "*mm. ";
348  message.precision(6);
349  DumpInfo();
350  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
351  "GeomSolids1001", JustWarning, message,
352  "Returning candidate distance.");
353  return dist;
354  }
355  }
356  }
357  while( Inside(p+dist*v) == kOutside ) ;
358  }
359  }
360  else // p outside A, start in A
361  {
362  dist = fPtrSolidA->DistanceToIn(p,v) ;
363 
364  if( dist == kInfinity ) // past A, hence past A\B
365  {
366  return kInfinity ;
367  }
368  else
369  {
370  G4int count2=0;
371  while( Inside(p+dist*v) == kOutside ) // pushing loop
372  {
373  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
374  dist += disTmp ;
375 
376  if( Inside(p+dist*v) == kOutside )
377  {
378  disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
379 
380  if(disTmp == kInfinity) // past A, hence past A\B
381  {
382  return kInfinity ;
383  }
384  dist2 = dist+disTmp;
385  if (dist == dist2) { return dist; } // no progress
386  dist = dist2 ;
387  count2++;
388  if( count2 > 1000 ) // Infinite loop detected
389  {
390  G4String nameB = fPtrSolidB->GetName();
391  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
392  {
393  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
394  ->GetConstituentMovedSolid()->GetName();
395  }
396  std::ostringstream message;
397  message << "Illegal condition caused by solids: "
398  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
399  message.precision(16);
400  message << "Looping detected in point " << p+dist*v
401  << ", from original point " << p
402  << " and direction " << v << G4endl
403  << "Computed candidate distance: " << dist << "*mm. ";
404  message.precision(6);
405  DumpInfo();
406  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
407  "GeomSolids1001", JustWarning, message,
408  "Returning candidate distance.");
409  return dist;
410  }
411  }
412  } // Loop checking, 13.08.2015, G.Cosmo
413  }
414  }
415 
416  return dist ;
417 }
418 
420 //
421 // Approximate nearest distance from the point p to the intersection of
422 // two solids. It is usually underestimated from the point of view of
423 // isotropic safety
424 
425 G4double
427 {
428  G4double dist=0.0;
429 
430 #ifdef G4BOOLDEBUG
431  if( Inside(p) == kInside )
432  {
433  G4cout << "WARNING - Invalid call in "
434  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
435  << " Point p is inside !" << G4endl;
436  G4cout << " p = " << p << G4endl;
437  G4cerr << "WARNING - Invalid call in "
438  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
439  << " Point p is inside !" << G4endl;
440  G4cerr << " p = " << p << G4endl;
441  }
442 #endif
443 
444  if( ( fPtrSolidA->Inside(p) != kOutside) && // case 1
445  ( fPtrSolidB->Inside(p) != kOutside) )
446  {
447  dist= fPtrSolidB->DistanceToOut(p) ;
448  }
449  else
450  {
451  dist= fPtrSolidA->DistanceToIn(p) ;
452  }
453 
454  return dist;
455 }
456 
458 //
459 // The same algorithm as DistanceToOut(p)
460 
461 G4double
463  const G4ThreeVector& v,
464  const G4bool calcNorm,
465  G4bool *validNorm,
466  G4ThreeVector *n ) const
467 {
468 #ifdef G4BOOLDEBUG
469  if( Inside(p) == kOutside )
470  {
471  G4cout << "Position:" << G4endl << G4endl;
472  G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
473  G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
474  G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
475  G4cout << "Direction:" << G4endl << G4endl;
476  G4cout << "v.x() = " << v.x() << G4endl;
477  G4cout << "v.y() = " << v.y() << G4endl;
478  G4cout << "v.z() = " << v.z() << G4endl << G4endl;
479  G4cout << "WARNING - Invalid call in "
480  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
481  << " Point p is outside !" << G4endl;
482  G4cout << " p = " << p << G4endl;
483  G4cout << " v = " << v << G4endl;
484  G4cerr << "WARNING - Invalid call in "
485  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
486  << " Point p is outside !" << G4endl;
487  G4cerr << " p = " << p << G4endl;
488  G4cerr << " v = " << v << G4endl;
489  }
490 #endif
491 
492  G4double distout;
493  G4double distA = fPtrSolidA->DistanceToOut(p,v,calcNorm,validNorm,n) ;
494  G4double distB = fPtrSolidB->DistanceToIn(p,v) ;
495  if(distB < distA)
496  {
497  if(calcNorm)
498  {
499  *n = -(fPtrSolidB->SurfaceNormal(p+distB*v)) ;
500  *validNorm = false ;
501  }
502  distout= distB ;
503  }
504  else
505  {
506  distout= distA ;
507  }
508  return distout;
509 }
510 
512 //
513 // Inverted algorithm of DistanceToIn(p)
514 
515 G4double
517 {
518  G4double dist=0.0;
519 
520  if( Inside(p) == kOutside )
521  {
522 #ifdef G4BOOLDEBUG
523  G4cout << "WARNING - Invalid call in "
524  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
525  << " Point p is outside" << G4endl;
526  G4cout << " p = " << p << G4endl;
527  G4cerr << "WARNING - Invalid call in "
528  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
529  << " Point p is outside" << G4endl;
530  G4cerr << " p = " << p << G4endl;
531 #endif
532  }
533  else
534  {
536  fPtrSolidB->DistanceToIn(p) ) ;
537  }
538  return dist;
539 }
540 
542 //
543 //
544 
546 {
547  return G4String("G4SubtractionSolid");
548 }
549 
551 //
552 // Make a clone of the object
553 
555 {
556  return new G4SubtractionSolid(*this);
557 }
558 
560 //
561 //
562 
563 void
565  const G4int,
566  const G4VPhysicalVolume* )
567 {
568 }
569 
571 //
572 //
573 
574 void
576 {
577  scene.AddSolid (*this);
578 }
579 
581 //
582 //
583 
584 G4Polyhedron*
586 {
587  HepPolyhedronProcessor processor;
588  // Stack components and components of components recursively
589  // See G4BooleanSolid::StackPolyhedron
590  G4Polyhedron* top = StackPolyhedron(processor, this);
591  G4Polyhedron* result = new G4Polyhedron(*top);
592  if (processor.execute(*result)) { return result; }
593  else { return 0; }
594 }
G4String GetName() const
G4VSolid * fPtrSolidB
G4VSolid * Clone() const
virtual G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const =0
static constexpr double mm
Definition: G4SIunits.hh:115
static const G4double kInfinity
Definition: geomdefs.hh:42
CLHEP::Hep3Vector G4ThreeVector
CLHEP::HepRotation G4RotationMatrix
std::vector< ExP01TrackerHit * > a
Definition: ExP01Classes.hh:33
virtual G4GeometryType GetEntityType() const =0
virtual void AddSolid(const G4Box &)=0
int G4int
Definition: G4Types.hh:78
G4Polyhedron * CreatePolyhedron() const
void DumpInfo() const
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const
G4GLOB_DLL std::ostream G4cout
virtual EInside Inside(const G4ThreeVector &p) const =0
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
void Extent(G4ThreeVector &pMin, G4ThreeVector &pMax) const
G4double GetRadialTolerance() const
bool G4bool
Definition: G4Types.hh:79
G4SubtractionSolid & operator=(const G4SubtractionSolid &rhs)
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
EInside Inside(const G4ThreeVector &p) const
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
HepGeom::Transform3D G4Transform3D
G4SubtractionSolid(const G4String &pName, G4VSolid *pSolidA, G4VSolid *pSolidB)
const G4int n
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
void DescribeYourselfTo(G4VGraphicsScene &scene) const
#define processor
Definition: xmlparse.cc:617
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
EInside
Definition: geomdefs.hh:58
EAxis
Definition: geomdefs.hh:54
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
G4VSolid * fPtrSolidA
#define G4endl
Definition: G4ios.hh:61
G4GeometryType GetEntityType() const
G4BooleanSolid & operator=(const G4BooleanSolid &rhs)
double G4double
Definition: G4Types.hh:76
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const =0
virtual void Extent(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Definition: G4VSolid.cc:626
G4Polyhedron * StackPolyhedron(HepPolyhedronProcessor &, const G4VSolid *) const
static G4GeometryTolerance * GetInstance()
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4GLOB_DLL std::ostream G4cerr