Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/specific/src/G4Voxelizer.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 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // G4Voxelizer implementation
 27 //
 28 // 19.10.12 Marek Gayer, created
 29 // --------------------------------------------------------------------
 30 
 31 #include <iostream>
 32 #include <iomanip>
 33 #include <sstream>
 34 #include <algorithm>
 35 #include <set>
 36 
 37 #include "G4VSolid.hh" 
 38 
 39 #include "G4CSGSolid.hh"
 40 #include "G4GeometryTolerance.hh"
 41 #include "G4Orb.hh"
 42 #include "G4PhysicalConstants.hh"
 43 #include "G4SolidStore.hh"
 44 #include "G4Types.hh"
 45 #include "G4Voxelizer.hh"
 46 #include "Randomize.hh"
 47 #include "geomdefs.hh"
 48 
 49 using namespace std;
 50 
 51 G4ThreadLocal G4int G4Voxelizer::fDefaultVoxelsCount = -1;
 52 
 53 //______________________________________________________________________________
 54 G4Voxelizer::G4Voxelizer()
 55   : fBoundingBox("VoxBBox", 1, 1, 1)
 56 {
 57   fCountOfVoxels = fNPerSlice = fTotalCandidates = 0;
 58   
 59   fTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
 60 
 61   SetMaxVoxels(fDefaultVoxelsCount); 
 62 
 63   G4SolidStore::GetInstance()->DeRegister(&fBoundingBox);
 64 }
 65 
 66 //______________________________________________________________________________
 67 G4Voxelizer::~G4Voxelizer() = default;
 68 
 69 //______________________________________________________________________________
 70 void G4Voxelizer::BuildEmpty()
 71 {
 72   // by reserving the size of candidates, we would avoid reallocation of 
 73   // the vector which could cause fragmentation
 74   //
 75   std::vector<G4int> xyz(3), max(3), candidates(fTotalCandidates);
 76   const std::vector<G4int> empty(0);
 77 
 78   for (auto i = 0; i <= 2; ++i) max[i] = (G4int)fBoundaries[i].size();
 79   unsigned int size = max[0] * max[1] * max[2];
 80 
 81   fEmpty.Clear();
 82   fEmpty.ResetBitNumber(size-1);
 83   fEmpty.ResetAllBits(true);
 84 
 85   for (xyz[2] = 0; xyz[2] < max[2]; ++xyz[2])
 86   {
 87     for (xyz[1] = 0; xyz[1] < max[1]; ++xyz[1])
 88     {
 89       for (xyz[0] = 0; xyz[0] < max[0]; ++xyz[0])
 90       {
 91         if (GetCandidatesVoxelArray(xyz, candidates) != 0) 
 92         {
 93           G4int index = GetVoxelsIndex(xyz);
 94           fEmpty.SetBitNumber(index, false);
 95 
 96           // rather than assigning directly with:
 97           // "fCandidates[index] = candidates;", in an effort to ensure that 
 98           // capacity would be just exact, we rather use following 3 lines
 99           //
100           std::vector<G4int> &c = (fCandidates[index] = empty);
101           c.reserve(candidates.size());
102           c.assign(candidates.begin(), candidates.end());
103         }
104       }
105     }
106   }
107 #ifdef G4SPECSDEBUG
108   G4cout << "Non-empty voxels count: " << fCandidates.size() << G4endl;
109 #endif
110 }
111 
112 //______________________________________________________________________________
113 void G4Voxelizer::BuildVoxelLimits(std::vector<G4VSolid*>& solids,
114                                    std::vector<G4Transform3D>& transforms)
115 {
116   // "BuildVoxelLimits"'s aim is to store the coordinates of the origin as
117   // well as the half lengths related to the bounding box of each node.
118   // These quantities are stored in the array "fBoxes" (6 different values per
119   // node
120   //
121   if (std::size_t numNodes = solids.size()) // Number of nodes in "multiUnion"
122   {
123     fBoxes.resize(numNodes); // Array which will store the half lengths
124     fNPerSlice = G4int(1 + (fBoxes.size() - 1) / (8 * sizeof(unsigned int)));
125 
126     // related to a particular node, but also
127     // the coordinates of its origin
128 
129     G4ThreeVector toleranceVector(fTolerance,fTolerance,fTolerance);
130 
131     for (std::size_t i = 0; i < numNodes; ++i)
132     {
133       G4VSolid& solid = *solids[i];
134       G4Transform3D transform = transforms[i];
135       G4ThreeVector min, max;
136 
137       solid.BoundingLimits(min, max);
138       if (solid.GetEntityType() == "G4Orb")
139       {
140         G4Orb& orb = *(G4Orb*) &solid;
141         G4ThreeVector orbToleranceVector;
142         G4double tolerance = orb.GetRadialTolerance() / 2.0;
143         orbToleranceVector.set(tolerance,tolerance,tolerance);
144         min -= orbToleranceVector;
145         max += orbToleranceVector;
146       }
147       else
148       {
149         min -= toleranceVector;
150         max += toleranceVector;
151       }
152       TransformLimits(min, max, transform);
153       fBoxes[i].hlen = (max - min) / 2.;
154       fBoxes[i].pos =  (max + min) / 2.;
155     }
156     fTotalCandidates = (G4int)fBoxes.size();
157   }
158 }
159 
160 //______________________________________________________________________________
161 void G4Voxelizer::BuildVoxelLimits(std::vector<G4VFacet*>& facets)
162 {
163   // "BuildVoxelLimits"'s aim is to store the coordinates of the origin as well
164   // as the half lengths related to the bounding box of each node.
165   // These quantities are stored in the array "fBoxes" (6 different values per
166   // node.
167 
168   if (std::size_t numNodes = facets.size()) // Number of nodes
169   {
170     fBoxes.resize(numNodes); // Array which will store the half lengths
171     fNPerSlice = G4int(1+(fBoxes.size()-1)/(8*sizeof(unsigned int)));
172 
173     G4ThreeVector toleranceVector(10*fTolerance, 10*fTolerance, 10*fTolerance);
174 
175     for (std::size_t i = 0; i < numNodes; ++i)
176     {
177       G4VFacet &facet = *facets[i];
178       G4ThreeVector min, max;
179       G4ThreeVector x(1,0,0), y(0,1,0), z(0,0,1);
180       G4ThreeVector extent;
181       max.set (facet.Extent(x), facet.Extent(y), facet.Extent(z));
182       min.set (-facet.Extent(-x), -facet.Extent(-y), -facet.Extent(-z));
183       min -= toleranceVector;
184       max += toleranceVector;
185       G4ThreeVector hlen = (max - min) / 2;
186       fBoxes[i].hlen = hlen;
187       fBoxes[i].pos = min + hlen;
188     }
189     fTotalCandidates = (G4int)fBoxes.size();
190   }
191 }
192 
193 //______________________________________________________________________________
194 void G4Voxelizer::DisplayVoxelLimits() const
195 {
196   // "DisplayVoxelLimits" displays the dX, dY, dZ, pX, pY and pZ for each node
197 
198   std::size_t numNodes = fBoxes.size();
199   G4long oldprec = G4cout.precision(16);
200   for(std::size_t i = 0; i < numNodes; ++i)
201   {
202     G4cout << setw(10) << setiosflags(ios::fixed) <<
203       "    -> Node " << i+1 <<  ":\n" << 
204       "\t * [x,y,z] = " << fBoxes[i].hlen <<
205       "\t * [x,y,z] = " << fBoxes[i].pos << "\n";
206   }
207   G4cout.precision(oldprec);
208 }
209 
210 //______________________________________________________________________________
211 void G4Voxelizer::CreateSortedBoundary(std::vector<G4double>& boundary,
212                                        G4int axis)
213 {
214   // "CreateBoundaries"'s aim is to determine the slices induced by the
215   // bounding fBoxes, along each axis. The created boundaries are stored
216   // in the array "boundariesRaw"
217 
218   std::size_t numNodes = fBoxes.size(); // Number of nodes in structure
219 
220   // Determination of the boundaries along x, y and z axis
221   //
222   for(std::size_t i = 0 ; i < numNodes; ++i)   
223   {
224     // For each node, the boundaries are created by using the array "fBoxes"
225     // built in method "BuildVoxelLimits"
226     //
227     G4double p = fBoxes[i].pos[axis], d = fBoxes[i].hlen[axis];
228 
229     // x boundaries
230     //
231 #ifdef G4SPECSDEBUG
232     G4cout << "Boundary " << p - d << " - " << p + d << G4endl;
233 #endif
234     boundary[2*i] = p - d;
235     boundary[2*i+1] = p + d;
236   }
237   std::sort(boundary.begin(), boundary.end());
238 }
239 
240 //______________________________________________________________________________
241 void G4Voxelizer::BuildBoundaries()
242 {
243   // "SortBoundaries" orders the boundaries along each axis (increasing order)
244   // and also does not take into account redundant boundaries, i.e. if two
245   // boundaries are separated by a distance strictly inferior to "tolerance".
246   // The sorted boundaries are respectively stored in:
247   //              * boundaries[0..2]
248 
249   // In addition, the number of elements contained in the three latter arrays
250   // are precise thanks to variables: boundariesCountX, boundariesCountY and
251   // boundariesCountZ.
252 
253   if (std::size_t numNodes = fBoxes.size())
254   {
255     const G4double tolerance = fTolerance / 100.0;
256       // Minimal distance to discriminate two boundaries.
257 
258     std::vector<G4double> sortedBoundary(2*numNodes);
259 
260     for (auto j = 0; j <= 2; ++j)
261     {
262       CreateSortedBoundary(sortedBoundary, j);
263       std::vector<G4double> &boundary = fBoundaries[j];
264       boundary.clear();
265 
266       for(std::size_t i = 0 ; i < 2*numNodes; ++i)
267       {
268         G4double newBoundary = sortedBoundary[i];
269 #ifdef G4SPECSDEBUG 
270         if (j == 0) G4cout << "Examining " << newBoundary << "..." << G4endl;
271 #endif
272         auto size = (G4int)boundary.size();
273         if((size == 0) || std::abs(boundary[size-1] - newBoundary) > tolerance)
274         {
275           {
276 #ifdef G4SPECSDEBUG     
277             if (j == 0) G4cout << "Adding boundary " << newBoundary << "..."
278                                << G4endl;
279 #endif    
280             boundary.push_back(newBoundary);
281             continue;
282           }
283         }
284         // If two successive boundaries are too close from each other,
285         // only the first one is considered   
286       }
287 
288       auto n = (G4int)boundary.size();
289       G4int max = 100000;
290       if (n > max/2)
291       {
292         G4int skip = n / (max /2); // n has to be 2x bigger then 50.000.
293                                    // therefore only from 100.000 reduced
294         std::vector<G4double> reduced;
295         for (G4int i = 0; i < n; ++i)
296         {
297           // 50 ok for 2k, 1000, 2000
298           auto size = (G4int)boundary.size();
299           if (i % skip == 0 || i == 0 || i == size - 1)
300           {
301             // this condition of merging boundaries was wrong,
302             // it did not count with right part, which can be
303             // completely ommited and not included in final consideration.
304             // Now should be OK
305             //
306             reduced.push_back(boundary[i]);
307           }
308         }
309         boundary = std::move(reduced);
310       }
311     }
312   }
313 }
314 
315 //______________________________________________________________________________
316 void G4Voxelizer::DisplayBoundaries()
317 {
318   char axis[3] = {'X', 'Y', 'Z'};
319   for (auto i = 0; i <= 2; ++i)
320   {
321     G4cout << " * " << axis[i] << " axis:" << G4endl << "    | ";
322     DisplayBoundaries(fBoundaries[i]);
323   }
324 }
325 
326 //______________________________________________________________________________
327 void G4Voxelizer::DisplayBoundaries(std::vector<G4double> &boundaries)
328 {
329   // Prints the positions of the boundaries of the slices on the three axes
330 
331   std::size_t count = boundaries.size();
332   G4long oldprec = G4cout.precision(16);
333   for(std::size_t i = 0; i < count; ++i)
334   {
335     G4cout << setw(10) << setiosflags(ios::fixed) << boundaries[i];
336     if(i != count-1) G4cout << "-> ";
337   }
338   G4cout << "|" << G4endl << "Number of boundaries: " << count << G4endl;
339   G4cout.precision(oldprec);
340 }
341 
342 //______________________________________________________________________________
343 void G4Voxelizer::BuildBitmasks(std::vector<G4double> boundaries[],
344                                 G4SurfBits bitmasks[], G4bool countsOnly)
345 {
346   // "BuildListNodes" stores in the bitmasks solids present in each slice
347   // along an axis.
348 
349   std::size_t numNodes = fBoxes.size();
350   G4int bitsPerSlice = GetBitsPerSlice();
351 
352   for (auto k = 0; k < 3; ++k)
353   {
354     std::vector<G4double>& boundary = boundaries[k];
355     G4int voxelsCount = (G4int)boundary.size() - 1;
356     G4SurfBits& bitmask = bitmasks[k];
357 
358     if (!countsOnly)
359     {
360       bitmask.Clear();
361 #ifdef G4SPECSDEBUG
362       G4cout << "Allocating bitmask..." << G4endl;
363 #endif
364       bitmask.SetBitNumber(voxelsCount*bitsPerSlice-1, false);
365         // it is here so we can set the maximum number of bits. this line
366         // will rellocate the memory and set all to zero
367     }
368     std::vector<G4int>& candidatesCount = fCandidatesCounts[k];
369     candidatesCount.resize(voxelsCount);
370 
371     for(G4int i = 0 ; i < voxelsCount; ++i) { candidatesCount[i] = 0; }
372 
373     // Loop on the nodes, number of slices per axis
374     //
375     for(std::size_t j = 0 ; j < numNodes; ++j)
376     {
377       // Determination of the minimum and maximum position along x
378       // of the bounding boxe of each node
379       //
380       G4double p = fBoxes[j].pos[k], d = fBoxes[j].hlen[k];
381 
382       G4double min = p - d; // - localTolerance;
383       G4double max = p + d; // + localTolerance;
384 
385       G4int i = BinarySearch(boundary, min);
386       if (i < 0)  { i = 0; }
387 
388       do    // Loop checking, 13.08.2015, G.Cosmo
389       {
390         if (!countsOnly)
391         {
392           bitmask.SetBitNumber(i*bitsPerSlice+(G4int)j);
393         }
394         candidatesCount[i]++;
395         ++i;
396       }
397       while (max > boundary[i] && i < voxelsCount);
398     }
399   }
400 #ifdef G4SPECSDEBUG
401   G4cout << "Build list nodes completed." << G4endl;
402 #endif
403 }
404 
405 //______________________________________________________________________________
406 G4String G4Voxelizer::GetCandidatesAsString(const G4SurfBits& bits) const
407 {
408   // Decodes the candidates in mask as G4String.
409 
410   stringstream ss;
411   auto numNodes = (G4int)fBoxes.size();
412 
413   for(auto i=0; i<numNodes; ++i)
414   {
415     if (bits.TestBitNumber(i))  { ss << i+1 << " "; }
416   }
417   return ss.str();
418 }
419 
420 //______________________________________________________________________________
421 void G4Voxelizer::DisplayListNodes() const
422 {
423   // Prints which solids are present in the slices previously elaborated.
424 
425   char axis[3] = {'X', 'Y', 'Z'};
426   G4int size=8*sizeof(G4int)*fNPerSlice;
427   G4SurfBits bits(size);
428 
429   for (auto j = 0; j <= 2; ++j)
430   {
431     G4cout << " * " << axis[j] << " axis:" << G4endl;
432     auto count = (G4int)fBoundaries[j].size();
433     for(G4int i=0; i < count-1; ++i)
434     {
435       G4cout << "    Slice #" << i+1 << ": [" << fBoundaries[j][i]
436              << " ; " << fBoundaries[j][i+1] << "] -> ";
437       bits.set(size,(const char *)fBitmasks[j].fAllBits+i
438                                  *fNPerSlice*sizeof(G4int));
439       G4String result = GetCandidatesAsString(bits);
440       G4cout << "[ " << result.c_str() << "]  " << G4endl;
441     }
442   }
443 }
444 
445 //______________________________________________________________________________
446 void G4Voxelizer::BuildBoundingBox()
447 {
448   G4ThreeVector min(fBoundaries[0].front(),
449                     fBoundaries[1].front(),
450                     fBoundaries[2].front());
451   G4ThreeVector max(fBoundaries[0].back(),
452                     fBoundaries[1].back(),
453                     fBoundaries[2].back());
454   BuildBoundingBox(min, max);
455 }
456 
457 //______________________________________________________________________________
458 void G4Voxelizer::BuildBoundingBox(G4ThreeVector& amin,
459                                    G4ThreeVector& amax,
460                                    G4double tolerance)
461 {
462   for (auto i = 0; i <= 2; ++i)
463   {
464     G4double min = amin[i];
465     G4double max = amax[i];
466     fBoundingBoxSize[i] = (max - min) / 2 + tolerance * 0.5;
467     fBoundingBoxCenter[i] = min + fBoundingBoxSize[i];
468   }
469   fBoundingBox.SetXHalfLength(fBoundingBoxSize.x());
470   fBoundingBox.SetYHalfLength(fBoundingBoxSize.y());
471   fBoundingBox.SetZHalfLength(fBoundingBoxSize.z());
472 }
473 
474 // algorithm - 
475 
476 // in order to get balanced voxels, merge should always unite those regions,
477 // where the number of voxels is least the number.
478 // We will keep sorted list (std::set) with all voxels. there will be
479 // comparator function between two voxels, which will tell if voxel is less
480 // by looking at his right neighbor.
481 // First, we will add all the voxels into the tree.
482 // We will be pick the first item in the tree, merging it, adding the right
483 // merged voxel into the a list for future reduction (fBitmasks will be
484 // rebuilded later, therefore they need not to be updated).
485 // The merged voxel need to be added to the tree again, so it's position
486 // would be updated.
487 
488 //______________________________________________________________________________
489 void G4Voxelizer::SetReductionRatio(G4int maxVoxels,
490                                     G4ThreeVector& reductionRatio)
491 {
492   G4double maxTotal = (G4double) fCandidatesCounts[0].size()
493                     * fCandidatesCounts[1].size() * fCandidatesCounts[2].size();
494 
495   if (maxVoxels > 0 && maxVoxels < maxTotal)
496   {
497     G4double ratio = (G4double) maxVoxels / maxTotal;
498     ratio = std::pow(ratio, 1./3.);
499     if (ratio > 1)  { ratio = 1; }
500     reductionRatio.set(ratio,ratio,ratio);
501   }
502 }
503 
504 //______________________________________________________________________________
505 void G4Voxelizer::BuildReduceVoxels(std::vector<G4double> boundaries[],
506                                     G4ThreeVector reductionRatio)
507 {
508   for (auto k = 0; k <= 2; ++k)
509   {
510     std::vector<G4int> &candidatesCount = fCandidatesCounts[k];
511     auto max = (G4int)candidatesCount.size();
512     std::vector<G4VoxelInfo> voxels(max);
513     G4VoxelComparator comp(voxels);
514     std::set<G4int, G4VoxelComparator> voxelSet(comp);
515     std::vector<G4int> mergings;
516 
517     for (G4int j = 0; j < max; ++j)
518     {
519       G4VoxelInfo &voxel = voxels[j];
520       voxel.count = candidatesCount[j];
521       voxel.previous = j - 1;
522       voxel.next = j + 1;
523       voxels[j] = voxel;
524     }
525 
526     for (G4int j = 0; j < max - 1; ++j)  { voxelSet.insert(j); }
527       // we go to size-1 to make sure we will not merge the last element
528 
529     G4double reduction = reductionRatio[k];
530     if (reduction != 0)
531     {
532       G4int count = 0, currentCount;
533       while ((currentCount = (G4int)voxelSet.size()) > 2) 
534       {
535         G4double currentRatio = 1 - (G4double) count / max;
536         if ((currentRatio <= reduction) && (currentCount <= 1000))
537           break;
538         const G4int pos = *voxelSet.begin();
539         mergings.push_back(pos + 1);
540 
541         G4VoxelInfo& voxel = voxels[pos];
542         G4VoxelInfo& nextVoxel = voxels[voxel.next];
543 
544         if (voxelSet.erase(pos) != 1)
545         {
546           ;// k = k;
547         }
548         if (voxel.next != max - 1)
549           if (voxelSet.erase(voxel.next) != 1)
550           {
551             ;// k = k;
552           }
553         if (voxel.previous != -1)
554           if (voxelSet.erase(voxel.previous) != 1)
555           {
556             ;// k = k;
557           }
558         nextVoxel.count += voxel.count;
559         voxel.count = 0;
560         nextVoxel.previous = voxel.previous;
561 
562         if (voxel.next != max - 1)
563           voxelSet.insert(voxel.next);
564 
565         if (voxel.previous != -1)
566         {
567           voxels[voxel.previous].next = voxel.next;
568           voxelSet.insert(voxel.previous);
569         }
570         ++count;
571       }  // Loop checking, 13.08.2015, G.Cosmo
572     }
573 
574     if (!mergings.empty())
575     {
576       std::sort(mergings.begin(), mergings.end());
577 
578       const std::vector<G4double>& boundary = boundaries[k];
579       auto mergingsSize = (G4int)mergings.size();
580       vector<G4double> reducedBoundary;
581       G4int skip = mergings[0], i = 0;
582       max = (G4int)boundary.size();
583       for (G4int j = 0; j < max; ++j)
584       {
585         if (j != skip)
586         {
587           reducedBoundary.push_back(boundary[j]);
588         }
589         else if (++i < mergingsSize)
590         {
591           skip = mergings[i];
592         }
593       }
594       boundaries[k] = std::move(reducedBoundary);
595     }
596 /*
597     G4int count = 0;
598     while (true)    // Loop checking, 13.08.2015, G.Cosmo
599     {
600       G4double reduction = reductionRatio[k];
601       if (reduction == 0)
602         break;
603       G4int currentCount = voxelSet.size();
604       if (currentCount <= 2)
605         break;
606       G4double currentRatio = 1 - (G4double) count / max;
607       if (currentRatio <= reduction && currentCount <= 1000)
608         break;
609       const G4int pos = *voxelSet.begin();
610       mergings.push_back(pos);
611 
612       G4VoxelInfo &voxel = voxels[pos];
613       G4VoxelInfo &nextVoxel = voxels[voxel.next];
614 
615       voxelSet.erase(pos);
616       if (voxel.next != max - 1) { voxelSet.erase(voxel.next); }
617       if (voxel.previous != -1)  { voxelSet.erase(voxel.previous); }
618 
619       nextVoxel.count += voxel.count;
620       voxel.count = 0;
621       nextVoxel.previous = voxel.previous;
622 
623       if (voxel.next != max - 1)
624         voxelSet.insert(voxel.next);
625 
626       if (voxel.previous != -1)
627       {
628         voxels[voxel.previous].next = voxel.next;
629         voxelSet.insert(voxel.previous);
630       }
631       ++count;
632     }
633 
634     if (mergings.size())
635     {
636       std::sort(mergings.begin(), mergings.end());
637 
638       std::vector<G4double> &boundary = boundaries[k];
639       std::vector<G4double> reducedBoundary(boundary.size() - mergings.size());
640       G4int skip = mergings[0] + 1, cur = 0, i = 0;
641       max = boundary.size();
642       for (G4int j = 0; j < max; ++j)
643       {
644         if (j != skip)
645         {
646           reducedBoundary[cur++] = boundary[j];
647         }
648         else
649         {
650           if (++i < (G4int)mergings.size())  { skip = mergings[i] + 1; }
651         }
652       }
653       boundaries[k] = reducedBoundary;
654     }
655 */
656   }
657 }
658 
659 //______________________________________________________________________________
660 void G4Voxelizer::BuildReduceVoxels2(std::vector<G4double> boundaries[],
661                                      G4ThreeVector reductionRatio)
662 {
663   for (auto k = 0; k <= 2; ++k)
664   {
665     std::vector<G4int> &candidatesCount = fCandidatesCounts[k];
666     auto max = (G4int)candidatesCount.size();
667     G4int total = 0;
668     for (G4int i = 0; i < max; ++i) total += candidatesCount[i];
669 
670     G4double reduction = reductionRatio[k];
671     if (reduction == 0)
672       break;
673 
674     G4int destination = (G4int) (reduction * max) + 1;
675     if (destination > 1000) destination = 1000;
676     if (destination < 2) destination = 2;
677     G4double average = ((G4double)total / max) / reduction;
678 
679     std::vector<G4int> mergings;
680 
681     std::vector<G4double> &boundary = boundaries[k];
682     std::vector<G4double> reducedBoundary(destination);
683 
684     G4int sum = 0, cur = 0;
685     for (G4int i = 0; i < max; ++i)
686     {
687       sum += candidatesCount[i];
688       if (sum > average * (cur + 1) || i == 0)
689       {
690         G4double val = boundary[i];
691         reducedBoundary[cur] = val;
692         ++cur;
693         if (cur == destination)
694           break;
695       }
696     }
697     reducedBoundary[destination-1] = boundary[max];
698     boundaries[k] = std::move(reducedBoundary);
699   }
700 }
701 
702 //______________________________________________________________________________
703 void G4Voxelizer::Voxelize(std::vector<G4VSolid*>& solids,
704                            std::vector<G4Transform3D>& transforms)
705 {
706   BuildVoxelLimits(solids, transforms);
707   BuildBoundaries();
708   BuildBitmasks(fBoundaries, fBitmasks);
709   BuildBoundingBox();
710   BuildEmpty(); // this does not work well for multi-union,
711                 // actually only makes performance slower,
712                 // these are only pre-calculated but not used by multi-union
713 
714   for (auto & fCandidatesCount : fCandidatesCounts)
715   {
716     fCandidatesCount.resize(0);
717   }
718 }
719 
720 //______________________________________________________________________________
721 void G4Voxelizer::CreateMiniVoxels(std::vector<G4double> boundaries[],
722                                    G4SurfBits bitmasks[])
723 {
724   std::vector<G4int> voxel(3), maxVoxels(3);
725   for (auto i = 0; i <= 2; ++i) maxVoxels[i] = (G4int)boundaries[i].size();
726 
727   G4ThreeVector point;
728   for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
729   {
730     for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
731     {
732       for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
733       {
734         std::vector<G4int> candidates;
735         if (GetCandidatesVoxelArray(voxel, bitmasks, candidates, nullptr) != 0)
736         {
737           // find a box for corresponding non-empty voxel
738           G4VoxelBox box;
739           for (auto i = 0; i <= 2; ++i)
740           {
741             G4int index = voxel[i];
742             const std::vector<G4double> &boundary = boundaries[i];
743             G4double hlen = 0.5 * (boundary[index+1] - boundary[index]);
744             box.hlen[i] = hlen;
745             box.pos[i] = boundary[index] + hlen;
746           }
747           fVoxelBoxes.push_back(box);
748           std::vector<G4int>(candidates).swap(candidates);
749           fVoxelBoxesCandidates.push_back(std::move(candidates));
750         }
751       }
752     }
753   }
754 }
755 
756 //______________________________________________________________________________
757 void G4Voxelizer::Voxelize(std::vector<G4VFacet*>& facets)
758 {
759   G4int maxVoxels = fMaxVoxels;
760   G4ThreeVector reductionRatio = fReductionRatio;
761 
762   std::size_t size = facets.size();
763   if (size < 10)
764   {
765     for (const auto & facet : facets)
766     { 
767       if (facet->GetNumberOfVertices() > 3) ++size;
768     }
769   }
770 
771   if ((size >= 10 || maxVoxels > 0) && maxVoxels != 0 && maxVoxels != 1)
772   {
773 #ifdef G4SPECSDEBUG
774     G4cout << "Building voxel limits..." << G4endl;
775 #endif
776     
777     BuildVoxelLimits(facets);
778 
779 #ifdef G4SPECSDEBUG
780     G4cout << "Building boundaries..." << G4endl;
781 #endif
782     
783     BuildBoundaries();
784 
785 #ifdef G4SPECSDEBUG
786     G4cout << "Building bitmasks..." << G4endl;
787 #endif
788     
789     BuildBitmasks(fBoundaries, nullptr, true);
790 
791     if (maxVoxels < 0 && reductionRatio == G4ThreeVector())
792     {
793       maxVoxels = fTotalCandidates;
794       if (fTotalCandidates > 1000000) maxVoxels = 1000000;
795     }
796 
797     SetReductionRatio(maxVoxels, reductionRatio);
798 
799     fCountOfVoxels = CountVoxels(fBoundaries);
800 
801 #ifdef G4SPECSDEBUG
802     G4cout << "Total number of voxels: " << fCountOfVoxels << G4endl;
803 #endif
804 
805     BuildReduceVoxels2(fBoundaries, reductionRatio);
806 
807     fCountOfVoxels = CountVoxels(fBoundaries);
808 
809 #ifdef G4SPECSDEBUG
810     G4cout << "Total number of voxels after reduction: "
811            << fCountOfVoxels << G4endl;
812 #endif
813 
814 #ifdef G4SPECSDEBUG
815     G4cout << "Building bitmasks..." << G4endl;
816 #endif
817     
818     BuildBitmasks(fBoundaries, fBitmasks);
819 
820     G4ThreeVector reductionRatioMini;
821 
822     G4SurfBits bitmasksMini[3];
823 
824     // section for building mini voxels
825 
826     std::vector<G4double> miniBoundaries[3];
827 
828     for (auto i = 0; i <= 2; ++i)  { miniBoundaries[i] = fBoundaries[i]; }
829 
830     G4int voxelsCountMini = (fCountOfVoxels >= 1000)
831                           ? 100 : G4int(fCountOfVoxels / 10);
832 
833     SetReductionRatio(voxelsCountMini, reductionRatioMini);
834 
835 #ifdef G4SPECSDEBUG
836     G4cout << "Building reduced voxels..." << G4endl;
837 #endif
838     
839     BuildReduceVoxels(miniBoundaries, reductionRatioMini);
840 
841 #ifdef G4SPECSDEBUG
842     G4int total = CountVoxels(miniBoundaries);
843     G4cout << "Total number of mini voxels: " << total << G4endl;
844 #endif
845 
846 #ifdef G4SPECSDEBUG
847     G4cout << "Building mini bitmasks..." << G4endl;
848 #endif
849     
850     BuildBitmasks(miniBoundaries, bitmasksMini);
851 
852 #ifdef G4SPECSDEBUG
853     G4cout << "Creating Mini Voxels..." << G4endl;
854 #endif
855     
856     CreateMiniVoxels(miniBoundaries, bitmasksMini);
857 
858 #ifdef G4SPECSDEBUG
859     G4cout << "Building bounding box..." << G4endl;
860 #endif
861     
862     BuildBoundingBox();
863 
864 #ifdef G4SPECSDEBUG
865     G4cout << "Building empty..." << G4endl;
866 #endif
867     
868     BuildEmpty();
869 
870 #ifdef G4SPECSDEBUG
871     G4cout << "Deallocating unnecessary fields during runtime..." << G4endl;
872 #endif    
873     // deallocate fields unnecessary during runtime
874     //
875     fBoxes.resize(0);
876     for (auto i = 0; i < 3; ++i)
877     {
878       fCandidatesCounts[i].resize(0);
879       fBitmasks[i].Clear();
880     }
881   }
882 }
883 
884 
885 //______________________________________________________________________________
886 void G4Voxelizer::GetCandidatesVoxel(std::vector<G4int>& voxels)
887 {
888   // "GetCandidates" should compute which solids are possibly contained in
889   // the voxel defined by the three slices characterized by the passed indexes.
890 
891   G4cout << "   Candidates in voxel [" << voxels[0] << " ; " << voxels[1]
892          << " ; " << voxels[2] << "]: ";
893   std::vector<G4int> candidates;
894   G4int count = GetCandidatesVoxelArray(voxels, candidates);
895   G4cout << "[ ";
896   for (G4int i = 0; i < count; ++i) G4cout << candidates[i];
897   G4cout << "]  " << G4endl;
898 }
899 
900 //______________________________________________________________________________
901 void G4Voxelizer::FindComponentsFastest(unsigned int mask,
902                                          std::vector<G4int>& list, G4int i)
903 {
904   for (G4int byte = 0; byte < (G4int) (sizeof(unsigned int)); ++byte)
905   {
906     if (G4int maskByte = mask & 0xFF)
907     {
908       for (G4int bit = 0; bit < 8; ++bit)
909       {
910         if ((maskByte & 1) != 0) 
911           { list.push_back(8*(sizeof(unsigned int)*i+ byte) + bit); }
912         if ((maskByte >>= 1) == 0) break;
913       }
914     }
915     mask >>= 8;
916   }
917 }
918 
919 //______________________________________________________________________________
920 void G4Voxelizer::TransformLimits(G4ThreeVector& min, G4ThreeVector& max,
921                                   const G4Transform3D& transformation) const
922 {
923   // The goal of this method is to convert the quantities min and max
924   // (representing the bounding box of a given solid in its local frame)
925   // to the main frame, using "transformation"
926 
927   G4ThreeVector vertices[8] =     // Detemination of the vertices thanks to
928   {                               // the extension of each solid:
929     G4ThreeVector(min.x(), min.y(), min.z()), // 1st vertice:
930     G4ThreeVector(min.x(), max.y(), min.z()), // 2nd vertice:
931     G4ThreeVector(max.x(), max.y(), min.z()),
932     G4ThreeVector(max.x(), min.y(), min.z()),
933     G4ThreeVector(min.x(), min.y(), max.z()),
934     G4ThreeVector(min.x(), max.y(), max.z()),
935     G4ThreeVector(max.x(), max.y(), max.z()),
936     G4ThreeVector(max.x(), min.y(), max.z())
937   };
938 
939   min.set(kInfinity,kInfinity,kInfinity);
940   max.set(-kInfinity,-kInfinity,-kInfinity);
941 
942   // Loop on th vertices
943   G4int limit = sizeof(vertices) / sizeof(G4ThreeVector);
944   for (G4int i = 0 ; i < limit; ++i)
945   {
946     // From local frame to the global one:
947     // Current positions on the three axis:
948     G4ThreeVector current = GetGlobalPoint(transformation, vertices[i]);
949 
950     // If need be, replacement of the min & max values:
951     if (current.x() > max.x()) max.setX(current.x());
952     if (current.x() < min.x()) min.setX(current.x());
953 
954     if (current.y() > max.y()) max.setY(current.y());
955     if (current.y() < min.y()) min.setY(current.y());
956 
957     if (current.z() > max.z()) max.setZ(current.z());
958     if (current.z() < min.z()) min.setZ(current.z());
959   }
960 }
961 
962 //______________________________________________________________________________
963 G4int G4Voxelizer::GetCandidatesVoxelArray(const G4ThreeVector &point,
964                           std::vector<G4int> &list, G4SurfBits *crossed) const
965 {
966   // Method returning the candidates corresponding to the passed point
967 
968   list.clear();
969 
970   for (auto i = 0; i <= 2; ++i)
971   {
972     if(point[i] < fBoundaries[i].front() || point[i] >= fBoundaries[i].back()) 
973       return 0;
974   }
975 
976   if (fTotalCandidates == 1)
977   {
978     list.push_back(0);
979     return 1;
980   } 
981   else
982   {
983     if (fNPerSlice == 1)
984     {
985       unsigned int mask = 0xFFffFFff;
986       G4int slice;
987       if (fBoundaries[0].size() > 2)
988       {
989         slice = BinarySearch(fBoundaries[0], point.x());
990         if ((mask = ((unsigned int*) fBitmasks[0].fAllBits)[slice]) == 0u)
991           return 0;
992       }
993       if (fBoundaries[1].size() > 2)
994       {
995         slice = BinarySearch(fBoundaries[1], point.y());
996         if ((mask &= ((unsigned int*) fBitmasks[1].fAllBits)[slice]) == 0u)
997           return 0;
998       }
999       if (fBoundaries[2].size() > 2)
1000       {
1001         slice = BinarySearch(fBoundaries[2], point.z());
1002         if ((mask &= ((unsigned int*) fBitmasks[2].fAllBits)[slice]) == 0u)
1003           return 0;
1004       }
1005       if ((crossed != nullptr) && ((mask &= ~((unsigned int*)crossed->fAllBits)[0]) == 0u))
1006         return 0;
1007 
1008       FindComponentsFastest(mask, list, 0);
1009     }
1010     else
1011     {
1012       unsigned int* masks[3], mask; // masks for X,Y,Z axis
1013       for (auto i = 0; i <= 2; ++i)
1014       {
1015         G4int slice = BinarySearch(fBoundaries[i], point[i]);
1016         masks[i] = ((unsigned int*) fBitmasks[i].fAllBits)
1017                  + slice * fNPerSlice;
1018       }
1019       unsigned int* maskCrossed = crossed != nullptr
1020                                 ? (unsigned int*)crossed->fAllBits : nullptr;
1021 
1022       for (G4int i = 0 ; i < fNPerSlice; ++i)
1023       {
1024         // Logic "and" of the masks along the 3 axes x, y, z:
1025         // removing "if (!" and ") continue" => slightly slower
1026         //
1027         if ((mask = masks[0][i]) == 0u) continue;
1028         if ((mask &= masks[1][i]) == 0u) continue;
1029         if ((mask &= masks[2][i]) == 0u) continue;
1030         if ((maskCrossed != nullptr) && ((mask &= ~maskCrossed[i]) == 0u)) continue;
1031 
1032         FindComponentsFastest(mask, list, i);
1033       }
1034     }
1035 /*
1036     if (fNPerSlice == 1)
1037     {
1038       unsigned int mask;
1039       G4int slice = BinarySearch(fBoundaries[0], point.x()); 
1040       if (!(mask = ((unsigned int *) fBitmasks[0].fAllBits)[slice]
1041       )) return 0;
1042       slice = BinarySearch(fBoundaries[1], point.y());
1043       if (!(mask &= ((unsigned int *) fBitmasks[1].fAllBits)[slice]
1044       )) return 0;
1045       slice = BinarySearch(fBoundaries[2], point.z());
1046       if (!(mask &= ((unsigned int *) fBitmasks[2].fAllBits)[slice]
1047       )) return 0;
1048       if (crossed && (!(mask &= ~((unsigned int *)crossed->fAllBits)[0])))
1049         return 0;
1050 
1051       FindComponentsFastest(mask, list, 0);
1052     }
1053     else
1054     {
1055       unsigned int *masks[3], mask; // masks for X,Y,Z axis
1056       for (auto i = 0; i <= 2; ++i)
1057       {
1058         G4int slice = BinarySearch(fBoundaries[i], point[i]); 
1059         masks[i] = ((unsigned int *) fBitmasks[i].fAllBits) + slice*fNPerSlice;
1060       }
1061       unsigned int *maskCrossed =
1062         crossed ? (unsigned int *)crossed->fAllBits : 0;
1063 
1064       for (G4int i = 0 ; i < fNPerSlice; ++i)
1065       {
1066         // Logic "and" of the masks along the 3 axes x, y, z:
1067         // removing "if (!" and ") continue" => slightly slower
1068         //
1069         if (!(mask = masks[0][i])) continue;
1070         if (!(mask &= masks[1][i])) continue;
1071         if (!(mask &= masks[2][i])) continue;
1072         if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
1073 
1074         FindComponentsFastest(mask, list, i);
1075       }
1076     }
1077 */
1078   }
1079   return (G4int)list.size();
1080 }
1081 
1082 //______________________________________________________________________________
1083 G4int
1084 G4Voxelizer::GetCandidatesVoxelArray(const std::vector<G4int>& voxels,
1085                                      const G4SurfBits bitmasks[],
1086                                      std::vector<G4int>& list,
1087                                      G4SurfBits* crossed) const
1088 {
1089   list.clear();
1090 
1091   if (fTotalCandidates == 1)
1092   {
1093     list.push_back(0);
1094     return 1;
1095   }
1096   else
1097   {
1098     if (fNPerSlice == 1)
1099     {
1100       unsigned int mask;
1101       if ((mask = ((unsigned int *) bitmasks[0].fAllBits)[voxels[0]]) == 0u)
1102         return 0;
1103       if ((mask &= ((unsigned int *) bitmasks[1].fAllBits)[voxels[1]]) == 0u)
1104         return 0;
1105       if ((mask &= ((unsigned int *) bitmasks[2].fAllBits)[voxels[2]]) == 0u)
1106         return 0;
1107       if ((crossed != nullptr) && ((mask &= ~((unsigned int *)crossed->fAllBits)[0]) == 0u))
1108         return 0;
1109 
1110       FindComponentsFastest(mask, list, 0);
1111     }
1112     else
1113     {
1114       unsigned int *masks[3], mask; // masks for X,Y,Z axis
1115       for (auto i = 0; i <= 2; ++i)
1116       {
1117         masks[i] = ((unsigned int *) bitmasks[i].fAllBits)
1118                  + voxels[i]*fNPerSlice;
1119       }
1120       unsigned int *maskCrossed = crossed != nullptr
1121                                 ? (unsigned int *)crossed->fAllBits : nullptr;
1122 
1123       for (G4int i = 0 ; i < fNPerSlice; ++i)
1124       {
1125         // Logic "and" of the masks along the 3 axes x, y, z:
1126         // removing "if (!" and ") continue" => slightly slower
1127         //
1128         if ((mask = masks[0][i]) == 0u) continue;
1129         if ((mask &= masks[1][i]) == 0u) continue;
1130         if ((mask &= masks[2][i]) == 0u) continue;
1131         if ((maskCrossed != nullptr) && ((mask &= ~maskCrossed[i]) == 0u)) continue;
1132 
1133         FindComponentsFastest(mask, list, i);
1134       }
1135     }
1136   }
1137   return (G4int)list.size();
1138 }
1139 
1140 //______________________________________________________________________________
1141 G4int
1142 G4Voxelizer::GetCandidatesVoxelArray(const std::vector<G4int>& voxels,
1143                           std::vector<G4int>& list, G4SurfBits* crossed) const
1144 {
1145   // Method returning the candidates corresponding to the passed point
1146 
1147   return GetCandidatesVoxelArray(voxels, fBitmasks, list, crossed);
1148 }
1149 
1150 //______________________________________________________________________________
1151 G4bool G4Voxelizer::Contains(const G4ThreeVector& point) const
1152 {
1153   for (auto i = 0; i < 3; ++i)
1154   {
1155     if (point[i] < fBoundaries[i].front() || point[i] > fBoundaries[i].back())
1156       return false;
1157   }
1158   return true;
1159 }
1160 
1161 //______________________________________________________________________________
1162 G4double
1163 G4Voxelizer::DistanceToFirst(const G4ThreeVector& point,
1164                              const G4ThreeVector& direction) const
1165 {
1166   G4ThreeVector pointShifted = point - fBoundingBoxCenter;
1167   G4double shift = fBoundingBox.DistanceToIn(pointShifted, direction);
1168   return shift;
1169 }
1170 
1171 //______________________________________________________________________________
1172 G4double
1173 G4Voxelizer::DistanceToBoundingBox(const G4ThreeVector& point) const
1174 {
1175   G4ThreeVector pointShifted = point - fBoundingBoxCenter;
1176   G4double shift = MinDistanceToBox(pointShifted, fBoundingBoxSize);
1177   return shift;
1178 }
1179 
1180 //______________________________________________________________________________
1181 G4double
1182 G4Voxelizer::MinDistanceToBox (const G4ThreeVector& aPoint,
1183                                const G4ThreeVector& f)
1184 {
1185   // Estimates the isotropic safety from a point outside the current solid to
1186   // any of its surfaces. The algorithm may be accurate or should provide a
1187   // fast underestimate.
1188 
1189   G4double safe, safx, safy, safz;
1190   safe = safx = -f.x() + std::abs(aPoint.x());
1191   safy = -f.y() + std::abs(aPoint.y());
1192   if ( safy > safe ) safe = safy;
1193   safz = -f.z() + std::abs(aPoint.z());
1194   if ( safz > safe ) safe = safz;
1195   if (safe < 0.0) return 0.0; // point is inside
1196 
1197   G4double safsq = 0.0;
1198   G4int count = 0;
1199   if ( safx > 0 ) { safsq += safx*safx; ++count; }
1200   if ( safy > 0 ) { safsq += safy*safy; ++count; }
1201   if ( safz > 0 ) { safsq += safz*safz; ++count; }
1202   if (count == 1) return safe;
1203   return std::sqrt(safsq);
1204 }
1205 
1206 //______________________________________________________________________________
1207 G4double
1208 G4Voxelizer::DistanceToNext(const G4ThreeVector& point,
1209                             const G4ThreeVector& direction,
1210                                   std::vector<G4int>& curVoxel) const
1211 {
1212   G4double shift = kInfinity;
1213 
1214   G4int cur = 0; // the smallest index, which would be than increased
1215   for (G4int i = 0; i <= 2; ++i)
1216   {
1217     // Looking for the next voxels on the considered direction X,Y,Z axis
1218     //
1219     const std::vector<G4double>& boundary = fBoundaries[i];
1220     G4int index = curVoxel[i];
1221     if (direction[i] >= 1e-10)
1222     {
1223       ++index;
1224     }
1225     else
1226     {
1227       if (direction[i] > -1e-10)
1228         continue;
1229     }
1230     G4double dif = boundary[index] - point[i];
1231     G4double distance = dif / direction[i];
1232 
1233     if (shift > distance)
1234     {
1235       shift = distance;
1236       cur = i;
1237     }
1238   }
1239 
1240   if (shift != kInfinity)
1241   {
1242     // updating current voxel using the index corresponding
1243     // to the closest voxel boundary on the ray
1244 
1245     if (direction[cur] > 0)
1246     {
1247       if (++curVoxel[cur] >= (G4int) fBoundaries[cur].size() - 1)
1248         shift = kInfinity;
1249     }
1250     else
1251     {
1252       if (--curVoxel[cur] < 0)
1253         shift = kInfinity;
1254     }
1255   }
1256 
1257 /*
1258   for (auto i = 0; i <= 2; ++i)
1259   {
1260     // Looking for the next voxels on the considered direction X,Y,Z axis
1261     //
1262     const std::vector<G4double> &boundary = fBoundaries[i];
1263     G4int cur = curVoxel[i];
1264     if(direction[i] >= 1e-10)
1265     {
1266         if (boundary[++cur] - point[i] < fTolerance) // make sure shift would
1267         if (++cur >= (G4int) boundary.size())      // be non-zero
1268           continue;
1269     }
1270     else 
1271     {
1272       if(direction[i] <= -1e-10) 
1273       {
1274         if (point[i] - boundary[cur] < fTolerance) // make sure shift would
1275           if (--cur < 0)                           // be non-zero
1276             continue;
1277       }
1278       else 
1279         continue;
1280     }
1281     G4double dif = boundary[cur] - point[i];
1282     G4double distance = dif / direction[i];
1283 
1284     if (shift > distance) 
1285       shift = distance;
1286   }
1287 */
1288   return shift;
1289 }
1290 
1291 //______________________________________________________________________________
1292 G4bool
1293 G4Voxelizer::UpdateCurrentVoxel(const G4ThreeVector& point,
1294                                 const G4ThreeVector& direction,
1295                                 std::vector<G4int>& curVoxel) const
1296 {
1297   for (auto i = 0; i <= 2; ++i)
1298   {
1299     G4int index = curVoxel[i];
1300     const std::vector<G4double> &boundary = fBoundaries[i];
1301 
1302     if (direction[i] > 0) 
1303     {
1304       if (point[i] >= boundary[++index]) 
1305         if (++curVoxel[i] >= (G4int) boundary.size() - 1)
1306           return false;
1307     }
1308     else
1309     {
1310       if (point[i] < boundary[index]) 
1311         if (--curVoxel[i] < 0) 
1312           return false;
1313     }
1314 #ifdef G4SPECSDEBUG
1315     G4int indexOK = BinarySearch(boundary, point[i]);
1316     if (curVoxel[i] != indexOK)
1317       curVoxel[i] = indexOK; // put breakpoint here
1318 #endif
1319   }
1320   return true;
1321 }
1322 
1323 //______________________________________________________________________________
1324 void G4Voxelizer::SetMaxVoxels(G4int max)
1325 {
1326   fMaxVoxels = max;
1327   fReductionRatio.set(0,0,0);
1328 }
1329 
1330 //______________________________________________________________________________
1331 void G4Voxelizer::SetMaxVoxels(const G4ThreeVector& ratioOfReduction)
1332 {
1333   fMaxVoxels = -1;
1334   fReductionRatio = ratioOfReduction;
1335 }
1336 
1337 //______________________________________________________________________________
1338 void G4Voxelizer::SetDefaultVoxelsCount(G4int count)
1339 {
1340   fDefaultVoxelsCount = count;
1341 }
1342 
1343 //______________________________________________________________________________
1344 G4int G4Voxelizer::GetDefaultVoxelsCount()
1345 {
1346   return fDefaultVoxelsCount;
1347 }
1348 
1349 //______________________________________________________________________________
1350 G4int G4Voxelizer::AllocatedMemory()
1351 {
1352   G4int size = fEmpty.GetNbytes();
1353   size += fBoxes.capacity() * sizeof(G4VoxelBox);
1354   size += sizeof(G4double) * (fBoundaries[0].capacity()
1355         + fBoundaries[1].capacity() + fBoundaries[2].capacity());
1356   size += sizeof(G4int) * (fCandidatesCounts[0].capacity()
1357         + fCandidatesCounts[1].capacity() + fCandidatesCounts[2].capacity());
1358   size += fBitmasks[0].GetNbytes() + fBitmasks[1].GetNbytes()
1359         + fBitmasks[2].GetNbytes();
1360 
1361   auto csize = (G4int)fCandidates.size();
1362   for (G4int i = 0; i < csize; ++i)
1363   {
1364     size += sizeof(vector<G4int>) + fCandidates[i].capacity() * sizeof(G4int);
1365   }
1366 
1367   return size;
1368 }
1369