Geant4  10.02.p02
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 95422 2016-02-10 14:35:47Z 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 // CalculateExtent
140 
141 G4bool
143  const G4VoxelLimits& pVoxelLimit,
144  const G4AffineTransform& pTransform,
145  G4double& pMin,
146  G4double& pMax ) const
147 {
148  // Since we cannot be sure how much the second solid subtracts
149  // from the first, we must use the first solid's extent!
150 
151  return fPtrSolidA->CalculateExtent( pAxis, pVoxelLimit,
152  pTransform, pMin, pMax );
153 }
154 
156 //
157 // Touching ? Empty subtraction ?
158 
160 {
161  EInside positionA = fPtrSolidA->Inside(p);
162  if (positionA == kOutside) return kOutside;
163 
164  EInside positionB = fPtrSolidB->Inside(p);
165 
166  if(positionA == kInside && positionB == kOutside)
167  {
168  return kInside ;
169  }
170  else
171  {
172  static const G4double rtol
174  if(( positionA == kInside && positionB == kSurface) ||
175  ( positionB == kOutside && positionA == kSurface) ||
176  ( positionA == kSurface && positionB == kSurface &&
177  ( fPtrSolidA->SurfaceNormal(p) -
178  fPtrSolidB->SurfaceNormal(p) ).mag2() > rtol ) )
179  {
180  return kSurface;
181  }
182  else
183  {
184  return kOutside;
185  }
186  }
187 }
188 
190 //
191 // SurfaceNormal
192 
195 {
197  EInside insideThis= Inside(p);
198  if( insideThis == kOutside )
199  {
200 #ifdef G4BOOLDEBUG
201  G4cout << "WARNING - Invalid call [1] in "
202  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
203  << " Point p is outside !" << G4endl;
204  G4cout << " p = " << p << G4endl;
205  G4cerr << "WARNING - Invalid call [1] in "
206  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
207  << " Point p is outside !" << G4endl;
208  G4cerr << " p = " << p << G4endl;
209 #endif
210  }
211  else
212  {
213  EInside InsideA = fPtrSolidA->Inside(p);
214  EInside InsideB = fPtrSolidB->Inside(p);
215 
216  if( InsideA == kSurface &&
217  InsideB != kInside )
218  {
219  normal = fPtrSolidA->SurfaceNormal(p) ;
220  }
221  else if( InsideA == kInside &&
222  InsideB != kOutside )
223  {
224  normal = -fPtrSolidB->SurfaceNormal(p) ;
225  }
226  else
227  {
229  {
230  normal = fPtrSolidA->SurfaceNormal(p) ;
231  }
232  else
233  {
234  normal = -fPtrSolidB->SurfaceNormal(p) ;
235  }
236 #ifdef G4BOOLDEBUG
237  if(insideThis == kInside)
238  {
239  G4cout << "WARNING - Invalid call [2] in "
240  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
241  << " Point p is inside !" << G4endl;
242  G4cout << " p = " << p << G4endl;
243  G4cerr << "WARNING - Invalid call [2] in "
244  << "G4SubtractionSolid::SurfaceNormal(p)" << G4endl
245  << " Point p is inside !" << G4endl;
246  G4cerr << " p = " << p << G4endl;
247  }
248 #endif
249  }
250  }
251  return normal;
252 }
253 
255 //
256 // The same algorithm as in DistanceToIn(p)
257 
258 G4double
260  const G4ThreeVector& v ) const
261 {
262  G4double dist = 0.0,disTmp = 0.0 ;
263 
264 #ifdef G4BOOLDEBUG
265  if( Inside(p) == kInside )
266  {
267  G4cout << "WARNING - Invalid call in "
268  << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
269  << " Point p is inside !" << G4endl;
270  G4cout << " p = " << p << G4endl;
271  G4cout << " v = " << v << G4endl;
272  G4cerr << "WARNING - Invalid call in "
273  << "G4SubtractionSolid::DistanceToIn(p,v)" << G4endl
274  << " Point p is inside !" << G4endl;
275  G4cerr << " p = " << p << G4endl;
276  G4cerr << " v = " << v << G4endl;
277  }
278 #endif
279 
280  // if( // ( fPtrSolidA->Inside(p) != kOutside) && // case1:p in both A&B
281  if ( fPtrSolidB->Inside(p) != kOutside ) // start: out of B
282  {
283  dist = fPtrSolidB->DistanceToOut(p,v) ; // ,calcNorm,validNorm,n) ;
284 
285  if( fPtrSolidA->Inside(p+dist*v) != kInside )
286  {
287  G4int count1=0;
288  do // Loop checking, 13.08.2015, G.Cosmo
289  {
290  disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
291 
292  if(disTmp == kInfinity)
293  {
294  return kInfinity ;
295  }
296  dist += disTmp ;
297 
298  if( Inside(p+dist*v) == kOutside )
299  {
300  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
301  dist += disTmp ;
302  count1++;
303  if( count1 > 1000 ) // Infinite loop detected
304  {
305  G4String nameB = fPtrSolidB->GetName();
306  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
307  {
308  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
309  ->GetConstituentMovedSolid()->GetName();
310  }
311  std::ostringstream message;
312  message << "Illegal condition caused by solids: "
313  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
314  message.precision(16);
315  message << "Looping detected in point " << p+dist*v
316  << ", from original point " << p
317  << " and direction " << v << G4endl
318  << "Computed candidate distance: " << dist << "*mm. ";
319  message.precision(6);
320  DumpInfo();
321  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
322  "GeomSolids1001", JustWarning, message,
323  "Returning candidate distance.");
324  return dist;
325  }
326  }
327  }
328  while( Inside(p+dist*v) == kOutside ) ;
329  }
330  }
331  else // p outside A, start in A
332  {
333  dist = fPtrSolidA->DistanceToIn(p,v) ;
334 
335  if( dist == kInfinity ) // past A, hence past A\B
336  {
337  return kInfinity ;
338  }
339  else
340  {
341  G4int count2=0;
342  while( Inside(p+dist*v) == kOutside ) // pushing loop
343  {
344  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
345  dist += disTmp ;
346 
347  if( Inside(p+dist*v) == kOutside )
348  {
349  disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
350 
351  if(disTmp == kInfinity) // past A, hence past A\B
352  {
353  return kInfinity ;
354  }
355  dist += disTmp ;
356  count2++;
357  if( count2 > 1000 ) // Infinite loop detected
358  {
359  G4String nameB = fPtrSolidB->GetName();
360  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
361  {
362  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
363  ->GetConstituentMovedSolid()->GetName();
364  }
365  std::ostringstream message;
366  message << "Illegal condition caused by solids: "
367  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
368  message.precision(16);
369  message << "Looping detected in point " << p+dist*v
370  << ", from original point " << p
371  << " and direction " << v << G4endl
372  << "Computed candidate distance: " << dist << "*mm. ";
373  message.precision(6);
374  DumpInfo();
375  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
376  "GeomSolids1001", JustWarning, message,
377  "Returning candidate distance.");
378  return dist;
379  }
380  }
381  } // Loop checking, 13.08.2015, G.Cosmo
382  }
383  }
384 
385  return dist ;
386 }
387 
389 //
390 // Approximate nearest distance from the point p to the intersection of
391 // two solids. It is usually underestimated from the point of view of
392 // isotropic safety
393 
394 G4double
396 {
397  G4double dist=0.0;
398 
399 #ifdef G4BOOLDEBUG
400  if( Inside(p) == kInside )
401  {
402  G4cout << "WARNING - Invalid call in "
403  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
404  << " Point p is inside !" << G4endl;
405  G4cout << " p = " << p << G4endl;
406  G4cerr << "WARNING - Invalid call in "
407  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
408  << " Point p is inside !" << G4endl;
409  G4cerr << " p = " << p << G4endl;
410  }
411 #endif
412 
413  if( ( fPtrSolidA->Inside(p) != kOutside) && // case 1
414  ( fPtrSolidB->Inside(p) != kOutside) )
415  {
416  dist= fPtrSolidB->DistanceToOut(p) ;
417  }
418  else
419  {
420  dist= fPtrSolidA->DistanceToIn(p) ;
421  }
422 
423  return dist;
424 }
425 
427 //
428 // The same algorithm as DistanceToOut(p)
429 
430 G4double
432  const G4ThreeVector& v,
433  const G4bool calcNorm,
434  G4bool *validNorm,
435  G4ThreeVector *n ) const
436 {
437 #ifdef G4BOOLDEBUG
438  if( Inside(p) == kOutside )
439  {
440  G4cout << "Position:" << G4endl << G4endl;
441  G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
442  G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
443  G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
444  G4cout << "Direction:" << G4endl << G4endl;
445  G4cout << "v.x() = " << v.x() << G4endl;
446  G4cout << "v.y() = " << v.y() << G4endl;
447  G4cout << "v.z() = " << v.z() << G4endl << G4endl;
448  G4cout << "WARNING - Invalid call in "
449  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
450  << " Point p is outside !" << G4endl;
451  G4cout << " p = " << p << G4endl;
452  G4cout << " v = " << v << G4endl;
453  G4cerr << "WARNING - Invalid call in "
454  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
455  << " Point p is outside !" << G4endl;
456  G4cerr << " p = " << p << G4endl;
457  G4cerr << " v = " << v << G4endl;
458  }
459 #endif
460 
461  G4double distout;
462  G4double distA = fPtrSolidA->DistanceToOut(p,v,calcNorm,validNorm,n) ;
463  G4double distB = fPtrSolidB->DistanceToIn(p,v) ;
464  if(distB < distA)
465  {
466  if(calcNorm)
467  {
468  *n = -(fPtrSolidB->SurfaceNormal(p+distB*v)) ;
469  *validNorm = false ;
470  }
471  distout= distB ;
472  }
473  else
474  {
475  distout= distA ;
476  }
477  return distout;
478 }
479 
481 //
482 // Inverted algorithm of DistanceToIn(p)
483 
484 G4double
486 {
487  G4double dist=0.0;
488 
489  if( Inside(p) == kOutside )
490  {
491 #ifdef G4BOOLDEBUG
492  G4cout << "WARNING - Invalid call in "
493  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
494  << " Point p is outside" << G4endl;
495  G4cout << " p = " << p << G4endl;
496  G4cerr << "WARNING - Invalid call in "
497  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
498  << " Point p is outside" << G4endl;
499  G4cerr << " p = " << p << G4endl;
500 #endif
501  }
502  else
503  {
505  fPtrSolidB->DistanceToIn(p) ) ;
506  }
507  return dist;
508 }
509 
511 //
512 //
513 
515 {
516  return G4String("G4SubtractionSolid");
517 }
518 
520 //
521 // Make a clone of the object
522 
524 {
525  return new G4SubtractionSolid(*this);
526 }
527 
529 //
530 //
531 
532 void
534  const G4int,
535  const G4VPhysicalVolume* )
536 {
537 }
538 
540 //
541 //
542 
543 void
545 {
546  scene.AddSolid (*this);
547 }
548 
550 //
551 //
552 
553 G4Polyhedron*
555 {
556  HepPolyhedronProcessor processor;
557  // Stack components and components of components recursively
558  // See G4BooleanSolid::StackPolyhedron
559  G4Polyhedron* top = StackPolyhedron(processor, this);
560  G4Polyhedron* result = new G4Polyhedron(*top);
561  if (processor.execute(*result)) { return result; }
562  else { return 0; }
563 }
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 const G4double kInfinity
Definition: geomdefs.hh:42
CLHEP::Hep3Vector G4ThreeVector
CLHEP::HepRotation G4RotationMatrix
G4double a
Definition: TRTMaterials.hh:39
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
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
static const double mm
Definition: G4SIunits.hh:114
G4Polyhedron * StackPolyhedron(HepPolyhedronProcessor &, const G4VSolid *) const
static G4GeometryTolerance * GetInstance()
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4GLOB_DLL std::ostream G4cerr