Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4SurfaceVoxelizer.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// $Id:$
27// GEANT4 tag $Name: not supported by cvs2svn $
28//
29// --------------------------------------------------------------------
30// GEANT 4 class header file
31//
32// G4SurfaceVoxelizer implementation
33//
34// History:
35// 19.10.12 Marek Gayer, created
36// --------------------------------------------------------------------
37
38#include <iostream>
39#include <iomanip>
40#include <sstream>
41#include <algorithm>
42#include <set>
43
44#include "G4VSolid.hh"
45
46#include "G4Orb.hh"
47#include "G4SurfaceVoxelizer.hh"
48#include "G4SolidStore.hh"
49#include "Randomize.hh"
52#include "G4CSGSolid.hh"
53#include "G4Types.hh"
54#include "geomdefs.hh"
55
56using namespace std;
57
58G4int G4SurfaceVoxelizer::fDefaultVoxelsCount = -1;
59
60//______________________________________________________________________________
62 : fBoundingBox("TessBBox", 1, 1, 1)
63{
64 fCountOfVoxels = fNPerSlice = fTotalCandidates = 0;
65
67
68 SetMaxVoxels(fDefaultVoxelsCount);
69
70 G4SolidStore::GetInstance()->DeRegister(&fBoundingBox);
71}
72
73//______________________________________________________________________________
75{
76}
77
78//______________________________________________________________________________
79void G4SurfaceVoxelizer::BuildEmpty()
80{
81 // by reserving the size of candidates, we would avoid reallocation of
82 // the vector which could cause fragmentation
83 //
84 vector<G4int> xyz(3), max(3), candidates(fTotalCandidates);
85 const vector<G4int> empty(0);
86
87 for (G4int i = 0; i <= 2; i++) max[i] = fBoundaries[i].size();
88 unsigned int size = max[0] * max[1] * max[2];
89
90 fEmpty.Clear();
91 fEmpty.ResetBitNumber(size-1);
92 fEmpty.ResetAllBits(true);
93
94 for (xyz[2] = 0; xyz[2] < max[2]; ++xyz[2])
95 {
96 for (xyz[1] = 0; xyz[1] < max[1]; ++xyz[1])
97 {
98 for (xyz[0] = 0; xyz[0] < max[0]; ++xyz[0])
99 {
100 G4int index = GetVoxelsIndex(xyz);
101 if (GetCandidatesVoxelArray(xyz, candidates))
102 {
103 fEmpty.SetBitNumber(index, false);
104
105 // rather than assigning directly with:
106 // "fCandidates[index] = candidates;", in an effort to ensure that
107 // capacity would be just exact, we rather use following 3 lines
108 //
109 vector<G4int> &c = (fCandidates[index] = empty);
110 c.reserve(candidates.size());
111 c.assign(candidates.begin(), candidates.end());
112 }
113 }
114 }
115 }
116#ifdef G4SPECSDEBUG
117 G4cout << "Non-empty voxels count: " << fCandidates.size() << endl;
118#endif
119}
120
121//______________________________________________________________________________
122void G4SurfaceVoxelizer::BuildVoxelLimits(std::vector<G4VFacet *> &facets)
123{
124 // "BuildVoxelLimits"'s aim is to store the coordinates of the origin as well
125 // as the half lengths related to the bounding box of each node.
126 // These quantities are stored in the array "fBoxes" (6 different values per
127 // node.
128
129 if (G4int numNodes = facets.size()) // Number of nodes
130 {
131 fBoxes.resize(numNodes); // Array which will store the half lengths
132 fNPerSlice = 1+(fBoxes.size()-1)/(8*sizeof(unsigned int));
133
134 G4ThreeVector toleranceVector;
135 toleranceVector.set(10 * fTolerance,10 * fTolerance,10 * fTolerance);
136
137 for (G4int i = 0; i < numNodes; ++i)
138 {
139 G4VFacet &facet = *facets[i];
140 G4ThreeVector min, max;
141 G4ThreeVector x(1,0,0), y(0,1,0), z(0,0,1);
142 G4ThreeVector extent;
143 max.set (facet.Extent(x), facet.Extent(y), facet.Extent(z));
144 min.set (-facet.Extent(-x), -facet.Extent(-y), -facet.Extent(-z));
145 min -= toleranceVector; max += toleranceVector;
146 G4ThreeVector hlen = (max - min) / 2;
147 fBoxes[i].hlen = hlen;
148 fBoxes[i].pos = min + hlen;
149 }
150 fTotalCandidates = fBoxes.size();
151 }
152}
153
154//______________________________________________________________________________
156{
157 // "DisplayVoxelLimits" displays the dX, dY, dZ, pX, pY and pZ for each node
158
159 G4int numNodes = fBoxes.size();
160 G4int oldprec = G4cout.precision(16);
161 for(G4int i = 0; i < numNodes; ++i)
162 {
163 G4cout << setw(10) << setiosflags(ios::fixed) <<
164 " -> Node " << i+1 << ":\n" <<
165 "\t * [x,y,z] = " << fBoxes[i].hlen <<
166 "\t * [x,y,z] = " << fBoxes[i].pos << "\n";
167 }
168 G4cout.precision(oldprec);
169}
170
171//______________________________________________________________________________
172void G4SurfaceVoxelizer::CreateSortedBoundary(std::vector<G4double> &boundary,
173 G4int axis)
174{
175 // "CreateBoundaries"'s aim is to determine the slices induced by the
176 // bounding fBoxes, along each axis. The created boundaries are stored
177 // in the array "boundariesRaw"
178
179 G4int numNodes = fBoxes.size(); // Number of nodes in structure
180
181 // Determination of the boundaries along x, y and z axis
182 //
183 for(G4int i = 0 ; i < numNodes; ++i)
184 {
185 // For each node, the boundaries are created by using the array "fBoxes"
186 // built in method "BuildVoxelLimits"
187 //
188 G4double p = fBoxes[i].pos[axis], d = fBoxes[i].hlen[axis];
189
190 // x boundaries
191 //
192 boundary[2*i] = p - d;
193 boundary[2*i+1] = p + d;
194 }
195 sort(boundary.begin(), boundary.end());
196}
197
198//______________________________________________________________________________
199void G4SurfaceVoxelizer::BuildBoundaries()
200{
201 // "SortBoundaries" orders the boundaries along each axis (increasing order)
202 // and also does not take into account redundant boundaries, i.e. if two
203 // boundaries are separated by a distance strictly inferior to "tolerance".
204 // The sorted boundaries are respectively stored in:
205 // * boundaries[0..2]
206
207 // In addition, the number of elements contained in the three latter arrays
208 // are precise thanks to variables: boundariesCountX, boundariesCountY and
209 // boundariesCountZ.
210
211 if (G4int numNodes = fBoxes.size())
212 {
213 const G4double tolerance = fTolerance / 100.0;
214 // Minimal distance to discriminate two boundaries.
215
216 vector<G4double> sortedBoundary(2*numNodes);
217
218 G4int considered;
219
220 for (G4int j = 0; j <= 2; ++j)
221 {
222 CreateSortedBoundary(sortedBoundary, j);
223 vector<G4double> &boundary = fBoundaries[j];
224 boundary.clear();
225
226 considered = 0;
227
228 for(G4int i = 0 ; i < 2*numNodes; ++i)
229 {
230 G4double newBoundary = sortedBoundary[i];
231 G4int size = boundary.size();
232 if(!size || abs(boundary[size-1] - newBoundary) > tolerance)
233 {
234 considered++;
235 {
236 boundary.push_back(newBoundary);
237 continue;
238 }
239 }
240 // If two successive boundaries are too close from each other,
241 // only the first one is considered
242 }
243
244 G4int n = boundary.size();
245 G4int max = 100000;
246 if (n > max/2)
247 {
248 G4int skip = n / (max /2); // n has to be 2x bigger then 50.000.
249 // therefore only from 100.000 reduced
250 vector<G4double> reduced;
251 for (G4int i = 0; i < n; i++)
252 {
253 // 50 ok for 2k, 1000, 2000
254 G4int size = boundary.size();
255 if (i % skip == 0 || i == 0 || i == size - 1)
256 {
257 // this condition of merging boundaries was wrong,
258 // it did not count with right part, which can be
259 // completely ommited and not included in final consideration.
260 // Now should be OK
261 //
262 reduced.push_back(boundary[i]);
263 }
264 }
265 boundary = reduced;
266 }
267 }
268 }
269}
270
271//______________________________________________________________________________
273{
274 char axis[3] = {'X', 'Y', 'Z'};
275 for (G4int i = 0; i <= 2; ++i)
276 {
277 G4cout << " * " << axis[i] << " axis:" << endl << " | ";
278 DisplayBoundaries(fBoundaries[i]);
279 }
280}
281
282//______________________________________________________________________________
283void G4SurfaceVoxelizer::DisplayBoundaries(std::vector<G4double> &boundaries)
284{
285 // Prints the positions of the boundaries of the slices on the three axes
286
287 G4int count = boundaries.size();
288 G4int oldprec = G4cout.precision(16);
289 for(G4int i = 0; i < count; ++i)
290 {
291 G4cout << setw(10) << setiosflags(ios::fixed) << boundaries[i];
292 if(i != count-1) G4cout << "-> ";
293 }
294 G4cout << "|" << endl << "Number of boundaries: " << count << endl;
295 G4cout.precision(oldprec);
296}
297
298//______________________________________________________________________________
299void G4SurfaceVoxelizer::BuildBitmasks(std::vector<G4double> boundaries[],
300 G4SurfBits bitmasks[], G4bool countsOnly)
301{
302 // "BuildListNodes" stores in the bitmasks solids present in each slice
303 // along an axis.
304
305 G4int numNodes = fBoxes.size();
306 G4int bitsPerSlice = GetBitsPerSlice();
307
308 for (G4int k = 0; k < 3; k++)
309 {
310 G4int total = 0;
311 vector<G4double> &boundary = boundaries[k];
312 G4int voxelsCount = boundary.size() - 1;
313 G4SurfBits &bitmask = bitmasks[k];
314
315 if (!countsOnly)
316 {
317 bitmask.Clear();
318 bitmask.SetBitNumber(voxelsCount*bitsPerSlice-1, false);
319 // it is here so we can set the maximum number of bits. this line
320 // will rellocate the memory and set all to zero
321 }
322 vector<G4int> &candidatesCount = fCandidatesCounts[k];
323 candidatesCount.resize(voxelsCount);
324
325 for(G4int i = 0 ; i < voxelsCount; ++i) { candidatesCount[i] = 0; }
326
327 // Loop on the nodes, number of slices per axis
328 //
329 for(G4int j = 0 ; j < numNodes; j++)
330 {
331 // Determination of the minimum and maximum position along x
332 // of the bounding boxe of each node
333 //
334 G4double p = fBoxes[j].pos[k], d = fBoxes[j].hlen[k];
335
336 G4double min = p - d; // - localTolerance;
337 G4double max = p + d; // + localTolerance;
338
339 G4int i = BinarySearch(boundary, min);
340
341 do
342 {
343 if (!countsOnly)
344 bitmask.SetBitNumber(i*bitsPerSlice+j);
345
346 candidatesCount[i]++;
347 total++;
348 i++;
349 }
350 while (max > boundary[i] && i < voxelsCount);
351 }
352 }
353#ifdef G4SPECSDEBUG
354 G4cout << "Build list nodes completed" << endl;
355#endif
356}
357
358//______________________________________________________________________________
359G4String G4SurfaceVoxelizer::GetCandidatesAsString(const G4SurfBits &bits)
360{
361 // Decodes the candidates in mask as G4String.
362
363 stringstream ss;
364 G4int numNodes = fBoxes.size();
365
366 for(G4int i=0; i<numNodes; ++i)
367 {
368 if (bits.TestBitNumber(i)) { ss << i+1 << " "; }
369 }
370 return ss.str();
371}
372
373//______________________________________________________________________________
375{
376 // Prints which solids are present in the slices previously elaborated.
377
378 char axis[3] = {'X', 'Y', 'Z'};
379 G4int size=8*sizeof(G4int)*fNPerSlice;
380 G4SurfBits bits(size);
381
382 for (G4int j = 0; j <= 2; ++j)
383 {
384 G4cout << " * " << axis[j] << " axis:" << endl;
385 G4int count = fBoundaries[j].size();
386 for(G4int i=0; i < count-1; ++i)
387 {
388 G4cout << " Slice #" << i+1 << ": [" << fBoundaries[j][i]
389 << " ; " << fBoundaries[j][i+1] << "] -> ";
390 bits.set(size,(const char *)fBitmasks[j].fAllBits+i
391 *fNPerSlice*sizeof(G4int));
392 G4String result = GetCandidatesAsString(bits);
393 G4cout << "[ " << result.c_str() << "] " << endl;
394 }
395 }
396}
397
398//______________________________________________________________________________
399void G4SurfaceVoxelizer::BuildBoundingBox()
400{
401 G4ThreeVector toleranceVector;
402 toleranceVector.set(fTolerance/100,fTolerance/100,fTolerance/100);
403 for (G4int i = 0; i <= 2; ++i)
404 {
405 G4double min = fBoundaries[i].front();
406 G4double max = fBoundaries[i].back();
407 fBoundingBoxSize[i] = (max-min)/2;
408 fBoundingBoxCenter[i] = min + fBoundingBoxSize[i];
409 }
410 // sizes -= toleranceVector;
411 fBoundingBox = G4Box("TessBBox", fBoundingBoxSize.x(),
412 fBoundingBoxSize.y(), fBoundingBoxSize.z());
413}
414
415// algorithm -
416
417// in order to get balanced voxels, merge should always unite those regions,
418// where the number of voxels is least the number.
419// We will keep sorted list (std::set) with all voxels. there will be
420// comparator function between two voxels, which will tell if voxel is less
421// by looking at his right neighbor.
422// First, we will add all the voxels into the tree.
423// We will be pick the first item in the tree, merging it, adding the right
424// merged voxel into the a list for future reduction (fBitmasks will be
425// rebuilded later, therefore they need not to be updated).
426// The merged voxel need to be added to the tree again, so it's position
427// would be updated.
428
429//______________________________________________________________________________
430void G4SurfaceVoxelizer::SetReductionRatio(G4int maxVoxels,
431 G4ThreeVector &reductionRatio)
432{
433 G4double maxTotal = (G4double) fCandidatesCounts[0].size()
434 * fCandidatesCounts[1].size() * fCandidatesCounts[2].size();
435
436 if (maxVoxels > 0 && maxVoxels < maxTotal)
437 {
438 G4double ratio = (G4double) maxVoxels / maxTotal;
439 ratio = pow(ratio, 1./3.);
440 if (ratio > 1) { ratio = 1; }
441 reductionRatio.set(ratio,ratio,ratio);
442 }
443}
444
445//______________________________________________________________________________
446void G4SurfaceVoxelizer::BuildReduceVoxels(std::vector<G4double> boundaries[],
447 G4ThreeVector reductionRatio)
448{
449 for (G4int k = 0; k <= 2; ++k)
450 {
451 vector<G4int> &candidatesCount = fCandidatesCounts[k];
452 G4int max = candidatesCount.size();
453 vector<G4VoxelInfo> voxels(max);
454 G4VoxelComparator comp(voxels);
455 set<G4int, G4VoxelComparator> voxelSet(comp);
456 vector<G4int> mergings;
457
458 for (G4int j = 0; j < max; ++j)
459 {
460 G4VoxelInfo &voxel = voxels[j];
461 voxel.count = candidatesCount[j];
462 voxel.previous = j - 1;
463 voxel.next = j + 1;
464 voxels[j] = voxel;
465 }
466
467 for (G4int j = 0; j < max - 1; ++j) { voxelSet.insert(j); }
468 // we go to size-1 to make sure we will not merge the last element
469
470 G4int count = 0;
471 while (true)
472 {
473 G4double reduction = reductionRatio[k];
474 if (reduction == 0)
475 break;
476 G4int currentCount = voxelSet.size();
477 if (currentCount <= 2)
478 break;
479 G4double currentRatio = 1 - (G4double) count / max;
480 if (currentRatio <= reduction && currentCount <= 1000)
481 break;
482 const G4int pos = *voxelSet.begin();
483 mergings.push_back(pos);
484
485 G4VoxelInfo &voxel = voxels[pos];
486 G4VoxelInfo &nextVoxel = voxels[voxel.next];
487
488 voxelSet.erase(pos);
489 if (voxel.next != max - 1) { voxelSet.erase(voxel.next); }
490 if (voxel.previous != -1) { voxelSet.erase(voxel.previous); }
491
492 nextVoxel.count += voxel.count;
493 voxel.count = 0;
494 nextVoxel.previous = voxel.previous;
495
496 if (voxel.next != max - 1)
497 voxelSet.insert(voxel.next);
498
499 if (voxel.previous != -1)
500 {
501 voxels[voxel.previous].next = voxel.next;
502 voxelSet.insert(voxel.previous);
503 }
504 count++;
505 }
506
507 if (mergings.size())
508 {
509 sort(mergings.begin(), mergings.end());
510
511 vector<G4double> &boundary = boundaries[k];
512 vector<G4double> reducedBoundary(boundary.size() - mergings.size());
513 G4int skip = mergings[0] + 1, cur = 0, i = 0;
514 max = boundary.size();
515 for (G4int j = 0; j < max; ++j)
516 {
517 if (j != skip)
518 {
519 reducedBoundary[cur++] = boundary[j];
520 }
521 else
522 {
523 if (++i < (G4int)mergings.size()) { skip = mergings[i] + 1; }
524 }
525 }
526 boundaries[k] = reducedBoundary;
527 }
528 }
529}
530
531//______________________________________________________________________________
532void G4SurfaceVoxelizer::BuildReduceVoxels2(std::vector<G4double> boundaries[],
533 G4ThreeVector reductionRatio)
534{
535 for (G4int k = 0; k <= 2; ++k)
536 {
537 vector<G4int> &candidatesCount = fCandidatesCounts[k];
538 G4int max = candidatesCount.size();
539 G4int total = 0;
540 for (G4int i = 0; i < max; i++) total += candidatesCount[i];
541
542 G4double reduction = reductionRatio[k];
543 if (reduction == 0)
544 break;
545
546 G4int destination = (G4int) (reduction * max) + 1;
547 if (destination > 1000) destination = 1000;
548 if (destination < 2) destination = 2;
549 G4double average = ((G4double)total / max) / reduction;
550
551 vector<G4int> mergings;
552
553 vector<G4double> &boundary = boundaries[k];
554 vector<G4double> reducedBoundary(destination);
555
556 G4int sum = 0, cur = 0;
557 for (G4int i = 0; i < max; i++)
558 {
559 sum += candidatesCount[i];
560 if (sum > average * (cur + 1) || i == 0)
561 {
562 G4double val = boundary[i];
563 reducedBoundary[cur] = val;
564 cur++;
565 if (cur == destination)
566 break;
567 }
568 }
569 reducedBoundary[destination-1] = boundary[max];
570 boundaries[k] = reducedBoundary;
571 }
572}
573
574//______________________________________________________________________________
575void G4SurfaceVoxelizer::CreateMiniVoxels(std::vector<G4double> boundaries[],
576 G4SurfBits bitmasks[])
577{
578 vector<G4int> voxel(3), maxVoxels(3);
579 for (G4int i = 0; i <= 2; ++i) maxVoxels[i] = boundaries[i].size();
580
581 G4ThreeVector point;
582 for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
583 {
584 for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
585 {
586 for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
587 {
588 vector<G4int> candidates;
589 if (GetCandidatesVoxelArray(voxel, bitmasks, candidates, 0))
590 {
591 // find a box for corresponding non-empty voxel
592 G4VoxelBox box;
593 for (G4int i = 0; i <= 2; ++i)
594 {
595 G4int index = voxel[i];
596 const vector<G4double> &boundary = boundaries[i];
597 G4double hlen = 0.5 * (boundary[index+1] - boundary[index]);
598 box.hlen[i] = hlen;
599 box.pos[i] = boundary[index] + hlen;
600 }
601 fVoxelBoxes.push_back(box);
602 vector<G4int>(candidates).swap(candidates);
603 fVoxelBoxesCandidates.push_back(candidates);
604 }
605 }
606 }
607 }
608}
609
610//______________________________________________________________________________
611void G4SurfaceVoxelizer::Voxelize(std::vector<G4VFacet *> &facets)
612{
613 G4int maxVoxels = fMaxVoxels;
614 G4ThreeVector reductionRatio = fReductionRatio;
615
616 G4int size = facets.size();
617 if (size < 10)
618 {
619 for (G4int i = 0; i < (G4int) facets.size(); i++)
620 {
621 if (facets[i]->GetNumberOfVertices() > 3) size++;
622 }
623 }
624
625 if ((size >= 10 || maxVoxels > 0) && maxVoxels != 0 && maxVoxels != 1)
626 {
627 BuildVoxelLimits(facets);
628
629 BuildBoundaries();
630
631 BuildBitmasks(fBoundaries, 0, true);
632
633 if (maxVoxels < 0 && reductionRatio == G4ThreeVector())
634 {
635 maxVoxels = fTotalCandidates;
636 if (fTotalCandidates > 1000000) maxVoxels = 1000000;
637 }
638
639 SetReductionRatio(maxVoxels, reductionRatio);
640
641 fCountOfVoxels = CountVoxels(fBoundaries);
642
643#ifdef G4SPECSDEBUG
644 G4cout << "Total number of voxels: " << fCountOfVoxels << endl;
645#endif
646
647 BuildReduceVoxels2(fBoundaries, reductionRatio);
648
649 fCountOfVoxels = CountVoxels(fBoundaries);
650
651#ifdef G4SPECSDEBUG
652 G4cout << "Total number of voxels after reduction: "
653 << fCountOfVoxels << endl;
654#endif
655
656 BuildBitmasks(fBoundaries, fBitmasks);
657
658 G4ThreeVector reductionRatioMini;
659
660 G4SurfBits bitmasksMini[3];
661
662 // section for building mini voxels
663
664 vector<G4double> miniBoundaries[3];
665
666 for (G4int i = 0; i <= 2; ++i) { miniBoundaries[i] = fBoundaries[i]; }
667
668 G4int voxelsCountMini = (fCountOfVoxels >= 1000)
669 ? 100 : fCountOfVoxels / 10;
670
671 // if (voxelCountMini < 8) voxelCountMini = 8;
672 // voxelsCountMini = 1;
673
674 SetReductionRatio(voxelsCountMini, reductionRatioMini);
675
676 BuildReduceVoxels(miniBoundaries, reductionRatioMini);
677
678#ifdef G4SPECSDEBUG
679 G4int total = CountVoxels(miniBoundaries);
680 G4cout << "Total number of mini voxels: " << total << endl;
681#endif
682
683 BuildBitmasks(miniBoundaries, bitmasksMini);
684
685 CreateMiniVoxels(miniBoundaries, bitmasksMini);
686
687 BuildBoundingBox();
688
689 BuildEmpty();
690
691 // deallocate fields unnecessary during runtime
692 //
693 fBoxes.resize(0);
694 for (G4int i = 0; i < 3; i++)
695 {
696 fCandidatesCounts[i].resize(0);
697 fBitmasks[i].Clear();
698 }
699 }
700}
701
702
703//______________________________________________________________________________
704void G4SurfaceVoxelizer::GetCandidatesVoxel(std::vector<G4int> &voxels)
705{
706 // "GetCandidates" should compute which solids are possibly contained in
707 // the voxel defined by the three slices characterized by the passed indexes.
708
709 G4cout << " Candidates in voxel [" << voxels[0] << " ; " << voxels[1]
710 << " ; " << voxels[2] << "]: ";
711 vector<G4int> candidates;
712 G4int count = GetCandidatesVoxelArray(voxels, candidates);
713 G4cout << "[ ";
714 for (G4int i = 0; i < count; ++i) G4cout << candidates[i];
715 G4cout << "] " << endl;
716}
717
718//______________________________________________________________________________
719void G4SurfaceVoxelizer::FindComponentsFastest(unsigned int mask,
720 std::vector<G4int> &list, G4int i)
721{
722 for (G4int byte = 0; byte < (G4int) (sizeof(unsigned int)); byte++)
723 {
724 if (G4int maskByte = mask & 0xFF)
725 {
726 for (G4int bit = 0; bit < 8; bit++)
727 {
728 if (maskByte & 1)
729 { list.push_back(8*(sizeof(unsigned int)*i+ byte) + bit); }
730 if (!(maskByte >>= 1)) break;
731 }
732 }
733 mask >>= 8;
734 }
735}
736
737//______________________________________________________________________________
739 std::vector<G4int> &list, G4SurfBits *crossed) const
740{
741 // Method returning the candidates corresponding to the passed point
742
743 list.clear();
744
745 for (G4int i = 0; i <= 2; ++i)
746 {
747 if(point[i] < fBoundaries[i].front() || point[i] >= fBoundaries[i].back())
748 return 0;
749 }
750
751 if (fTotalCandidates == 1)
752 {
753 list.push_back(0);
754 return 1;
755 }
756 else
757 {
758 if (fNPerSlice == 1)
759 {
760 unsigned int mask;
761 G4int slice = BinarySearch(fBoundaries[0], point.x());
762 if (!(mask = ((unsigned int *) fBitmasks[0].fAllBits)[slice]
763 )) return 0;
764 slice = BinarySearch(fBoundaries[1], point.y());
765 if (!(mask &= ((unsigned int *) fBitmasks[1].fAllBits)[slice]
766 )) return 0;
767 slice = BinarySearch(fBoundaries[2], point.z());
768 if (!(mask &= ((unsigned int *) fBitmasks[2].fAllBits)[slice]
769 )) return 0;
770 if (crossed && (!(mask &= ~((unsigned int *)crossed->fAllBits)[0])))
771 return 0;
772
773 FindComponentsFastest(mask, list, 0);
774 }
775 else
776 {
777 unsigned int *masks[3], mask; // masks for X,Y,Z axis
778 for (G4int i = 0; i <= 2; ++i)
779 {
780 G4int slice = BinarySearch(fBoundaries[i], point[i]);
781 masks[i] = ((unsigned int *) fBitmasks[i].fAllBits) + slice*fNPerSlice;
782 }
783 unsigned int *maskCrossed =
784 crossed ? (unsigned int *)crossed->fAllBits : 0;
785
786 for (G4int i = 0 ; i < fNPerSlice; ++i)
787 {
788 // Logic "and" of the masks along the 3 axes x, y, z:
789 // removing "if (!" and ") continue" => slightly slower
790 //
791 if (!(mask = masks[0][i])) continue;
792 if (!(mask &= masks[1][i])) continue;
793 if (!(mask &= masks[2][i])) continue;
794 if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
795
796 FindComponentsFastest(mask, list, i);
797 }
798 }
799 }
800 return list.size();
801}
802
803//______________________________________________________________________________
804G4int
805G4SurfaceVoxelizer::GetCandidatesVoxelArray(const std::vector<G4int> &voxels,
806 const G4SurfBits bitmasks[],
807 std::vector<G4int> &list,
808 G4SurfBits *crossed) const
809{
810 list.clear();
811
812 if (fTotalCandidates == 1)
813 {
814 list.push_back(0);
815 return 1;
816 }
817 else
818 {
819 if (fNPerSlice == 1)
820 {
821 unsigned int mask;
822 if (!(mask = ((unsigned int *) bitmasks[0].fAllBits)[voxels[0]]
823 )) return 0;
824 if (!(mask &= ((unsigned int *) bitmasks[1].fAllBits)[voxels[1]]
825 )) return 0;
826 if (!(mask &= ((unsigned int *) bitmasks[2].fAllBits)[voxels[2]]
827 )) return 0;
828 if (crossed && (!(mask &= ~((unsigned int *)crossed->fAllBits)[0])))
829 return 0;
830
831 FindComponentsFastest(mask, list, 0);
832 }
833 else
834 {
835 unsigned int *masks[3], mask; // masks for X,Y,Z axis
836 for (G4int i = 0; i <= 2; ++i)
837 {
838 masks[i] = ((unsigned int *) bitmasks[i].fAllBits)
839 + voxels[i]*fNPerSlice;
840 }
841 unsigned int *maskCrossed =
842 crossed ? (unsigned int *)crossed->fAllBits : 0;
843
844 for (G4int i = 0 ; i < fNPerSlice; ++i)
845 {
846 // Logic "and" of the masks along the 3 axes x, y, z:
847 // removing "if (!" and ") continue" => slightly slower
848 //
849 if (!(mask = masks[0][i])) continue;
850 if (!(mask &= masks[1][i])) continue;
851 if (!(mask &= masks[2][i])) continue;
852 if (maskCrossed && !(mask &= ~maskCrossed[i])) continue;
853
854 FindComponentsFastest(mask, list, i);
855 }
856 }
857 }
858 return list.size();
859}
860
861//______________________________________________________________________________
862G4int
863G4SurfaceVoxelizer::GetCandidatesVoxelArray(const std::vector<G4int> &voxels,
864 std::vector<G4int> &list, G4SurfBits *crossed) const
865{
866 // Method returning the candidates corresponding to the passed point
867
868 return GetCandidatesVoxelArray(voxels, fBitmasks, list, crossed);
869}
870
871//______________________________________________________________________________
873{
874 for (G4int i = 0; i < 3; ++i)
875 {
876 if (point[i] < fBoundaries[i].front() || point[i] > fBoundaries[i].back())
877 return false;
878 }
879 return true;
880}
881
882//______________________________________________________________________________
885 const G4ThreeVector &direction) const
886{
887 G4ThreeVector pointShifted = point - fBoundingBoxCenter;
888 G4double shift = fBoundingBox.DistanceToIn(pointShifted, direction);
889 return shift;
890}
891
892//______________________________________________________________________________
895{
896 G4ThreeVector pointShifted = point - fBoundingBoxCenter;
897 G4double shift = MinDistanceToBox(pointShifted, fBoundingBoxSize);
898 return shift;
899}
900
901//______________________________________________________________________________
904 const G4ThreeVector &f)
905{
906 // Estimates the isotropic safety from a point outside the current solid to
907 // any of its surfaces. The algorithm may be accurate or should provide a
908 // fast underestimate.
909
910 G4double safe, safx, safy, safz;
911 safe = safx = -f.x() + std::abs(aPoint.x());
912 safy = -f.y() + std::abs(aPoint.y());
913 if ( safy > safe ) safe = safy;
914 safz = -f.z() + std::abs(aPoint.z());
915 if ( safz > safe ) safe = safz;
916 if (safe < 0.0) return 0.0; // point is inside
917 // if (!aAccurate) return safe;
918 G4double safsq = 0.0;
919 G4int count = 0;
920 if ( safx > 0 ) { safsq += safx*safx; count++; }
921 if ( safy > 0 ) { safsq += safy*safy; count++; }
922 if ( safz > 0 ) { safsq += safz*safz; count++; }
923 if (count == 1) return safe;
924 return std::sqrt(safsq);
925}
926
927//______________________________________________________________________________
930 const G4ThreeVector &direction,
931 const std::vector<G4int> &curVoxel) const
932{
933 G4double shift = kInfinity;
934
935 for (G4int i = 0; i <= 2; ++i)
936 {
937 // Looking for the next voxels on the considered direction X,Y,Z axis
938 //
939 const vector<G4double> &boundary = fBoundaries[i];
940 G4int cur = curVoxel[i];
941 if(direction[i] >= 1e-10)
942 {
943 if (boundary[cur] - point[i] < fTolerance) // make sure shift would
944 if (++cur >= (G4int) boundary.size()) // be non-zero
945 continue;
946 }
947 else
948 {
949 if(direction[i] <= -1e-10)
950 {
951 if (point[i] - boundary[cur] < fTolerance) // make sure shift would
952 if (--cur < 0) // be non-zero
953 continue;
954 }
955 else
956 continue;
957 }
958 G4double dif = boundary[cur] - point[i];
959 G4double distance = dif / direction[i];
960
961 if (shift > distance)
962 shift = distance;
963 }
964
965 return shift;
966}
967
968//______________________________________________________________________________
969G4bool
971 const G4ThreeVector &direction,
972 std::vector<G4int> &curVoxel) const
973{
974 for (G4int i = 0; i <= 2; ++i)
975 {
976 G4int index = curVoxel[i];
977 const vector<G4double> &boundary = fBoundaries[i];
978
979 if (direction[i] > 0)
980 {
981 if (point[i] >= boundary[++index])
982 if (++curVoxel[i] >= (G4int) boundary.size() - 1)
983 return false;
984 }
985 else
986 {
987 if (point[i] < boundary[index])
988 if (--curVoxel[i] < 0)
989 return false;
990 }
991#ifdef G4SPECSDEBUG
992 G4int indexOK = BinarySearch(boundary, point[i]);
993 if (curVoxel[i] != indexOK)
994 curVoxel[i] = indexOK; // put breakpoint here
995#endif
996 }
997 return true;
998}
999
1000//______________________________________________________________________________
1002{
1003 fMaxVoxels = max;
1004 fReductionRatio.set(0,0,0);
1005}
1006
1007//______________________________________________________________________________
1009{
1010 fMaxVoxels = -1;
1011 fReductionRatio = ratioOfReduction;
1012}
1013
1014//______________________________________________________________________________
1016{
1017 G4int res = fDefaultVoxelsCount;
1018 fDefaultVoxelsCount = count;
1019 return res;
1020}
1021
1022//______________________________________________________________________________
1024{
1025 return fDefaultVoxelsCount;
1026}
1027
1028//______________________________________________________________________________
1030{
1031 G4int size = fEmpty.GetNbytes();
1032 size += fBoxes.capacity() * sizeof(G4VoxelBox);
1033 size += sizeof(G4double) * (fBoundaries[0].capacity()
1034 + fBoundaries[1].capacity() + fBoundaries[2].capacity());
1035 size += sizeof(G4int) * (fCandidatesCounts[0].capacity()
1036 + fCandidatesCounts[1].capacity() + fCandidatesCounts[2].capacity());
1037 size += fBitmasks[0].GetNbytes() + fBitmasks[1].GetNbytes()
1038 + fBitmasks[2].GetNbytes();
1039
1040 G4int csize = fCandidates.size();
1041 for (G4int i = 0; i < csize; i++)
1042 {
1043 size += sizeof(vector<G4int>) + fCandidates[i].capacity() * sizeof(G4int);
1044 }
1045
1046 return size;
1047}
1048
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
G4DLLIMPORT std::ostream G4cout
double z() const
double x() const
double y() const
void set(double x, double y, double z)
Definition: G4Box.hh:55
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Definition: G4Box.cc:556
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
static void DeRegister(G4VSolid *pSolid)
static G4SolidStore * GetInstance()
unsigned int GetNbytes() const
Definition: G4SurfBits.hh:102
unsigned char * fAllBits
Definition: G4SurfBits.hh:113
void ResetAllBits(G4bool value=false)
Definition: G4SurfBits.cc:154
void Clear()
Definition: G4SurfBits.cc:92
void ResetBitNumber(unsigned int bitnumber)
Definition: G4SurfBits.hh:161
void SetBitNumber(unsigned int bitnumber, G4bool value=true)
Definition: G4SurfBits.hh:123
void set(unsigned int nbits, const char *array)
Definition: G4SurfBits.cc:174
G4bool TestBitNumber(unsigned int bitnumber) const
Definition: G4SurfBits.hh:148
G4bool Contains(const G4ThreeVector &point) const
G4bool UpdateCurrentVoxel(const G4ThreeVector &point, const G4ThreeVector &direction, std::vector< G4int > &curVoxel) const
G4double DistanceToBoundingBox(const G4ThreeVector &point) const
void SetMaxVoxels(G4int max)
G4double DistanceToNext(const G4ThreeVector &point, const G4ThreeVector &direction, const std::vector< G4int > &curVoxel) const
G4int GetCandidatesVoxelArray(const G4ThreeVector &point, std::vector< G4int > &list, G4SurfBits *crossed=0) const
G4int GetVoxelsIndex(G4int x, G4int y, G4int z) const
static G4double MinDistanceToBox(const G4ThreeVector &aPoint, const G4ThreeVector &f)
G4double DistanceToFirst(const G4ThreeVector &point, const G4ThreeVector &direction) const
static G4int SetDefaultVoxelsCount(G4int count)
void Voxelize(std::vector< G4VFacet * > &facets)
G4int GetBitsPerSlice() const
long long CountVoxels(std::vector< G4double > boundaries[]) const
static G4int BinarySearch(const std::vector< T > &vec, T value)
void GetCandidatesVoxel(std::vector< G4int > &voxels)
static G4int GetDefaultVoxelsCount()
virtual G4double Extent(const G4ThreeVector)=0
G4ThreeVector hlen
G4ThreeVector pos