Geant4  10.02.p03
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 102292 2017-01-20 11:27:42Z 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 // Calculate extent under transform and specified limit
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, dist2 = 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  dist2 = dist+disTmp;
302  if (dist == dist2) { return dist; } // no progress
303  dist = dist2 ;
304  count1++;
305  if( count1 > 1000 ) // Infinite loop detected
306  {
307  G4String nameB = fPtrSolidB->GetName();
308  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
309  {
310  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
311  ->GetConstituentMovedSolid()->GetName();
312  }
313  std::ostringstream message;
314  message << "Illegal condition caused by solids: "
315  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
316  message.precision(16);
317  message << "Looping detected in point " << p+dist*v
318  << ", from original point " << p
319  << " and direction " << v << G4endl
320  << "Computed candidate distance: " << dist << "*mm. ";
321  message.precision(6);
322  DumpInfo();
323  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
324  "GeomSolids1001", JustWarning, message,
325  "Returning candidate distance.");
326  return dist;
327  }
328  }
329  }
330  while( Inside(p+dist*v) == kOutside ) ;
331  }
332  }
333  else // p outside A, start in A
334  {
335  dist = fPtrSolidA->DistanceToIn(p,v) ;
336 
337  if( dist == kInfinity ) // past A, hence past A\B
338  {
339  return kInfinity ;
340  }
341  else
342  {
343  G4int count2=0;
344  while( Inside(p+dist*v) == kOutside ) // pushing loop
345  {
346  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
347  dist += disTmp ;
348 
349  if( Inside(p+dist*v) == kOutside )
350  {
351  disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
352 
353  if(disTmp == kInfinity) // past A, hence past A\B
354  {
355  return kInfinity ;
356  }
357  dist2 = dist+disTmp;
358  if (dist == dist2) { return dist; } // no progress
359  dist = dist2 ;
360  count2++;
361  if( count2 > 1000 ) // Infinite loop detected
362  {
363  G4String nameB = fPtrSolidB->GetName();
364  if(fPtrSolidB->GetEntityType()=="G4DisplacedSolid")
365  {
366  nameB = (dynamic_cast<G4DisplacedSolid*>(fPtrSolidB))
367  ->GetConstituentMovedSolid()->GetName();
368  }
369  std::ostringstream message;
370  message << "Illegal condition caused by solids: "
371  << fPtrSolidA->GetName() << " and " << nameB << G4endl;
372  message.precision(16);
373  message << "Looping detected in point " << p+dist*v
374  << ", from original point " << p
375  << " and direction " << v << G4endl
376  << "Computed candidate distance: " << dist << "*mm. ";
377  message.precision(6);
378  DumpInfo();
379  G4Exception("G4SubtractionSolid::DistanceToIn(p,v)",
380  "GeomSolids1001", JustWarning, message,
381  "Returning candidate distance.");
382  return dist;
383  }
384  }
385  } // Loop checking, 13.08.2015, G.Cosmo
386  }
387  }
388 
389  return dist ;
390 }
391 
393 //
394 // Approximate nearest distance from the point p to the intersection of
395 // two solids. It is usually underestimated from the point of view of
396 // isotropic safety
397 
398 G4double
400 {
401  G4double dist=0.0;
402 
403 #ifdef G4BOOLDEBUG
404  if( Inside(p) == kInside )
405  {
406  G4cout << "WARNING - Invalid call in "
407  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
408  << " Point p is inside !" << G4endl;
409  G4cout << " p = " << p << G4endl;
410  G4cerr << "WARNING - Invalid call in "
411  << "G4SubtractionSolid::DistanceToIn(p)" << G4endl
412  << " Point p is inside !" << G4endl;
413  G4cerr << " p = " << p << G4endl;
414  }
415 #endif
416 
417  if( ( fPtrSolidA->Inside(p) != kOutside) && // case 1
418  ( fPtrSolidB->Inside(p) != kOutside) )
419  {
420  dist= fPtrSolidB->DistanceToOut(p) ;
421  }
422  else
423  {
424  dist= fPtrSolidA->DistanceToIn(p) ;
425  }
426 
427  return dist;
428 }
429 
431 //
432 // The same algorithm as DistanceToOut(p)
433 
434 G4double
436  const G4ThreeVector& v,
437  const G4bool calcNorm,
438  G4bool *validNorm,
439  G4ThreeVector *n ) const
440 {
441 #ifdef G4BOOLDEBUG
442  if( Inside(p) == kOutside )
443  {
444  G4cout << "Position:" << G4endl << G4endl;
445  G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
446  G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
447  G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
448  G4cout << "Direction:" << G4endl << G4endl;
449  G4cout << "v.x() = " << v.x() << G4endl;
450  G4cout << "v.y() = " << v.y() << G4endl;
451  G4cout << "v.z() = " << v.z() << G4endl << G4endl;
452  G4cout << "WARNING - Invalid call in "
453  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
454  << " Point p is outside !" << G4endl;
455  G4cout << " p = " << p << G4endl;
456  G4cout << " v = " << v << G4endl;
457  G4cerr << "WARNING - Invalid call in "
458  << "G4SubtractionSolid::DistanceToOut(p,v)" << G4endl
459  << " Point p is outside !" << G4endl;
460  G4cerr << " p = " << p << G4endl;
461  G4cerr << " v = " << v << G4endl;
462  }
463 #endif
464 
465  G4double distout;
466  G4double distA = fPtrSolidA->DistanceToOut(p,v,calcNorm,validNorm,n) ;
467  G4double distB = fPtrSolidB->DistanceToIn(p,v) ;
468  if(distB < distA)
469  {
470  if(calcNorm)
471  {
472  *n = -(fPtrSolidB->SurfaceNormal(p+distB*v)) ;
473  *validNorm = false ;
474  }
475  distout= distB ;
476  }
477  else
478  {
479  distout= distA ;
480  }
481  return distout;
482 }
483 
485 //
486 // Inverted algorithm of DistanceToIn(p)
487 
488 G4double
490 {
491  G4double dist=0.0;
492 
493  if( Inside(p) == kOutside )
494  {
495 #ifdef G4BOOLDEBUG
496  G4cout << "WARNING - Invalid call in "
497  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
498  << " Point p is outside" << G4endl;
499  G4cout << " p = " << p << G4endl;
500  G4cerr << "WARNING - Invalid call in "
501  << "G4SubtractionSolid::DistanceToOut(p)" << G4endl
502  << " Point p is outside" << G4endl;
503  G4cerr << " p = " << p << G4endl;
504 #endif
505  }
506  else
507  {
509  fPtrSolidB->DistanceToIn(p) ) ;
510  }
511  return dist;
512 }
513 
515 //
516 //
517 
519 {
520  return G4String("G4SubtractionSolid");
521 }
522 
524 //
525 // Make a clone of the object
526 
528 {
529  return new G4SubtractionSolid(*this);
530 }
531 
533 //
534 //
535 
536 void
538  const G4int,
539  const G4VPhysicalVolume* )
540 {
541 }
542 
544 //
545 //
546 
547 void
549 {
550  scene.AddSolid (*this);
551 }
552 
554 //
555 //
556 
557 G4Polyhedron*
559 {
561  // Stack components and components of components recursively
562  // See G4BooleanSolid::StackPolyhedron
563  G4Polyhedron* top = StackPolyhedron(processor, this);
564  G4Polyhedron* result = new G4Polyhedron(*top);
565  if (processor.execute(*result)) { return result; }
566  else { return 0; }
567 }
G4VSolid * fPtrSolidB
virtual G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const =0
EInside Inside(const G4ThreeVector &p) const
static const G4double kInfinity
Definition: geomdefs.hh:42
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const
virtual G4GeometryType GetEntityType() const =0
virtual void AddSolid(const G4Box &)=0
int G4int
Definition: G4Types.hh:78
G4String GetName() const
void DumpInfo() const
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
Char_t n[5]
G4GLOB_DLL std::ostream G4cout
G4double GetRadialTolerance() const
virtual EInside Inside(const G4ThreeVector &p) const =0
void DescribeYourselfTo(G4VGraphicsScene &scene) const
bool G4bool
Definition: G4Types.hh:79
G4SubtractionSolid & operator=(const G4SubtractionSolid &rhs)
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
G4SubtractionSolid(const G4String &pName, G4VSolid *pSolidA, G4VSolid *pSolidB)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
double x() const
#define processor
Definition: xmlparse.cc:617
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
double y() const
EInside
Definition: geomdefs.hh:58
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
EAxis
Definition: geomdefs.hh:54
double z() const
G4VSolid * fPtrSolidA
#define G4endl
Definition: G4ios.hh:61
G4VSolid * Clone() const
G4BooleanSolid & operator=(const G4BooleanSolid &rhs)
double G4double
Definition: G4Types.hh:76
G4Polyhedron * StackPolyhedron(HepPolyhedronProcessor &, const G4VSolid *) const
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const =0
G4GeometryType GetEntityType() const
static const double mm
Definition: G4SIunits.hh:114
bool execute(HepPolyhedron &)
static G4GeometryTolerance * GetInstance()
G4Polyhedron * CreatePolyhedron() const
G4GLOB_DLL std::ostream G4cerr