Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/Boolean/src/G4MultiUnion.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /geometry/solids/Boolean/src/G4MultiUnion.cc (Version 11.3.0) and /geometry/solids/Boolean/src/G4MultiUnion.cc (Version 11.2.2)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 // Implementation of G4MultiUnion class            26 // Implementation of G4MultiUnion class
 27 //                                                 27 //
 28 // 19.10.12 M.Gayer - Original implementation      28 // 19.10.12 M.Gayer - Original implementation from USolids module
 29 // 06.04.17 G.Cosmo - Adapted implementation i     29 // 06.04.17 G.Cosmo - Adapted implementation in Geant4 for VecGeom migration
 30 // -------------------------------------------     30 // --------------------------------------------------------------------
 31                                                    31 
 32 #include <iostream>                                32 #include <iostream>
 33 #include <sstream>                                 33 #include <sstream>
 34                                                    34 
 35 #include "G4MultiUnion.hh"                         35 #include "G4MultiUnion.hh"
 36 #include "Randomize.hh"                            36 #include "Randomize.hh"
 37 #include "G4GeometryTolerance.hh"                  37 #include "G4GeometryTolerance.hh"
 38 #include "G4BoundingEnvelope.hh"                   38 #include "G4BoundingEnvelope.hh"
 39 #include "G4AffineTransform.hh"                    39 #include "G4AffineTransform.hh"
 40 #include "G4DisplacedSolid.hh"                     40 #include "G4DisplacedSolid.hh"
 41                                                    41 
 42 #include "G4VGraphicsScene.hh"                     42 #include "G4VGraphicsScene.hh"
 43 #include "G4Polyhedron.hh"                         43 #include "G4Polyhedron.hh"
 44 #include "G4PolyhedronArbitrary.hh"                44 #include "G4PolyhedronArbitrary.hh"
 45 #include "HepPolyhedronProcessor.h"                45 #include "HepPolyhedronProcessor.h"
 46                                                    46 
 47 #include "G4BooleanSolid.hh"                       47 #include "G4BooleanSolid.hh"
 48                                                    48 
 49 #include "G4AutoLock.hh"                           49 #include "G4AutoLock.hh"
 50                                                    50 
 51 namespace                                          51 namespace
 52 {                                                  52 {
 53   G4Mutex polyhedronMutex = G4MUTEX_INITIALIZE     53   G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
 54 }                                                  54 }
 55                                                    55 
 56 //____________________________________________     56 //______________________________________________________________________________
 57 G4MultiUnion::G4MultiUnion(const G4String& nam     57 G4MultiUnion::G4MultiUnion(const G4String& name)
 58   : G4VSolid(name)                                 58   : G4VSolid(name)
 59 {                                                  59 {
 60   SetName(name);                                   60   SetName(name);
 61   fSolids.clear();                                 61   fSolids.clear();
 62   fTransformObjs.clear();                          62   fTransformObjs.clear();
 63   kRadTolerance = G4GeometryTolerance::GetInst     63   kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance();
 64 }                                                  64 }
 65                                                    65 
 66 //____________________________________________     66 //______________________________________________________________________________
 67 G4MultiUnion::~G4MultiUnion()                      67 G4MultiUnion::~G4MultiUnion()
 68 = default;                                         68 = default;
 69                                                    69 
 70 //____________________________________________     70 //______________________________________________________________________________
 71 void G4MultiUnion::AddNode(G4VSolid& solid, co     71 void G4MultiUnion::AddNode(G4VSolid& solid, const G4Transform3D& trans)
 72 {                                                  72 {
 73   fSolids.push_back(&solid);                       73   fSolids.push_back(&solid);
 74   fTransformObjs.push_back(trans);  // Store a     74   fTransformObjs.push_back(trans);  // Store a local copy of transformations
 75 }                                                  75 }
 76                                                    76 
 77 //____________________________________________     77 //______________________________________________________________________________
 78 void G4MultiUnion::AddNode(G4VSolid* solid, co     78 void G4MultiUnion::AddNode(G4VSolid* solid, const G4Transform3D& trans)
 79 {                                                  79 {
 80   fSolids.push_back(solid);                        80   fSolids.push_back(solid);
 81   fTransformObjs.push_back(trans);  // Store a     81   fTransformObjs.push_back(trans);  // Store a local copy of transformations
 82 }                                                  82 }
 83                                                    83 
 84 //____________________________________________     84 //______________________________________________________________________________
 85 G4VSolid* G4MultiUnion::Clone() const              85 G4VSolid* G4MultiUnion::Clone() const
 86 {                                                  86 {
 87   return new G4MultiUnion(*this);                  87   return new G4MultiUnion(*this);
 88 }                                                  88 }
 89                                                    89 
 90 // Copy constructor                                90 // Copy constructor
 91 //____________________________________________     91 //______________________________________________________________________________
 92 G4MultiUnion::G4MultiUnion(const G4MultiUnion&     92 G4MultiUnion::G4MultiUnion(const G4MultiUnion& rhs)
 93   : G4VSolid(rhs), fCubicVolume(rhs.fCubicVolu     93   : G4VSolid(rhs), fCubicVolume(rhs.fCubicVolume),
 94     fSurfaceArea(rhs.fSurfaceArea),                94     fSurfaceArea(rhs.fSurfaceArea),
 95     kRadTolerance(rhs.kRadTolerance), fAccurat     95     kRadTolerance(rhs.kRadTolerance), fAccurate(rhs.fAccurate)
 96 {                                                  96 {
 97 }                                                  97 }
 98                                                    98 
 99 // Fake default constructor for persistency        99 // Fake default constructor for persistency
100 //____________________________________________    100 //______________________________________________________________________________
101 G4MultiUnion::G4MultiUnion( __void__& a )         101 G4MultiUnion::G4MultiUnion( __void__& a )
102   : G4VSolid(a)                                   102   : G4VSolid(a)
103 {                                                 103 {
104 }                                                 104 }
105                                                   105 
106 // Assignment operator                            106 // Assignment operator
107 //____________________________________________    107 //______________________________________________________________________________
108 G4MultiUnion& G4MultiUnion::operator = (const     108 G4MultiUnion& G4MultiUnion::operator = (const G4MultiUnion& rhs)
109 {                                                 109 {
110   // Check assignment to self                     110   // Check assignment to self
111   //                                              111   //
112   if (this == &rhs)                               112   if (this == &rhs)
113   {                                               113   {
114     return *this;                                 114     return *this;
115   }                                               115   }
116                                                   116 
117   // Copy base class data                         117   // Copy base class data
118   //                                              118   //
119   G4VSolid::operator=(rhs);                       119   G4VSolid::operator=(rhs);
120                                                   120 
121   return *this;                                   121   return *this;
122 }                                                 122 }
123                                                   123 
124 //____________________________________________    124 //______________________________________________________________________________
125 G4double G4MultiUnion::GetCubicVolume()           125 G4double G4MultiUnion::GetCubicVolume()
126 {                                                 126 {
                                                   >> 127   // Computes the cubic volume of the "G4MultiUnion" structure using
                                                   >> 128   // random points
                                                   >> 129 
127   if (fCubicVolume == 0.0)                        130   if (fCubicVolume == 0.0)
128   {                                               131   {
129     fCubicVolume = EstimateCubicVolume(1000000 << 132     G4ThreeVector extentMin, extentMax, d, p, point;
                                                   >> 133     G4int inside = 0, generated;
                                                   >> 134     BoundingLimits(extentMin, extentMax);
                                                   >> 135     d = (extentMax - extentMin) / 2.;
                                                   >> 136     p = (extentMax + extentMin) / 2.;
                                                   >> 137     G4ThreeVector left = p - d;
                                                   >> 138     G4ThreeVector length = d * 2;
                                                   >> 139     for (generated = 0; generated < 10000; ++generated)
                                                   >> 140     {
                                                   >> 141       G4ThreeVector rvec(G4UniformRand(), G4UniformRand(), G4UniformRand());
                                                   >> 142       point = left + G4ThreeVector(length.x()*rvec.x(),
                                                   >> 143                                    length.y()*rvec.y(),
                                                   >> 144                                    length.z()*rvec.z());
                                                   >> 145       if (Inside(point) != EInside::kOutside) ++inside;
                                                   >> 146     }
                                                   >> 147     G4double vbox = (2 * d.x()) * (2 * d.y()) * (2 * d.z());
                                                   >> 148     fCubicVolume = inside * vbox / generated;
130   }                                               149   }
131   return fCubicVolume;                            150   return fCubicVolume;
132 }                                                 151 }
133                                                   152 
134 //____________________________________________    153 //______________________________________________________________________________
135 G4double                                          154 G4double
136 G4MultiUnion::DistanceToInNoVoxels(const G4Thr    155 G4MultiUnion::DistanceToInNoVoxels(const G4ThreeVector& aPoint,
137                                    const G4Thr    156                                    const G4ThreeVector& aDirection) const
138 {                                                 157 {
139   G4ThreeVector direction = aDirection.unit();    158   G4ThreeVector direction = aDirection.unit();
140   G4ThreeVector localPoint, localDirection;       159   G4ThreeVector localPoint, localDirection;
141   G4double minDistance = kInfinity;               160   G4double minDistance = kInfinity;
142                                                   161 
143   std::size_t numNodes = fSolids.size();          162   std::size_t numNodes = fSolids.size();
144   for (std::size_t i = 0 ; i < numNodes ; ++i)    163   for (std::size_t i = 0 ; i < numNodes ; ++i)
145   {                                               164   {
146     G4VSolid& solid = *fSolids[i];                165     G4VSolid& solid = *fSolids[i];
147     const G4Transform3D& transform = fTransfor    166     const G4Transform3D& transform = fTransformObjs[i];
148                                                   167 
149     localPoint = GetLocalPoint(transform, aPoi    168     localPoint = GetLocalPoint(transform, aPoint);
150     localDirection = GetLocalVector(transform,    169     localDirection = GetLocalVector(transform, direction);
151                                                   170 
152     G4double distance = solid.DistanceToIn(loc    171     G4double distance = solid.DistanceToIn(localPoint, localDirection);
153     if (minDistance > distance) minDistance =     172     if (minDistance > distance) minDistance = distance;
154   }                                               173   }
155   return minDistance;                             174   return minDistance;
156 }                                                 175 }
157                                                   176 
158 //____________________________________________    177 //______________________________________________________________________________
159 G4double G4MultiUnion::DistanceToInCandidates(    178 G4double G4MultiUnion::DistanceToInCandidates(const G4ThreeVector& aPoint,
160                                                   179                                               const G4ThreeVector& direction,
161                                                   180                                               std::vector<G4int>& candidates,
162                                                   181                                               G4SurfBits& bits) const
163 {                                                 182 {
164   std::size_t candidatesCount = candidates.siz    183   std::size_t candidatesCount = candidates.size();
165   G4ThreeVector localPoint, localDirection;       184   G4ThreeVector localPoint, localDirection;
166                                                   185 
167   G4double minDistance = kInfinity;               186   G4double minDistance = kInfinity;
168   for (std::size_t i = 0 ; i < candidatesCount    187   for (std::size_t i = 0 ; i < candidatesCount; ++i)
169   {                                               188   {
170     G4int candidate = candidates[i];              189     G4int candidate = candidates[i];
171     G4VSolid& solid = *fSolids[candidate];        190     G4VSolid& solid = *fSolids[candidate];
172     const G4Transform3D& transform = fTransfor    191     const G4Transform3D& transform = fTransformObjs[candidate];
173                                                   192 
174     localPoint = GetLocalPoint(transform, aPoi    193     localPoint = GetLocalPoint(transform, aPoint);
175     localDirection = GetLocalVector(transform,    194     localDirection = GetLocalVector(transform, direction);
176     G4double distance = solid.DistanceToIn(loc    195     G4double distance = solid.DistanceToIn(localPoint, localDirection);
177     if (minDistance > distance) minDistance =     196     if (minDistance > distance) minDistance = distance;
178     bits.SetBitNumber(candidate);                 197     bits.SetBitNumber(candidate);
179     if (minDistance == 0) break;                  198     if (minDistance == 0) break;
180   }                                               199   }
181   return minDistance;                             200   return minDistance;
182 }                                                 201 }
183                                                   202 
184 // Algorithm note: we have to look also for al    203 // Algorithm note: we have to look also for all other objects in next voxels,
185 // if the distance is not shorter ... we have     204 // if the distance is not shorter ... we have to do it because,
186 // for example for objects which starts in fir    205 // for example for objects which starts in first voxel in which they
187 // do not collide with direction line, but in     206 // do not collide with direction line, but in second it collides...
188 // The idea of crossing voxels would be still     207 // The idea of crossing voxels would be still applicable,
189 // because this way we could exclude from the     208 // because this way we could exclude from the testing such solids,
190 // which were found that obviously are not goo    209 // which were found that obviously are not good candidates, because
191 // they would return infinity                     210 // they would return infinity
192 // But if distance is smaller than the shift t    211 // But if distance is smaller than the shift to next voxel, we can return
193 // it immediately                                 212 // it immediately
194 //____________________________________________    213 //______________________________________________________________________________
195 G4double G4MultiUnion::DistanceToIn(const G4Th    214 G4double G4MultiUnion::DistanceToIn(const G4ThreeVector& aPoint,
196                                     const G4Th    215                                     const G4ThreeVector& aDirection) const
197 {                                                 216 {
198   G4double minDistance = kInfinity;               217   G4double minDistance = kInfinity;
199   G4ThreeVector direction = aDirection.unit();    218   G4ThreeVector direction = aDirection.unit();
200   G4double shift = fVoxels.DistanceToFirst(aPo    219   G4double shift = fVoxels.DistanceToFirst(aPoint, direction);
201   if (shift == kInfinity) return shift;           220   if (shift == kInfinity) return shift;
202                                                   221 
203   G4ThreeVector currentPoint = aPoint;            222   G4ThreeVector currentPoint = aPoint;
204   if (shift != 0.0) currentPoint += direction     223   if (shift != 0.0) currentPoint += direction * shift;
205                                                   224 
206   G4SurfBits exclusion(fVoxels.GetBitsPerSlice    225   G4SurfBits exclusion(fVoxels.GetBitsPerSlice());
207   std::vector<G4int> candidates, curVoxel(3);     226   std::vector<G4int> candidates, curVoxel(3);
208   fVoxels.GetVoxel(curVoxel, currentPoint);       227   fVoxels.GetVoxel(curVoxel, currentPoint);
209                                                   228 
210   do                                              229   do
211   {                                               230   {
212     {                                             231     {
213       if (fVoxels.GetCandidatesVoxelArray(curV    232       if (fVoxels.GetCandidatesVoxelArray(curVoxel, candidates, &exclusion) != 0)
214       {                                           233       {
215         G4double distance = DistanceToInCandid    234         G4double distance = DistanceToInCandidates(aPoint, direction,
216                                                   235                                                    candidates, exclusion);
217         if (minDistance > distance) minDistanc    236         if (minDistance > distance) minDistance = distance;
218         if (distance < shift) break;              237         if (distance < shift) break;
219       }                                           238       }
220     }                                             239     }
221     shift = fVoxels.DistanceToNext(aPoint, dir    240     shift = fVoxels.DistanceToNext(aPoint, direction, curVoxel);
222   }                                               241   }
223   while (minDistance > shift);                    242   while (minDistance > shift);
224                                                   243  
225   return minDistance;                             244   return minDistance;
226 }                                                 245 }
227                                                   246 
228 //____________________________________________    247 //______________________________________________________________________________
229 G4double G4MultiUnion::DistanceToOutNoVoxels(c    248 G4double G4MultiUnion::DistanceToOutNoVoxels(const G4ThreeVector& aPoint,
230                                              c    249                                              const G4ThreeVector& aDirection,
231                                              G    250                                              G4ThreeVector* aNormal) const
232 {                                                 251 {
233   // Computes distance from a point presumably    252   // Computes distance from a point presumably outside the solid to the solid
234   // surface. Ignores first surface if the poi    253   // surface. Ignores first surface if the point is actually inside.
235   // Early return infinity in case the safety     254   // Early return infinity in case the safety to any surface is found greater
236   // than the proposed step aPstep.               255   // than the proposed step aPstep.
237   // The normal vector to the crossed surface     256   // The normal vector to the crossed surface is filled only in case the box
238   // is crossed, otherwise aNormal->IsNull() i    257   // is crossed, otherwise aNormal->IsNull() is true.
239                                                   258 
240   // algorithm:                                   259   // algorithm:
241   G4ThreeVector direction = aDirection.unit();    260   G4ThreeVector direction = aDirection.unit();
242   G4ThreeVector localPoint, localDirection;       261   G4ThreeVector localPoint, localDirection;
243   G4int ignoredSolid = -1;                        262   G4int ignoredSolid = -1;
244   G4double resultDistToOut = 0;                   263   G4double resultDistToOut = 0;
245   G4ThreeVector currentPoint = aPoint;            264   G4ThreeVector currentPoint = aPoint;
246                                                   265 
247   auto numNodes = (G4int)fSolids.size();          266   auto numNodes = (G4int)fSolids.size();
248   for (auto i = 0; i < numNodes; ++i)             267   for (auto i = 0; i < numNodes; ++i)
249   {                                               268   {
250     if (i != ignoredSolid)                        269     if (i != ignoredSolid)
251     {                                             270     {
252       G4VSolid& solid = *fSolids[i];              271       G4VSolid& solid = *fSolids[i];
253       const G4Transform3D& transform = fTransf    272       const G4Transform3D& transform = fTransformObjs[i];
254       localPoint = GetLocalPoint(transform, cu    273       localPoint = GetLocalPoint(transform, currentPoint);
255       localDirection = GetLocalVector(transfor    274       localDirection = GetLocalVector(transform, direction);
256       EInside location = solid.Inside(localPoi    275       EInside location = solid.Inside(localPoint);
257       if (location != EInside::kOutside)          276       if (location != EInside::kOutside)
258       {                                           277       {
259         G4double distance = solid.DistanceToOu    278         G4double distance = solid.DistanceToOut(localPoint, localDirection,
260                                                   279                                                 false, nullptr, aNormal);
261         if (distance < kInfinity)                 280         if (distance < kInfinity)
262         {                                         281         {
263           if (resultDistToOut == kInfinity) re    282           if (resultDistToOut == kInfinity) resultDistToOut = 0;
264           if (distance > 0)                       283           if (distance > 0)
265           {                                       284           {
266             currentPoint = GetGlobalPoint(tran    285             currentPoint = GetGlobalPoint(transform, localPoint
267                                           + di    286                                           + distance*localDirection);
268             resultDistToOut += distance;          287             resultDistToOut += distance;
269             ignoredSolid = i; // skip the soli    288             ignoredSolid = i; // skip the solid which we have just left
270             i = -1; // force the loop to conti    289             i = -1; // force the loop to continue from 0
271           }                                       290           }
272         }                                         291         }
273       }                                           292       }
274     }                                             293     }
275   }                                               294   }
276   return resultDistToOut;                         295   return resultDistToOut;
277 }                                                 296 }
278                                                   297 
279 //____________________________________________    298 //______________________________________________________________________________
280 G4double G4MultiUnion::DistanceToOut(const G4T    299 G4double G4MultiUnion::DistanceToOut(const G4ThreeVector& aPoint,
281                                      const G4T    300                                      const G4ThreeVector& aDirection,
282                                      const G4b    301                                      const G4bool /* calcNorm */,
283                                      G4bool* /    302                                      G4bool* /* validNorm */,
284                                      G4ThreeVe    303                                      G4ThreeVector* aNormal) const
285 {                                                 304 {
286   return DistanceToOutVoxels(aPoint, aDirectio    305   return DistanceToOutVoxels(aPoint, aDirection, aNormal);
287 }                                                 306 }
288                                                   307 
289 //____________________________________________    308 //______________________________________________________________________________
290 G4double G4MultiUnion::DistanceToOutVoxels(con    309 G4double G4MultiUnion::DistanceToOutVoxels(const G4ThreeVector& aPoint,
291                                            con    310                                            const G4ThreeVector& aDirection,
292                                            G4T    311                                            G4ThreeVector* aNormal) const
293 {                                                 312 {
294   // Computes distance from a point presumably    313   // Computes distance from a point presumably inside the solid to the solid
295   // surface. Ignores first surface along each    314   // surface. Ignores first surface along each axis systematically (for points
296   // inside or outside. Early returns zero in     315   // inside or outside. Early returns zero in case the second surface is behind
297   // the starting point.                          316   // the starting point.
298   // o The proposed step is ignored.              317   // o The proposed step is ignored.
299   // o The normal vector to the crossed surfac    318   // o The normal vector to the crossed surface is always filled.
300                                                   319 
301   // In the case the considered point is locat    320   // In the case the considered point is located inside the G4MultiUnion
302   // structure, the treatments are as follows:    321   // structure, the treatments are as follows:
303   //      - investigation of the candidates fo    322   //      - investigation of the candidates for the passed point
304   //      - progressive moving of the point to    323   //      - progressive moving of the point towards the surface, along the
305   //        passed direction                      324   //        passed direction
306   //      - processing of the normal              325   //      - processing of the normal
307                                                   326 
308   G4ThreeVector direction = aDirection.unit();    327   G4ThreeVector direction = aDirection.unit();
309   std::vector<G4int> candidates;                  328   std::vector<G4int> candidates;
310   G4double distance = 0;                          329   G4double distance = 0;
311   std::size_t numNodes = 2*fSolids.size();        330   std::size_t numNodes = 2*fSolids.size();
312   std::size_t count=0;                            331   std::size_t count=0;
313                                                   332 
314   if (fVoxels.GetCandidatesVoxelArray(aPoint,     333   if (fVoxels.GetCandidatesVoxelArray(aPoint, candidates) != 0)
315   {                                               334   {
316     // For normal case for which we presume th    335     // For normal case for which we presume the point is inside
317     G4ThreeVector localPoint, localDirection,     336     G4ThreeVector localPoint, localDirection, localNormal;
318     G4ThreeVector currentPoint = aPoint;          337     G4ThreeVector currentPoint = aPoint;
319     G4SurfBits exclusion(fVoxels.GetBitsPerSli    338     G4SurfBits exclusion(fVoxels.GetBitsPerSlice());
320     G4bool notOutside;                            339     G4bool notOutside;
321     G4ThreeVector maxNormal;                      340     G4ThreeVector maxNormal;
322                                                   341 
323     do                                            342     do
324     {                                             343     {
325       notOutside = false;                         344       notOutside = false;
326                                                   345 
327       G4double maxDistance = -kInfinity;          346       G4double maxDistance = -kInfinity;
328       G4int maxCandidate = 0;                     347       G4int maxCandidate = 0;
329       G4ThreeVector maxLocalPoint;                348       G4ThreeVector maxLocalPoint;
330                                                   349 
331       std::size_t limit = candidates.size();      350       std::size_t limit = candidates.size();
332       for (std::size_t i = 0 ; i < limit ; ++i    351       for (std::size_t i = 0 ; i < limit ; ++i)
333       {                                           352       {
334         G4int candidate = candidates[i];          353         G4int candidate = candidates[i];
335         // ignore the current component (that     354         // ignore the current component (that you just got out of) since
336         // numerically the propagated point wi    355         // numerically the propagated point will be on its surface
337                                                   356 
338         G4VSolid& solid = *fSolids[candidate];    357         G4VSolid& solid = *fSolids[candidate];
339         const G4Transform3D& transform = fTran    358         const G4Transform3D& transform = fTransformObjs[candidate];
340                                                   359 
341         // The coordinates of the point are mo    360         // The coordinates of the point are modified so as to fit the
342         // intrinsic solid local frame:           361         // intrinsic solid local frame:
343         localPoint = GetLocalPoint(transform,     362         localPoint = GetLocalPoint(transform, currentPoint);
344                                                   363 
345         // DistanceToOut at least for Trd some    364         // DistanceToOut at least for Trd sometimes return non-zero value
346         // even from points that are outside.     365         // even from points that are outside. Therefore, this condition
347         // must currently be here, otherwise i    366         // must currently be here, otherwise it would not work.
348         // But it means it would be slower.       367         // But it means it would be slower.
349                                                   368 
350         if (solid.Inside(localPoint) != EInsid    369         if (solid.Inside(localPoint) != EInside::kOutside)
351         {                                         370         {
352           notOutside = true;                      371           notOutside = true;
353                                                   372 
354           localDirection = GetLocalVector(tran    373           localDirection = GetLocalVector(transform, direction);
355                                                   374 
356           // propagate with solid.DistanceToOu    375           // propagate with solid.DistanceToOut
357           G4double shift = solid.DistanceToOut    376           G4double shift = solid.DistanceToOut(localPoint, localDirection,
358                                                   377                                                false, nullptr, &localNormal);
359           if (maxDistance < shift)                378           if (maxDistance < shift)
360           {                                       379           {
361             maxDistance = shift;                  380             maxDistance = shift;
362             maxCandidate = candidate;             381             maxCandidate = candidate;
363             maxNormal = localNormal;              382             maxNormal = localNormal;
364           }                                       383           }
365         }                                         384         }
366       }                                           385       }
367                                                   386 
368       if (notOutside)                             387       if (notOutside)
369       {                                           388       {
370         const G4Transform3D& transform = fTran    389         const G4Transform3D& transform = fTransformObjs[maxCandidate];
371                                                   390 
372         // convert from local normal              391         // convert from local normal
373         if (aNormal != nullptr) *aNormal = Get    392         if (aNormal != nullptr) *aNormal = GetGlobalVector(transform, maxNormal);
374                                                   393 
375         distance += maxDistance;                  394         distance += maxDistance;
376         currentPoint += maxDistance * directio    395         currentPoint += maxDistance * direction;
377         if(maxDistance == 0.) ++count;            396         if(maxDistance == 0.) ++count;
378                                                   397 
379         // the current component will be ignor    398         // the current component will be ignored
380         exclusion.SetBitNumber(maxCandidate);     399         exclusion.SetBitNumber(maxCandidate);
381         EInside location = InsideWithExclusion    400         EInside location = InsideWithExclusion(currentPoint, &exclusion);
382                                                   401 
383         // perform a Inside                       402         // perform a Inside
384         // it should be excluded current solid    403         // it should be excluded current solid from checking
385         // we have to collect the maximum dist    404         // we have to collect the maximum distance from all given candidates.
386         // such "maximum" candidate should be     405         // such "maximum" candidate should be then used for finding next
387         // candidates                             406         // candidates
388         if (location == EInside::kOutside)        407         if (location == EInside::kOutside)
389         {                                         408         {
390           // else return cumulated distances t    409           // else return cumulated distances to outside of the traversed
391           // components                           410           // components
392           break;                                  411           break;
393         }                                         412         }
394         // if inside another component, redo 1    413         // if inside another component, redo 1 to 3 but add the next
395         // DistanceToOut on top of the previou    414         // DistanceToOut on top of the previous.
396                                                   415 
397         // and fill the candidates for the cor    416         // and fill the candidates for the corresponding voxel (just
398         // exiting current component along dir    417         // exiting current component along direction)
399         candidates.clear();                       418         candidates.clear();
400                                                   419 
401         fVoxels.GetCandidatesVoxelArray(curren    420         fVoxels.GetCandidatesVoxelArray(currentPoint, candidates, &exclusion);
402         exclusion.ResetBitNumber(maxCandidate)    421         exclusion.ResetBitNumber(maxCandidate);
403       }                                           422       }
404     }                                             423     }
405     while  ((notOutside) && (count < numNodes)    424     while  ((notOutside) && (count < numNodes));
406   }                                               425   }
407                                                   426 
408   return distance;                                427   return distance;
409 }                                                 428 }
410                                                   429 
411 //____________________________________________    430 //______________________________________________________________________________
412 EInside G4MultiUnion::InsideWithExclusion(cons    431 EInside G4MultiUnion::InsideWithExclusion(const G4ThreeVector& aPoint,
413                                           G4Su    432                                           G4SurfBits* exclusion) const
414 {                                                 433 {
415   // Classify point location with respect to s    434   // Classify point location with respect to solid:
416   //  o eInside       - inside the solid          435   //  o eInside       - inside the solid
417   //  o eSurface      - close to surface withi    436   //  o eSurface      - close to surface within tolerance
418   //  o eOutside      - outside the solid         437   //  o eOutside      - outside the solid
419                                                   438 
420   // Hitherto, it is considered that only para    439   // Hitherto, it is considered that only parallelepipedic nodes
421   // can be added to the container                440   // can be added to the container
422                                                   441 
423   // Implementation using voxelisation techniq    442   // Implementation using voxelisation techniques:
424   // -----------------------------------------    443   // ---------------------------------------------
425                                                   444 
426   G4ThreeVector localPoint;                       445   G4ThreeVector localPoint;
427   EInside location = EInside::kOutside;           446   EInside location = EInside::kOutside;
428                                                   447 
429   std::vector<G4int> candidates;                  448   std::vector<G4int> candidates;
430   std::vector<G4MultiUnionSurface> surfaces;      449   std::vector<G4MultiUnionSurface> surfaces;
431                                                   450 
432   // TODO: test if it works well and if so mea    451   // TODO: test if it works well and if so measure performance
433   // TODO: getPointIndex should not be used, i    452   // TODO: getPointIndex should not be used, instead GetVoxel + GetVoxelsIndex
434   //       should be used                         453   //       should be used
435   // TODO: than pass result to GetVoxel furthe    454   // TODO: than pass result to GetVoxel further to GetCandidatesVoxelArray
436   // TODO: eventually GetVoxel should be inlin    455   // TODO: eventually GetVoxel should be inlined here, early exit if any
437   //       binary search is -1                    456   //       binary search is -1
438                                                   457 
439   G4int limit = fVoxels.GetCandidatesVoxelArra    458   G4int limit = fVoxels.GetCandidatesVoxelArray(aPoint, candidates, exclusion);
440   for (G4int i = 0 ; i < limit ; ++i)             459   for (G4int i = 0 ; i < limit ; ++i)
441   {                                               460   {
442     G4int candidate = candidates[i];              461     G4int candidate = candidates[i];
443     G4VSolid& solid = *fSolids[candidate];        462     G4VSolid& solid = *fSolids[candidate];
444     const G4Transform3D& transform = fTransfor    463     const G4Transform3D& transform = fTransformObjs[candidate];
445                                                   464 
446     // The coordinates of the point are modifi    465     // The coordinates of the point are modified so as to fit the intrinsic
447     // solid local frame:                         466     // solid local frame:
448     localPoint = GetLocalPoint(transform, aPoi    467     localPoint = GetLocalPoint(transform, aPoint);
449     location = solid.Inside(localPoint);          468     location = solid.Inside(localPoint);
450     if (location == EInside::kInside) return E    469     if (location == EInside::kInside) return EInside::kInside;
451     else if (location == EInside::kSurface)       470     else if (location == EInside::kSurface)
452     {                                             471     {
453       G4MultiUnionSurface surface;                472       G4MultiUnionSurface surface;
454       surface.point = localPoint;                 473       surface.point = localPoint;
455       surface.solid = &solid;                     474       surface.solid = &solid;
456       surfaces.push_back(surface);                475       surfaces.push_back(surface);
457     }                                             476     }
458   }                                               477   }
459                                                   478 
460   ////////////////////////////////////////////    479   ///////////////////////////////////////////////////////////////////////////
461   // Important comment: When two solids touch     480   // Important comment: When two solids touch each other along a flat
462   // surface, the surface points will be consi    481   // surface, the surface points will be considered as kSurface, while points
463   // located around will correspond to kInside    482   // located around will correspond to kInside (cf. G4UnionSolid)
464                                                   483 
465   std::size_t size = surfaces.size();             484   std::size_t size = surfaces.size();
466                                                   485 
467   if (size == 0)                                  486   if (size == 0)
468   {                                               487   {
469     return EInside::kOutside;                     488     return EInside::kOutside;
470   }                                               489   }
471                                                   490 
472   for (std::size_t i = 0; i < size - 1; ++i)      491   for (std::size_t i = 0; i < size - 1; ++i)
473   {                                               492   {
474     G4MultiUnionSurface& left = surfaces[i];      493     G4MultiUnionSurface& left = surfaces[i];
475     for (std::size_t j = i + 1; j < size; ++j)    494     for (std::size_t j = i + 1; j < size; ++j)
476     {                                             495     {
477       G4MultiUnionSurface& right = surfaces[j]    496       G4MultiUnionSurface& right = surfaces[j];
478       G4ThreeVector n, n2;                        497       G4ThreeVector n, n2;
479       n = left.solid->SurfaceNormal(left.point    498       n = left.solid->SurfaceNormal(left.point);
480       n2 = right.solid->SurfaceNormal(right.po    499       n2 = right.solid->SurfaceNormal(right.point);
481       if ((n +  n2).mag2() < 1000 * kRadTolera    500       if ((n +  n2).mag2() < 1000 * kRadTolerance)
482         return EInside::kInside;                  501         return EInside::kInside;
483     }                                             502     }
484   }                                               503   }
485                                                   504 
486   return EInside::kSurface;                       505   return EInside::kSurface;
487 }                                                 506 }
488                                                   507 
489 //____________________________________________    508 //______________________________________________________________________________
490 EInside G4MultiUnion::Inside(const G4ThreeVect    509 EInside G4MultiUnion::Inside(const G4ThreeVector& aPoint) const
491 {                                                 510 {
492   // Classify point location with respect to s    511   // Classify point location with respect to solid:
493   //  o eInside       - inside the solid          512   //  o eInside       - inside the solid
494   //  o eSurface      - close to surface withi    513   //  o eSurface      - close to surface within tolerance
495   //  o eOutside      - outside the solid         514   //  o eOutside      - outside the solid
496                                                   515 
497   // Hitherto, it is considered that only para    516   // Hitherto, it is considered that only parallelepipedic nodes can be
498   // added to the container                       517   // added to the container
499                                                   518 
500   // Implementation using voxelisation techniq    519   // Implementation using voxelisation techniques:
501   // -----------------------------------------    520   // ---------------------------------------------
502                                                   521 
503   //  return InsideIterator(aPoint);              522   //  return InsideIterator(aPoint);
504                                                   523 
505   EInside location = InsideWithExclusion(aPoin    524   EInside location = InsideWithExclusion(aPoint);
506   return location;                                525   return location;
507 }                                                 526 }
508                                                   527 
509 //____________________________________________    528 //______________________________________________________________________________
510 EInside G4MultiUnion::InsideNoVoxels(const G4T    529 EInside G4MultiUnion::InsideNoVoxels(const G4ThreeVector& aPoint) const
511 {                                                 530 {
512   G4ThreeVector localPoint;                       531   G4ThreeVector localPoint;
513   EInside location = EInside::kOutside;           532   EInside location = EInside::kOutside;
514   G4int countSurface = 0;                         533   G4int countSurface = 0;
515                                                   534 
516   auto numNodes = (G4int)fSolids.size();          535   auto numNodes = (G4int)fSolids.size();
517   for (auto i = 0 ; i < numNodes ; ++i)           536   for (auto i = 0 ; i < numNodes ; ++i)
518   {                                               537   {
519     G4VSolid& solid = *fSolids[i];                538     G4VSolid& solid = *fSolids[i];
520     G4Transform3D transform = GetTransformatio    539     G4Transform3D transform = GetTransformation(i);
521                                                   540 
522     // The coordinates of the point are modifi    541     // The coordinates of the point are modified so as to fit the
523     // intrinsic solid local frame:               542     // intrinsic solid local frame:
524     localPoint = GetLocalPoint(transform, aPoi    543     localPoint = GetLocalPoint(transform, aPoint);
525                                                   544 
526     location = solid.Inside(localPoint);          545     location = solid.Inside(localPoint);
527                                                   546 
528     if (location == EInside::kSurface)            547     if (location == EInside::kSurface)
529       ++countSurface;                             548       ++countSurface;
530                                                   549 
531     if (location == EInside::kInside) return E    550     if (location == EInside::kInside) return EInside::kInside;
532   }                                               551   }
533   if (countSurface != 0) return EInside::kSurf    552   if (countSurface != 0) return EInside::kSurface;
534   return EInside::kOutside;                       553   return EInside::kOutside;
535 }                                                 554 }
536                                                   555 
537 //____________________________________________    556 //______________________________________________________________________________
538 void G4MultiUnion::Extent(EAxis aAxis, G4doubl    557 void G4MultiUnion::Extent(EAxis aAxis, G4double& aMin, G4double& aMax) const
539 {                                                 558 {
540   // Determines the bounding box for the consi    559   // Determines the bounding box for the considered instance of "UMultipleUnion"
541   G4ThreeVector min, max;                         560   G4ThreeVector min, max;
542                                                   561 
543   auto numNodes = (G4int)fSolids.size();          562   auto numNodes = (G4int)fSolids.size();
544   for (auto i = 0 ; i < numNodes ; ++i)           563   for (auto i = 0 ; i < numNodes ; ++i)
545   {                                               564   {
546     G4VSolid& solid = *fSolids[i];                565     G4VSolid& solid = *fSolids[i];
547     G4Transform3D transform = GetTransformatio    566     G4Transform3D transform = GetTransformation(i);
548     solid.BoundingLimits(min, max);               567     solid.BoundingLimits(min, max);
549                                                   568    
550     TransformLimits(min, max, transform);         569     TransformLimits(min, max, transform);
551                                                   570     
552     if (i == 0)                                   571     if (i == 0)
553     {                                             572     {
554       switch (aAxis)                              573       switch (aAxis)
555       {                                           574       {
556         case kXAxis:                              575         case kXAxis:
557           aMin = min.x();                         576           aMin = min.x();
558           aMax = max.x();                         577           aMax = max.x();
559           break;                                  578           break;
560         case kYAxis:                              579         case kYAxis:
561           aMin = min.y();                         580           aMin = min.y();
562           aMax = max.y();                         581           aMax = max.y();
563           break;                                  582           break;
564         case kZAxis:                              583         case kZAxis:
565           aMin = min.z();                         584           aMin = min.z();
566           aMax = max.z();                         585           aMax = max.z();
567           break;                                  586           break;
568         default:                                  587         default:
569           break;                                  588           break;
570       }                                           589       }
571     }                                             590     }
572     else                                          591     else
573     {                                             592     {
574       // Determine the min/max on the consider    593       // Determine the min/max on the considered axis:
575       switch (aAxis)                              594       switch (aAxis)
576       {                                           595       {
577         case kXAxis:                              596         case kXAxis:
578           if (min.x() < aMin)                     597           if (min.x() < aMin)
579             aMin = min.x();                       598             aMin = min.x();
580           if (max.x() > aMax)                     599           if (max.x() > aMax)
581             aMax = max.x();                       600             aMax = max.x();
582           break;                                  601           break;
583         case kYAxis:                              602         case kYAxis:
584           if (min.y() < aMin)                     603           if (min.y() < aMin)
585             aMin = min.y();                       604             aMin = min.y();
586           if (max.y() > aMax)                     605           if (max.y() > aMax)
587             aMax = max.y();                       606             aMax = max.y();
588           break;                                  607           break;
589         case kZAxis:                              608         case kZAxis:
590           if (min.z() < aMin)                     609           if (min.z() < aMin)
591             aMin = min.z();                       610             aMin = min.z();
592           if (max.z() > aMax)                     611           if (max.z() > aMax)
593             aMax = max.z();                       612             aMax = max.z();
594           break;                                  613           break;
595         default:                                  614         default:
596           break;                                  615           break;
597       }                                           616       }
598     }                                             617     }
599   }                                               618   }
600 }                                                 619 }
601                                                   620 
602 //____________________________________________    621 //______________________________________________________________________________
603 void G4MultiUnion::BoundingLimits(G4ThreeVecto    622 void G4MultiUnion::BoundingLimits(G4ThreeVector& aMin,
604                                   G4ThreeVecto    623                                   G4ThreeVector& aMax) const
605 {                                                 624 {
606    Extent(kXAxis, aMin[0], aMax[0]);              625    Extent(kXAxis, aMin[0], aMax[0]);
607    Extent(kYAxis, aMin[1], aMax[1]);              626    Extent(kYAxis, aMin[1], aMax[1]);
608    Extent(kZAxis, aMin[2], aMax[2]);              627    Extent(kZAxis, aMin[2], aMax[2]);
609 }                                                 628 }
610                                                   629 
611 //____________________________________________    630 //______________________________________________________________________________
612 G4bool                                            631 G4bool
613 G4MultiUnion::CalculateExtent(const EAxis pAxi    632 G4MultiUnion::CalculateExtent(const EAxis pAxis,
614                               const G4VoxelLim    633                               const G4VoxelLimits& pVoxelLimit,
615                               const G4AffineTr    634                               const G4AffineTransform& pTransform,
616                                     G4double&     635                                     G4double& pMin, G4double& pMax) const
617 {                                                 636 {
618   G4ThreeVector bmin, bmax;                       637   G4ThreeVector bmin, bmax;
619                                                   638 
620   // Get bounding box                             639   // Get bounding box
621   BoundingLimits(bmin,bmax);                      640   BoundingLimits(bmin,bmax);
622                                                   641 
623   // Find extent                                  642   // Find extent
624   G4BoundingEnvelope bbox(bmin,bmax);             643   G4BoundingEnvelope bbox(bmin,bmax);
625   return bbox.CalculateExtent(pAxis,pVoxelLimi    644   return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
626 }                                                 645 }
627                                                   646 
628 //____________________________________________    647 //______________________________________________________________________________
629 G4ThreeVector G4MultiUnion::SurfaceNormal(cons    648 G4ThreeVector G4MultiUnion::SurfaceNormal(const G4ThreeVector& aPoint) const
630 {                                                 649 {
631   // Computes the localNormal on a surface and    650   // Computes the localNormal on a surface and returns it as a unit vector.
632   // Must return a valid vector. (even if the     651   // Must return a valid vector. (even if the point is not on the surface).
633   //                                              652   //
634   //   On an edge or corner, provide an averag    653   //   On an edge or corner, provide an average localNormal of all facets within
635   //   tolerance                                  654   //   tolerance
636   //   NOTE: the tolerance value used in here     655   //   NOTE: the tolerance value used in here is not yet the global surface
637   //         tolerance - we will have to revis    656   //         tolerance - we will have to revise this value - TODO
638                                                   657 
639   std::vector<G4int> candidates;                  658   std::vector<G4int> candidates;
640   G4ThreeVector localPoint, normal, localNorma    659   G4ThreeVector localPoint, normal, localNormal;
641   G4double safety = kInfinity;                    660   G4double safety = kInfinity;
642   G4int node = 0;                                 661   G4int node = 0;
643                                                   662 
644   ////////////////////////////////////////////    663   ///////////////////////////////////////////////////////////////////////////
645   // Important comment: Cases for which the po    664   // Important comment: Cases for which the point is located on an edge or
646   // on a vertice remain to be treated            665   // on a vertice remain to be treated
647                                                   666 
648   // determine weather we are in voxel area       667   // determine weather we are in voxel area
649   if (fVoxels.GetCandidatesVoxelArray(aPoint,     668   if (fVoxels.GetCandidatesVoxelArray(aPoint, candidates) != 0)
650   {                                               669   {
651     std::size_t limit = candidates.size();        670     std::size_t limit = candidates.size();
652     for (std::size_t i = 0 ; i < limit ; ++i)     671     for (std::size_t i = 0 ; i < limit ; ++i)
653     {                                             672     {
654       G4int candidate = candidates[i];            673       G4int candidate = candidates[i];
655       const G4Transform3D& transform = fTransf    674       const G4Transform3D& transform = fTransformObjs[candidate];
656                                                   675 
657       // The coordinates of the point are modi    676       // The coordinates of the point are modified so as to fit the intrinsic
658       // solid local frame:                       677       // solid local frame:
659       localPoint = GetLocalPoint(transform, aP    678       localPoint = GetLocalPoint(transform, aPoint);
660       G4VSolid& solid = *fSolids[candidate];      679       G4VSolid& solid = *fSolids[candidate];
661       EInside location = solid.Inside(localPoi    680       EInside location = solid.Inside(localPoint);
662                                                   681 
663       if (location == EInside::kSurface)          682       if (location == EInside::kSurface)
664       {                                           683       {
665         // normal case when point is on surfac    684         // normal case when point is on surface, we pick first solid
666         normal = GetGlobalVector(transform, so    685         normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
667         return normal.unit();                     686         return normal.unit();
668       }                                           687       }
669       else                                        688       else
670       {                                           689       {
671         // collect the smallest safety and rem    690         // collect the smallest safety and remember solid node
672         G4double s = (location == EInside::kIn    691         G4double s = (location == EInside::kInside)
673                    ? solid.DistanceToOut(local    692                    ? solid.DistanceToOut(localPoint)
674                    : solid.DistanceToIn(localP    693                    : solid.DistanceToIn(localPoint);
675         if (s < safety)                           694         if (s < safety)
676         {                                         695         {
677           safety = s;                             696           safety = s;
678           node = candidate;                       697           node = candidate;
679         }                                         698         }
680       }                                           699       }
681     }                                             700     }
682     // on none of the solids, the point was no    701     // on none of the solids, the point was not on the surface
683     G4VSolid& solid = *fSolids[node];             702     G4VSolid& solid = *fSolids[node];
684     const G4Transform3D& transform = fTransfor    703     const G4Transform3D& transform = fTransformObjs[node];
685     localPoint = GetLocalPoint(transform, aPoi    704     localPoint = GetLocalPoint(transform, aPoint);
686                                                   705 
687     normal = GetGlobalVector(transform, solid.    706     normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
688     return normal.unit();                         707     return normal.unit();
689   }                                               708   }
690   else                                            709   else
691   {                                               710   {
692     // for the case when point is certainly ou    711     // for the case when point is certainly outside:
693                                                   712 
694     // find a solid in union with the smallest    713     // find a solid in union with the smallest safety
695     node = SafetyFromOutsideNumberNode(aPoint,    714     node = SafetyFromOutsideNumberNode(aPoint, safety);
696     G4VSolid& solid = *fSolids[node];             715     G4VSolid& solid = *fSolids[node];
697                                                   716 
698     const G4Transform3D& transform = fTransfor    717     const G4Transform3D& transform = fTransformObjs[node];
699     localPoint = GetLocalPoint(transform, aPoi    718     localPoint = GetLocalPoint(transform, aPoint);
700                                                   719 
701     // evaluate normal for point at this found    720     // evaluate normal for point at this found solid
702     // and transform multi-union coordinates      721     // and transform multi-union coordinates
703     normal = GetGlobalVector(transform, solid.    722     normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
704                                                   723 
705     return normal.unit();                         724     return normal.unit();
706   }                                               725   }
707 }                                                 726 }
708                                                   727 
709 //____________________________________________    728 //______________________________________________________________________________
710 G4double G4MultiUnion::DistanceToOut(const G4T    729 G4double G4MultiUnion::DistanceToOut(const G4ThreeVector& point) const
711 {                                                 730 {
712   // Estimates isotropic distance to the surfa    731   // Estimates isotropic distance to the surface of the solid. This must
713   // be either accurate or an underestimate.      732   // be either accurate or an underestimate.
714   // Two modes: - default/fast mode, sacrifici    733   // Two modes: - default/fast mode, sacrificing accuracy for speed
715   //            - "precise" mode,  requests ac    734   //            - "precise" mode,  requests accurate value if available.
716                                                   735 
717   std::vector<G4int> candidates;                  736   std::vector<G4int> candidates;
718   G4ThreeVector localPoint;                       737   G4ThreeVector localPoint;
719   G4double safetyMin = kInfinity;                 738   G4double safetyMin = kInfinity;
720                                                   739 
721   // In general, the value return by DistanceT    740   // In general, the value return by DistanceToIn(p) will not be the exact
722   // but only an undervalue (cf. overlaps)        741   // but only an undervalue (cf. overlaps)
723   fVoxels.GetCandidatesVoxelArray(point, candi    742   fVoxels.GetCandidatesVoxelArray(point, candidates);
724                                                   743 
725   std::size_t limit = candidates.size();          744   std::size_t limit = candidates.size();
726   for (std::size_t i = 0; i < limit; ++i)         745   for (std::size_t i = 0; i < limit; ++i)
727   {                                               746   {
728     G4int candidate = candidates[i];              747     G4int candidate = candidates[i];
729                                                   748 
730     // The coordinates of the point are modifi    749     // The coordinates of the point are modified so as to fit the intrinsic
731     // solid local frame:                         750     // solid local frame:
732     const G4Transform3D& transform = fTransfor    751     const G4Transform3D& transform = fTransformObjs[candidate];
733     localPoint = GetLocalPoint(transform, poin    752     localPoint = GetLocalPoint(transform, point);
734     G4VSolid& solid = *fSolids[candidate];        753     G4VSolid& solid = *fSolids[candidate];
735     if (solid.Inside(localPoint) == EInside::k    754     if (solid.Inside(localPoint) == EInside::kInside)
736     {                                             755     {
737       G4double safety = solid.DistanceToOut(lo    756       G4double safety = solid.DistanceToOut(localPoint);
738       if (safetyMin > safety) safetyMin = safe    757       if (safetyMin > safety) safetyMin = safety;
739     }                                             758     }
740   }                                               759   }
741   if (safetyMin == kInfinity) safetyMin = 0; /    760   if (safetyMin == kInfinity) safetyMin = 0; // we are not inside
742                                                   761 
743   return safetyMin;                               762   return safetyMin;
744 }                                                 763 }
745                                                   764 
746 //____________________________________________    765 //______________________________________________________________________________
747 G4double G4MultiUnion::DistanceToIn(const G4Th    766 G4double G4MultiUnion::DistanceToIn(const G4ThreeVector& point) const
748 {                                                 767 {
749   // Estimates the isotropic safety from a poi    768   // Estimates the isotropic safety from a point outside the current solid to
750   // any of its surfaces. The algorithm may be    769   // any of its surfaces. The algorithm may be accurate or should provide a fast
751   // underestimate.                               770   // underestimate.
752                                                   771 
753   if (!fAccurate)  { return fVoxels.DistanceTo    772   if (!fAccurate)  { return fVoxels.DistanceToBoundingBox(point); }
754                                                   773 
755   const std::vector<G4VoxelBox>& boxes = fVoxe    774   const std::vector<G4VoxelBox>& boxes = fVoxels.GetBoxes();
756   G4double safetyMin = kInfinity;                 775   G4double safetyMin = kInfinity;
757   G4ThreeVector localPoint;                       776   G4ThreeVector localPoint;
758                                                   777 
759   std::size_t numNodes = fSolids.size();          778   std::size_t numNodes = fSolids.size();
760   for (std::size_t j = 0; j < numNodes; ++j)      779   for (std::size_t j = 0; j < numNodes; ++j)
761   {                                               780   {
762     G4ThreeVector dxyz;                           781     G4ThreeVector dxyz;
763     if (j > 0)                                    782     if (j > 0)
764     {                                             783     {
765       const G4ThreeVector& pos = boxes[j].pos;    784       const G4ThreeVector& pos = boxes[j].pos;
766       const G4ThreeVector& hlen = boxes[j].hle    785       const G4ThreeVector& hlen = boxes[j].hlen;
767       for (auto i = 0; i <= 2; ++i)               786       for (auto i = 0; i <= 2; ++i)
768         // distance to middle point - hlength     787         // distance to middle point - hlength => distance from point to border
769         // of x,y,z                               788         // of x,y,z
770         if ((dxyz[i] = std::abs(point[i] - pos    789         if ((dxyz[i] = std::abs(point[i] - pos[i]) - hlen[i]) > safetyMin)
771           continue;                               790           continue;
772                                                   791 
773       G4double d2xyz = 0.;                        792       G4double d2xyz = 0.;
774       for (auto i = 0; i <= 2; ++i)               793       for (auto i = 0; i <= 2; ++i)
775         if (dxyz[i] > 0) d2xyz += dxyz[i] * dx    794         if (dxyz[i] > 0) d2xyz += dxyz[i] * dxyz[i];
776                                                   795 
777       // minimal distance is at least this, bu    796       // minimal distance is at least this, but could be even higher. therefore,
778       // we can stop if previous was already l    797       // we can stop if previous was already lower, let us check if it does any
779       // chance to be better tha previous valu    798       // chance to be better tha previous values...
780       if (d2xyz >= safetyMin * safetyMin)         799       if (d2xyz >= safetyMin * safetyMin)
781       {                                           800       {
782         continue;                                 801         continue;
783       }                                           802       }
784     }                                             803     }
785     const G4Transform3D& transform = fTransfor    804     const G4Transform3D& transform = fTransformObjs[j];
786     localPoint = GetLocalPoint(transform, poin    805     localPoint = GetLocalPoint(transform, point);
787     G4VSolid& solid = *fSolids[j];                806     G4VSolid& solid = *fSolids[j];
788                                                   807 
789     G4double safety = solid.DistanceToIn(local    808     G4double safety = solid.DistanceToIn(localPoint);
790     if (safety <= 0) return safety;               809     if (safety <= 0) return safety;
791       // it was detected, that the point is no    810       // it was detected, that the point is not located outside
792     if (safetyMin > safety) safetyMin = safety    811     if (safetyMin > safety) safetyMin = safety;
793   }                                               812   }
794   return safetyMin;                               813   return safetyMin;
795 }                                                 814 }
796                                                   815 
797 //____________________________________________    816 //______________________________________________________________________________
798 G4double G4MultiUnion::GetSurfaceArea()           817 G4double G4MultiUnion::GetSurfaceArea()
799 {                                                 818 {
800   if (fSurfaceArea == 0.0)                        819   if (fSurfaceArea == 0.0)
801   {                                               820   {
802     fSurfaceArea = EstimateSurfaceArea(1000000    821     fSurfaceArea = EstimateSurfaceArea(1000000, 0.001);
803   }                                               822   }
804   return fSurfaceArea;                            823   return fSurfaceArea;
805 }                                                 824 }
806                                                   825 
807 //____________________________________________    826 //______________________________________________________________________________
808 G4int G4MultiUnion::GetNumOfConstituents() con << 
809 {                                              << 
810   G4int num = 0;                               << 
811   for (const auto solid : fSolids) { num += so << 
812   return num;                                  << 
813 }                                              << 
814                                                << 
815 //____________________________________________ << 
816 G4bool G4MultiUnion::IsFaceted() const         << 
817 {                                              << 
818   for (const auto solid : fSolids) { if (!soli << 
819   return true;                                 << 
820 }                                              << 
821                                                << 
822 //____________________________________________ << 
823 void G4MultiUnion::Voxelize()                     827 void G4MultiUnion::Voxelize()
824 {                                                 828 {
825   fVoxels.Voxelize(fSolids, fTransformObjs);      829   fVoxels.Voxelize(fSolids, fTransformObjs);
826 }                                                 830 }
827                                                   831 
828 //____________________________________________    832 //______________________________________________________________________________
829 G4int G4MultiUnion::SafetyFromOutsideNumberNod    833 G4int G4MultiUnion::SafetyFromOutsideNumberNode(const G4ThreeVector& aPoint,
830                                                   834                                                 G4double& safetyMin) const
831 {                                                 835 {
832   // Method returning the closest node from a     836   // Method returning the closest node from a point located outside a
833   // G4MultiUnion.                                837   // G4MultiUnion.
834   // This is used to compute the normal in the    838   // This is used to compute the normal in the case no candidate has been found.
835                                                   839 
836   const std::vector<G4VoxelBox>& boxes = fVoxe    840   const std::vector<G4VoxelBox>& boxes = fVoxels.GetBoxes();
837   safetyMin = kInfinity;                          841   safetyMin = kInfinity;
838   std::size_t safetyNode = 0;                     842   std::size_t safetyNode = 0;
839   G4ThreeVector localPoint;                       843   G4ThreeVector localPoint;
840                                                   844 
841   std::size_t numNodes = fSolids.size();          845   std::size_t numNodes = fSolids.size();
842   for (std::size_t i = 0; i < numNodes; ++i)      846   for (std::size_t i = 0; i < numNodes; ++i)
843   {                                               847   {
844     G4double d2xyz = 0.;                          848     G4double d2xyz = 0.;
845     G4double dxyz0 = std::abs(aPoint.x() - box    849     G4double dxyz0 = std::abs(aPoint.x() - boxes[i].pos.x()) - boxes[i].hlen.x();
846     if (dxyz0 > safetyMin) continue;              850     if (dxyz0 > safetyMin) continue;
847     G4double dxyz1 = std::abs(aPoint.y() - box    851     G4double dxyz1 = std::abs(aPoint.y() - boxes[i].pos.y()) - boxes[i].hlen.y();
848     if (dxyz1 > safetyMin) continue;              852     if (dxyz1 > safetyMin) continue;
849     G4double dxyz2 = std::abs(aPoint.z() - box    853     G4double dxyz2 = std::abs(aPoint.z() - boxes[i].pos.z()) - boxes[i].hlen.z();
850     if (dxyz2 > safetyMin) continue;              854     if (dxyz2 > safetyMin) continue;
851                                                   855 
852     if (dxyz0 > 0) d2xyz += dxyz0 * dxyz0;        856     if (dxyz0 > 0) d2xyz += dxyz0 * dxyz0;
853     if (dxyz1 > 0) d2xyz += dxyz1 * dxyz1;        857     if (dxyz1 > 0) d2xyz += dxyz1 * dxyz1;
854     if (dxyz2 > 0) d2xyz += dxyz2 * dxyz2;        858     if (dxyz2 > 0) d2xyz += dxyz2 * dxyz2;
855     if (d2xyz >= safetyMin * safetyMin) contin    859     if (d2xyz >= safetyMin * safetyMin) continue;
856                                                   860 
857     G4VSolid& solid = *fSolids[i];                861     G4VSolid& solid = *fSolids[i];
858     const G4Transform3D& transform = fTransfor    862     const G4Transform3D& transform = fTransformObjs[i];
859     localPoint = GetLocalPoint(transform, aPoi    863     localPoint = GetLocalPoint(transform, aPoint);
860     fAccurate = true;                             864     fAccurate = true;
861     G4double safety = solid.DistanceToIn(local    865     G4double safety = solid.DistanceToIn(localPoint);
862     fAccurate = false;                            866     fAccurate = false;
863     if (safetyMin > safety)                       867     if (safetyMin > safety)
864     {                                             868     {
865       safetyMin = safety;                         869       safetyMin = safety;
866       safetyNode = i;                             870       safetyNode = i;
867     }                                             871     }
868   }                                               872   }
869   return (G4int)safetyNode;                       873   return (G4int)safetyNode;
870 }                                                 874 }
871                                                   875 
872 //____________________________________________    876 //______________________________________________________________________________
873 void G4MultiUnion::TransformLimits(G4ThreeVect    877 void G4MultiUnion::TransformLimits(G4ThreeVector& min, G4ThreeVector& max,
874                                    const G4Tra    878                                    const G4Transform3D& transformation) const
875 {                                                 879 {
876   // The goal of this method is to convert the    880   // The goal of this method is to convert the quantities min and max
877   // (representing the bounding box of a given    881   // (representing the bounding box of a given solid in its local frame)
878   // to the main frame, using "transformation"    882   // to the main frame, using "transformation"
879                                                   883 
880   G4ThreeVector vertices[8] =     // Deteminat    884   G4ThreeVector vertices[8] =     // Detemination of the vertices thanks to
881   {                               // the exten    885   {                               // the extension of each solid:
882     G4ThreeVector(min.x(), min.y(), min.z()),     886     G4ThreeVector(min.x(), min.y(), min.z()), // 1st vertice:
883     G4ThreeVector(min.x(), max.y(), min.z()),     887     G4ThreeVector(min.x(), max.y(), min.z()), // 2nd vertice:
884     G4ThreeVector(max.x(), max.y(), min.z()),     888     G4ThreeVector(max.x(), max.y(), min.z()),
885     G4ThreeVector(max.x(), min.y(), min.z()),     889     G4ThreeVector(max.x(), min.y(), min.z()),
886     G4ThreeVector(min.x(), min.y(), max.z()),     890     G4ThreeVector(min.x(), min.y(), max.z()),
887     G4ThreeVector(min.x(), max.y(), max.z()),     891     G4ThreeVector(min.x(), max.y(), max.z()),
888     G4ThreeVector(max.x(), max.y(), max.z()),     892     G4ThreeVector(max.x(), max.y(), max.z()),
889     G4ThreeVector(max.x(), min.y(), max.z())      893     G4ThreeVector(max.x(), min.y(), max.z())
890   };                                              894   };
891                                                   895 
892   min.set(kInfinity,kInfinity,kInfinity);         896   min.set(kInfinity,kInfinity,kInfinity);
893   max.set(-kInfinity,-kInfinity,-kInfinity);      897   max.set(-kInfinity,-kInfinity,-kInfinity);
894                                                   898 
895   // Loop on th vertices                          899   // Loop on th vertices
896   G4int limit = sizeof(vertices) / sizeof(G4Th    900   G4int limit = sizeof(vertices) / sizeof(G4ThreeVector);
897   for (G4int i = 0 ; i < limit; ++i)              901   for (G4int i = 0 ; i < limit; ++i)
898   {                                               902   {
899     // From local frame to the global one:        903     // From local frame to the global one:
900     // Current positions on the three axis:       904     // Current positions on the three axis:
901     G4ThreeVector current = GetGlobalPoint(tra    905     G4ThreeVector current = GetGlobalPoint(transformation, vertices[i]);
902                                                   906 
903     // If need be, replacement of the min & ma    907     // If need be, replacement of the min & max values:
904     if (current.x() > max.x()) max.setX(curren    908     if (current.x() > max.x()) max.setX(current.x());
905     if (current.x() < min.x()) min.setX(curren    909     if (current.x() < min.x()) min.setX(current.x());
906                                                   910 
907     if (current.y() > max.y()) max.setY(curren    911     if (current.y() > max.y()) max.setY(current.y());
908     if (current.y() < min.y()) min.setY(curren    912     if (current.y() < min.y()) min.setY(current.y());
909                                                   913 
910     if (current.z() > max.z()) max.setZ(curren    914     if (current.z() > max.z()) max.setZ(current.z());
911     if (current.z() < min.z()) min.setZ(curren    915     if (current.z() < min.z()) min.setZ(current.z());
912   }                                               916   }
913 }                                                 917 }
914                                                   918 
915 // Stream object contents to an output stream     919 // Stream object contents to an output stream
916 //____________________________________________    920 //______________________________________________________________________________
917 std::ostream& G4MultiUnion::StreamInfo(std::os    921 std::ostream& G4MultiUnion::StreamInfo(std::ostream& os) const
918 {                                                 922 {
919   G4long oldprc = os.precision(16);               923   G4long oldprc = os.precision(16);
920   os << "-------------------------------------    924   os << "-----------------------------------------------------------\n"
921      << "                *** Dump for solid -     925      << "                *** Dump for solid - " << GetName() << " ***\n"
922      << "                =====================    926      << "                ===================================================\n"
923      << " Solid type: G4MultiUnion\n"             927      << " Solid type: G4MultiUnion\n"
924      << " Parameters: \n";                        928      << " Parameters: \n";
925      std::size_t numNodes = fSolids.size();       929      std::size_t numNodes = fSolids.size();
926      for (std::size_t i = 0 ; i < numNodes ; +    930      for (std::size_t i = 0 ; i < numNodes ; ++i)
927      {                                            931      {
928       G4VSolid& solid = *fSolids[i];              932       G4VSolid& solid = *fSolids[i];
929       solid.StreamInfo(os);                       933       solid.StreamInfo(os);
930       const G4Transform3D& transform = fTransf    934       const G4Transform3D& transform = fTransformObjs[i];
931       os << " Translation is " << transform.ge    935       os << " Translation is " << transform.getTranslation() << " \n";
932       os << " Rotation is :" << " \n";            936       os << " Rotation is :" << " \n";
933       os << " " << transform.getRotation() <<     937       os << " " << transform.getRotation() << "\n";
934      }                                            938      }
935   os << "             \n"                         939   os << "             \n"
936      << "-------------------------------------    940      << "-----------------------------------------------------------\n";
937   os.precision(oldprc);                           941   os.precision(oldprc);
938                                                   942 
939   return os;                                      943   return os;
940 }                                                 944 }
941                                                   945 
942 //____________________________________________    946 //______________________________________________________________________________
943 G4ThreeVector G4MultiUnion::GetPointOnSurface(    947 G4ThreeVector G4MultiUnion::GetPointOnSurface() const
944 {                                                 948 {
945   G4ThreeVector point;                            949   G4ThreeVector point;
946                                                   950 
947   G4long size = fSolids.size();                   951   G4long size = fSolids.size();
948                                                   952 
949   do                                              953   do
950   {                                               954   {
951     G4long rnd = G4RandFlat::shootInt(G4long(0    955     G4long rnd = G4RandFlat::shootInt(G4long(0), size);
952     G4VSolid& solid = *fSolids[rnd];              956     G4VSolid& solid = *fSolids[rnd];
953     point = solid.GetPointOnSurface();            957     point = solid.GetPointOnSurface();
954     const G4Transform3D& transform = fTransfor    958     const G4Transform3D& transform = fTransformObjs[rnd];
955     point = GetGlobalPoint(transform, point);     959     point = GetGlobalPoint(transform, point);
956   }                                               960   }
957   while (Inside(point) != EInside::kSurface);     961   while (Inside(point) != EInside::kSurface);
958                                                   962 
959   return point;                                   963   return point;
960 }                                                 964 }
961                                                   965 
962 //____________________________________________    966 //______________________________________________________________________________
963 void                                              967 void 
964 G4MultiUnion::DescribeYourselfTo ( G4VGraphics    968 G4MultiUnion::DescribeYourselfTo ( G4VGraphicsScene& scene ) const 
965 {                                                 969 {
966   scene.AddSolid (*this);                         970   scene.AddSolid (*this);
967 }                                                 971 }
968                                                   972 
969 //____________________________________________    973 //______________________________________________________________________________
970 G4Polyhedron* G4MultiUnion::CreatePolyhedron()    974 G4Polyhedron* G4MultiUnion::CreatePolyhedron() const
971 {                                                 975 {
972   if (G4BooleanSolid::GetExternalBooleanProces    976   if (G4BooleanSolid::GetExternalBooleanProcessor() == nullptr)
973   {                                               977   {
974     HepPolyhedronProcessor processor;             978     HepPolyhedronProcessor processor;
975     HepPolyhedronProcessor::Operation operatio    979     HepPolyhedronProcessor::Operation operation = HepPolyhedronProcessor::UNION;
976                                                   980 
977     G4VSolid* solidA = GetSolid(0);               981     G4VSolid* solidA = GetSolid(0);
978     const G4Transform3D transform0 = GetTransf    982     const G4Transform3D transform0 = GetTransformation(0);
979     G4DisplacedSolid dispSolidA("placedA", sol    983     G4DisplacedSolid dispSolidA("placedA", solidA, transform0);
980                                                   984 
981     auto top = new G4Polyhedron(*dispSolidA.Ge    985     auto top = new G4Polyhedron(*dispSolidA.GetPolyhedron());
982                                                   986 
983     for (G4int i = 1; i < GetNumberOfSolids();    987     for (G4int i = 1; i < GetNumberOfSolids(); ++i)
984     {                                             988     {
985       G4VSolid* solidB = GetSolid(i);             989       G4VSolid* solidB = GetSolid(i);
986       const G4Transform3D transform = GetTrans    990       const G4Transform3D transform = GetTransformation(i);
987       G4DisplacedSolid dispSolidB("placedB", s    991       G4DisplacedSolid dispSolidB("placedB", solidB, transform);
988       G4Polyhedron* operand = dispSolidB.GetPo    992       G4Polyhedron* operand = dispSolidB.GetPolyhedron();
989       processor.push_back(operation, *operand)    993       processor.push_back(operation, *operand);
990     }                                             994     }
991                                                   995 
992     if (processor.execute(*top))                  996     if (processor.execute(*top))
993     {                                             997     {
994       return top;                                 998       return top;
995     }                                             999     }
996     else                                          1000     else
997     {                                             1001     {
998       return nullptr;                             1002       return nullptr;
999     }                                             1003     }
1000   }                                              1004   }
1001   else                                           1005   else
1002   {                                              1006   {
1003     return G4BooleanSolid::GetExternalBoolean << 1007     G4VSolid* solidA = GetSolid(0);
                                                   >> 1008     auto solidAPolyhedron =solidA->GetPolyhedron();
                                                   >> 1009 
                                                   >> 1010     const G4Transform3D transform0 = GetTransformation(0);
                                                   >> 1011     G4DisplacedSolid dispSolidA("placedA", solidA, transform0);
                                                   >> 1012 
                                                   >> 1013     // dispSolidA.GetPolyhedron()
                                                   >> 1014     for (G4int i = 1; i < GetNumberOfSolids(); ++i)
                                                   >> 1015     {
                                                   >> 1016       G4VSolid* solidB = GetSolid(i);
                                                   >> 1017       const G4Transform3D transform = GetTransformation(i);
                                                   >> 1018       G4DisplacedSolid dispSolidB("placedB", solidB, transform);
                                                   >> 1019       solidAPolyhedron = G4BooleanSolid::GetExternalBooleanProcessor()
                                                   >> 1020                        ->Union(solidAPolyhedron, dispSolidB.GetPolyhedron());
                                                   >> 1021     }
                                                   >> 1022 
                                                   >> 1023     return solidAPolyhedron;
1004   }                                              1024   }
1005 }                                                1025 }
1006                                                  1026 
1007 //___________________________________________    1027 //______________________________________________________________________________
1008 G4Polyhedron* G4MultiUnion::GetPolyhedron() c    1028 G4Polyhedron* G4MultiUnion::GetPolyhedron() const
1009 {                                                1029 {
1010   if (fpPolyhedron == nullptr ||                 1030   if (fpPolyhedron == nullptr ||
1011       fRebuildPolyhedron ||                      1031       fRebuildPolyhedron ||
1012       fpPolyhedron->GetNumberOfRotationStepsA    1032       fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
1013       fpPolyhedron->GetNumberOfRotationSteps(    1033       fpPolyhedron->GetNumberOfRotationSteps())
1014   {                                              1034   {
1015     G4AutoLock l(&polyhedronMutex);              1035     G4AutoLock l(&polyhedronMutex);
1016     delete fpPolyhedron;                         1036     delete fpPolyhedron;
1017     fpPolyhedron = CreatePolyhedron();           1037     fpPolyhedron = CreatePolyhedron();
1018     fRebuildPolyhedron = false;                  1038     fRebuildPolyhedron = false;
1019     l.unlock();                                  1039     l.unlock();
1020   }                                              1040   }
1021   return fpPolyhedron;                           1041   return fpPolyhedron;
1022 }                                                1042 }
1023                                                  1043