Geant4-11
G4MultiUnion.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// Implementation of G4MultiUnion class
27//
28// 19.10.12 M.Gayer - Original implementation from USolids module
29// 06.04.17 G.Cosmo - Adapted implementation in Geant4 for VecGeom migration
30// --------------------------------------------------------------------
31
32#include <iostream>
33#include <sstream>
34
35#include "G4MultiUnion.hh"
36#include "Randomize.hh"
38#include "G4BoundingEnvelope.hh"
39#include "G4AffineTransform.hh"
40#include "G4DisplacedSolid.hh"
41
42#include "G4VGraphicsScene.hh"
43#include "G4Polyhedron.hh"
45
46#include "G4AutoLock.hh"
47
48namespace
49{
51}
52
53//______________________________________________________________________________
55 : G4VSolid(name)
56{
58 fSolids.clear();
59 fTransformObjs.clear();
61}
62
63//______________________________________________________________________________
65{
66}
67
68//______________________________________________________________________________
70{
71 fSolids.push_back(&solid);
72 fTransformObjs.push_back(trans); // Store a local copy of transformations
73}
74
75//______________________________________________________________________________
77{
78 fSolids.push_back(solid);
79 fTransformObjs.push_back(trans); // Store a local copy of transformations
80}
81
82//______________________________________________________________________________
84{
85 return new G4MultiUnion(*this);
86}
87
88// Copy constructor
89//______________________________________________________________________________
91 : G4VSolid(rhs), fCubicVolume(rhs.fCubicVolume),
92 fSurfaceArea(rhs.fSurfaceArea),
93 kRadTolerance(rhs.kRadTolerance), fAccurate(rhs.fAccurate)
94{
95}
96
97// Fake default constructor for persistency
98//______________________________________________________________________________
100 : G4VSolid(a)
101{
102}
103
104// Assignment operator
105//______________________________________________________________________________
107{
108 // Check assignment to self
109 //
110 if (this == &rhs)
111 {
112 return *this;
113 }
114
115 // Copy base class data
116 //
118
119 return *this;
120}
121
122//______________________________________________________________________________
124{
125 // Computes the cubic volume of the "G4MultiUnion" structure using
126 // random points
127
128 if (!fCubicVolume)
129 {
130 G4ThreeVector extentMin, extentMax, d, p, point;
131 G4int inside = 0, generated;
132 BoundingLimits(extentMin, extentMax);
133 d = (extentMax - extentMin) / 2.;
134 p = (extentMax + extentMin) / 2.;
135 G4ThreeVector left = p - d;
136 G4ThreeVector length = d * 2;
137 for (generated = 0; generated < 10000; ++generated)
138 {
140 point = left + G4ThreeVector(length.x()*rvec.x(),
141 length.y()*rvec.y(),
142 length.z()*rvec.z());
143 if (Inside(point) != EInside::kOutside) ++inside;
144 }
145 G4double vbox = (2 * d.x()) * (2 * d.y()) * (2 * d.z());
146 fCubicVolume = inside * vbox / generated;
147 }
148 return fCubicVolume;
149}
150
151//______________________________________________________________________________
154 const G4ThreeVector& aDirection) const
155{
156 G4ThreeVector direction = aDirection.unit();
157 G4ThreeVector localPoint, localDirection;
158 G4double minDistance = kInfinity;
159
160 G4int numNodes = fSolids.size();
161 for (G4int i = 0 ; i < numNodes ; ++i)
162 {
163 G4VSolid& solid = *fSolids[i];
165
166 localPoint = GetLocalPoint(transform, aPoint);
167 localDirection = GetLocalVector(transform, direction);
168
169 G4double distance = solid.DistanceToIn(localPoint, localDirection);
170 if (minDistance > distance) minDistance = distance;
171 }
172 return minDistance;
173}
174
175//______________________________________________________________________________
177 const G4ThreeVector& direction,
178 std::vector<G4int>& candidates,
179 G4SurfBits& bits) const
180{
181 G4int candidatesCount = candidates.size();
182 G4ThreeVector localPoint, localDirection;
183
184 G4double minDistance = kInfinity;
185 for (G4int i = 0 ; i < candidatesCount; ++i)
186 {
187 G4int candidate = candidates[i];
188 G4VSolid& solid = *fSolids[candidate];
189 const G4Transform3D& transform = fTransformObjs[candidate];
190
191 localPoint = GetLocalPoint(transform, aPoint);
192 localDirection = GetLocalVector(transform, direction);
193 G4double distance = solid.DistanceToIn(localPoint, localDirection);
194 if (minDistance > distance) minDistance = distance;
195 bits.SetBitNumber(candidate);
196 if (minDistance == 0) break;
197 }
198 return minDistance;
199}
200
201// Algorithm note: we have to look also for all other objects in next voxels,
202// if the distance is not shorter ... we have to do it because,
203// for example for objects which starts in first voxel in which they
204// do not collide with direction line, but in second it collides...
205// The idea of crossing voxels would be still applicable,
206// because this way we could exclude from the testing such solids,
207// which were found that obviously are not good candidates, because
208// they would return infinity
209// But if distance is smaller than the shift to next voxel, we can return
210// it immediately
211//______________________________________________________________________________
213 const G4ThreeVector& aDirection) const
214{
215 G4double minDistance = kInfinity;
216 G4ThreeVector direction = aDirection.unit();
217 G4double shift = fVoxels.DistanceToFirst(aPoint, direction);
218 if (shift == kInfinity) return shift;
219
220 G4ThreeVector currentPoint = aPoint;
221 if (shift) currentPoint += direction * shift;
222
224 std::vector<G4int> candidates, curVoxel(3);
225 fVoxels.GetVoxel(curVoxel, currentPoint);
226
227 do
228 {
229 {
230 if (fVoxels.GetCandidatesVoxelArray(curVoxel, candidates, &exclusion))
231 {
232 G4double distance = DistanceToInCandidates(aPoint, direction,
233 candidates, exclusion);
234 if (minDistance > distance) minDistance = distance;
235 if (distance < shift) break;
236 }
237 }
238 shift = fVoxels.DistanceToNext(aPoint, direction, curVoxel);
239 }
240 while (minDistance > shift);
241
242 return minDistance;
243}
244
245//______________________________________________________________________________
247 const G4ThreeVector& aDirection,
248 G4ThreeVector* aNormal) const
249{
250 // Computes distance from a point presumably outside the solid to the solid
251 // surface. Ignores first surface if the point is actually inside.
252 // Early return infinity in case the safety to any surface is found greater
253 // than the proposed step aPstep.
254 // The normal vector to the crossed surface is filled only in case the box
255 // is crossed, otherwise aNormal->IsNull() is true.
256
257 // algorithm:
258 G4ThreeVector direction = aDirection.unit();
259 G4ThreeVector localPoint, localDirection;
260 G4int ignoredSolid = -1;
261 G4double resultDistToOut = 0;
262 G4ThreeVector currentPoint = aPoint;
263
264 G4int numNodes = fSolids.size();
265 for (G4int i = 0; i < numNodes; ++i)
266 {
267 if (i != ignoredSolid)
268 {
269 G4VSolid& solid = *fSolids[i];
271 localPoint = GetLocalPoint(transform, currentPoint);
272 localDirection = GetLocalVector(transform, direction);
273 EInside location = solid.Inside(localPoint);
274 if (location != EInside::kOutside)
275 {
276 G4double distance = solid.DistanceToOut(localPoint, localDirection,
277 aNormal);
278 if (distance < kInfinity)
279 {
280 if (resultDistToOut == kInfinity) resultDistToOut = 0;
281 if (distance > 0)
282 {
283 currentPoint = GetGlobalPoint(transform, localPoint
284 + distance*localDirection);
285 resultDistToOut += distance;
286 ignoredSolid = i; // skip the solid which we have just left
287 i = -1; // force the loop to continue from 0
288 }
289 }
290 }
291 }
292 }
293 return resultDistToOut;
294}
295
296//______________________________________________________________________________
298 const G4ThreeVector& aDirection,
299 const G4bool /* calcNorm */,
300 G4bool* /* validNorm */,
301 G4ThreeVector* aNormal) const
302{
303 return DistanceToOutVoxels(aPoint, aDirection, aNormal);
304}
305
306//______________________________________________________________________________
308 const G4ThreeVector& aDirection,
309 G4ThreeVector* aNormal) const
310{
311 // Computes distance from a point presumably inside the solid to the solid
312 // surface. Ignores first surface along each axis systematically (for points
313 // inside or outside. Early returns zero in case the second surface is behind
314 // the starting point.
315 // o The proposed step is ignored.
316 // o The normal vector to the crossed surface is always filled.
317
318 // In the case the considered point is located inside the G4MultiUnion
319 // structure, the treatments are as follows:
320 // - investigation of the candidates for the passed point
321 // - progressive moving of the point towards the surface, along the
322 // passed direction
323 // - processing of the normal
324
325 G4ThreeVector direction = aDirection.unit();
326 std::vector<G4int> candidates;
327 G4double distance = 0;
328 G4int numNodes = 2*fSolids.size();
329 G4int count=0;
330
331 if (fVoxels.GetCandidatesVoxelArray(aPoint, candidates))
332 {
333 // For normal case for which we presume the point is inside
334 G4ThreeVector localPoint, localDirection, localNormal;
335 G4ThreeVector currentPoint = aPoint;
337 G4bool notOutside;
338 G4ThreeVector maxNormal;
339
340 do
341 {
342 notOutside = false;
343
344 G4double maxDistance = -kInfinity;
345 G4int maxCandidate = 0;
346 G4ThreeVector maxLocalPoint;
347
348 G4int limit = candidates.size();
349 for (G4int i = 0 ; i < limit ; ++i)
350 {
351 G4int candidate = candidates[i];
352 // ignore the current component (that you just got out of) since
353 // numerically the propagated point will be on its surface
354
355 G4VSolid& solid = *fSolids[candidate];
356 const G4Transform3D& transform = fTransformObjs[candidate];
357
358 // The coordinates of the point are modified so as to fit the
359 // intrinsic solid local frame:
360 localPoint = GetLocalPoint(transform, currentPoint);
361
362 // DistanceToOut at least for Trd sometimes return non-zero value
363 // even from points that are outside. Therefore, this condition
364 // must currently be here, otherwise it would not work.
365 // But it means it would be slower.
366
367 if (solid.Inside(localPoint) != EInside::kOutside)
368 {
369 notOutside = true;
370
371 localDirection = GetLocalVector(transform, direction);
372
373 // propagate with solid.DistanceToOut
374 G4double shift = solid.DistanceToOut(localPoint, localDirection,
375 false, 0, &localNormal);
376 if (maxDistance < shift)
377 {
378 maxDistance = shift;
379 maxCandidate = candidate;
380 maxNormal = localNormal;
381 }
382 }
383 }
384
385 if (notOutside)
386 {
387 const G4Transform3D& transform = fTransformObjs[maxCandidate];
388
389 // convert from local normal
390 if (aNormal) *aNormal = GetGlobalVector(transform, maxNormal);
391
392 distance += maxDistance;
393 currentPoint += maxDistance * direction;
394 if(maxDistance == 0.) ++count;
395
396 // the current component will be ignored
397 exclusion.SetBitNumber(maxCandidate);
398 EInside location = InsideWithExclusion(currentPoint, &exclusion);
399
400 // perform a Inside
401 // it should be excluded current solid from checking
402 // we have to collect the maximum distance from all given candidates.
403 // such "maximum" candidate should be then used for finding next
404 // candidates
405 if (location == EInside::kOutside)
406 {
407 // else return cumulated distances to outside of the traversed
408 // components
409 break;
410 }
411 // if inside another component, redo 1 to 3 but add the next
412 // DistanceToOut on top of the previous.
413
414 // and fill the candidates for the corresponding voxel (just
415 // exiting current component along direction)
416 candidates.clear();
417
418 fVoxels.GetCandidatesVoxelArray(currentPoint, candidates, &exclusion);
419 exclusion.ResetBitNumber(maxCandidate);
420 }
421 }
422 while ((notOutside) && (count < numNodes));
423 }
424
425 return distance;
426}
427
428//______________________________________________________________________________
430 G4SurfBits* exclusion) const
431{
432 // Classify point location with respect to solid:
433 // o eInside - inside the solid
434 // o eSurface - close to surface within tolerance
435 // o eOutside - outside the solid
436
437 // Hitherto, it is considered that only parallelepipedic nodes
438 // can be added to the container
439
440 // Implementation using voxelisation techniques:
441 // ---------------------------------------------
442
443 G4ThreeVector localPoint;
444 EInside location = EInside::kOutside;
445
446 std::vector<G4int> candidates;
447 std::vector<G4MultiUnionSurface> surfaces;
448
449 // TODO: test if it works well and if so measure performance
450 // TODO: getPointIndex should not be used, instead GetVoxel + GetVoxelsIndex
451 // should be used
452 // TODO: than pass result to GetVoxel further to GetCandidatesVoxelArray
453 // TODO: eventually GetVoxel should be inlined here, early exit if any
454 // binary search is -1
455
456 G4int limit = fVoxels.GetCandidatesVoxelArray(aPoint, candidates, exclusion);
457 for (G4int i = 0 ; i < limit ; ++i)
458 {
459 G4int candidate = candidates[i];
460 G4VSolid& solid = *fSolids[candidate];
461 const G4Transform3D& transform = fTransformObjs[candidate];
462
463 // The coordinates of the point are modified so as to fit the intrinsic
464 // solid local frame:
465 localPoint = GetLocalPoint(transform, aPoint);
466 location = solid.Inside(localPoint);
467 if (location == EInside::kInside) return EInside::kInside;
468 else if (location == EInside::kSurface)
469 {
470 G4MultiUnionSurface surface;
471 surface.point = localPoint;
472 surface.solid = &solid;
473 surfaces.push_back(surface);
474 }
475 }
476
478 // Important comment: When two solids touch each other along a flat
479 // surface, the surface points will be considered as kSurface, while points
480 // located around will correspond to kInside (cf. G4UnionSolid)
481
482 G4int size = surfaces.size();
483 for (G4int i = 0; i < size - 1; ++i)
484 {
485 G4MultiUnionSurface& left = surfaces[i];
486 for (G4int j = i + 1; j < size; ++j)
487 {
488 G4MultiUnionSurface& right = surfaces[j];
489 G4ThreeVector n, n2;
490 n = left.solid->SurfaceNormal(left.point);
491 n2 = right.solid->SurfaceNormal(right.point);
492 if ((n + n2).mag2() < 1000 * kRadTolerance)
493 return EInside::kInside;
494 }
495 }
496
497 location = size ? EInside::kSurface : EInside::kOutside;
498
499 return location;
500}
501
502//______________________________________________________________________________
504{
505 // Classify point location with respect to solid:
506 // o eInside - inside the solid
507 // o eSurface - close to surface within tolerance
508 // o eOutside - outside the solid
509
510 // Hitherto, it is considered that only parallelepipedic nodes can be
511 // added to the container
512
513 // Implementation using voxelisation techniques:
514 // ---------------------------------------------
515
516 // return InsideIterator(aPoint);
517
518 EInside location = InsideWithExclusion(aPoint);
519 return location;
520}
521
522//______________________________________________________________________________
524{
525 G4ThreeVector localPoint;
526 EInside location = EInside::kOutside;
527 G4int countSurface = 0;
528
529 G4int numNodes = fSolids.size();
530 for (G4int i = 0 ; i < numNodes ; ++i)
531 {
532 G4VSolid& solid = *fSolids[i];
534
535 // The coordinates of the point are modified so as to fit the
536 // intrinsic solid local frame:
537 localPoint = GetLocalPoint(transform, aPoint);
538
539 location = solid.Inside(localPoint);
540
541 if (location == EInside::kSurface)
542 ++countSurface;
543
544 if (location == EInside::kInside) return EInside::kInside;
545 }
546 if (countSurface != 0) return EInside::kSurface;
547 return EInside::kOutside;
548}
549
550//______________________________________________________________________________
551void G4MultiUnion::Extent(EAxis aAxis, G4double& aMin, G4double& aMax) const
552{
553 // Determines the bounding box for the considered instance of "UMultipleUnion"
555
556 G4int numNodes = fSolids.size();
557 for (G4int i = 0 ; i < numNodes ; ++i)
558 {
559 G4VSolid& solid = *fSolids[i];
561 solid.BoundingLimits(min, max);
562
564
565 if (i == 0)
566 {
567 switch (aAxis)
568 {
569 case kXAxis:
570 aMin = min.x();
571 aMax = max.x();
572 break;
573 case kYAxis:
574 aMin = min.y();
575 aMax = max.y();
576 break;
577 case kZAxis:
578 aMin = min.z();
579 aMax = max.z();
580 break;
581 default:
582 break;
583 }
584 }
585 else
586 {
587 // Determine the min/max on the considered axis:
588 switch (aAxis)
589 {
590 case kXAxis:
591 if (min.x() < aMin)
592 aMin = min.x();
593 if (max.x() > aMax)
594 aMax = max.x();
595 break;
596 case kYAxis:
597 if (min.y() < aMin)
598 aMin = min.y();
599 if (max.y() > aMax)
600 aMax = max.y();
601 break;
602 case kZAxis:
603 if (min.z() < aMin)
604 aMin = min.z();
605 if (max.z() > aMax)
606 aMax = max.z();
607 break;
608 default:
609 break;
610 }
611 }
612 }
613}
614
615//______________________________________________________________________________
617 G4ThreeVector& aMax) const
618{
619 Extent(kXAxis, aMin[0], aMax[0]);
620 Extent(kYAxis, aMin[1], aMax[1]);
621 Extent(kZAxis, aMin[2], aMax[2]);
622}
623
624//______________________________________________________________________________
625G4bool
627 const G4VoxelLimits& pVoxelLimit,
628 const G4AffineTransform& pTransform,
629 G4double& pMin, G4double& pMax) const
630{
631 G4ThreeVector bmin, bmax;
632
633 // Get bounding box
634 BoundingLimits(bmin,bmax);
635
636 // Find extent
637 G4BoundingEnvelope bbox(bmin,bmax);
638 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
639}
640
641//______________________________________________________________________________
643{
644 // Computes the localNormal on a surface and returns it as a unit vector.
645 // Must return a valid vector. (even if the point is not on the surface).
646 //
647 // On an edge or corner, provide an average localNormal of all facets within
648 // tolerance
649 // NOTE: the tolerance value used in here is not yet the global surface
650 // tolerance - we will have to revise this value - TODO
651
652 std::vector<G4int> candidates;
653 G4ThreeVector localPoint, normal, localNormal;
654 G4double safety = kInfinity;
655 G4int node = 0;
656
658 // Important comment: Cases for which the point is located on an edge or
659 // on a vertice remain to be treated
660
661 // determine weather we are in voxel area
662 if (fVoxels.GetCandidatesVoxelArray(aPoint, candidates))
663 {
664 G4int limit = candidates.size();
665 for (G4int i = 0 ; i < limit ; ++i)
666 {
667 G4int candidate = candidates[i];
668 const G4Transform3D& transform = fTransformObjs[candidate];
669
670 // The coordinates of the point are modified so as to fit the intrinsic
671 // solid local frame:
672 localPoint = GetLocalPoint(transform, aPoint);
673 G4VSolid& solid = *fSolids[candidate];
674 EInside location = solid.Inside(localPoint);
675
676 if (location == EInside::kSurface)
677 {
678 // normal case when point is on surface, we pick first solid
679 normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
680 return normal.unit();
681 }
682 else
683 {
684 // collect the smallest safety and remember solid node
685 G4double s = (location == EInside::kInside)
686 ? solid.DistanceToOut(localPoint)
687 : solid.DistanceToIn(localPoint);
688 if (s < safety)
689 {
690 safety = s;
691 node = candidate;
692 }
693 }
694 }
695 // on none of the solids, the point was not on the surface
696 G4VSolid& solid = *fSolids[node];
698 localPoint = GetLocalPoint(transform, aPoint);
699
700 normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
701 return normal.unit();
702 }
703 else
704 {
705 // for the case when point is certainly outside:
706
707 // find a solid in union with the smallest safety
708 node = SafetyFromOutsideNumberNode(aPoint, safety);
709 G4VSolid& solid = *fSolids[node];
710
712 localPoint = GetLocalPoint(transform, aPoint);
713
714 // evaluate normal for point at this found solid
715 // and transform multi-union coordinates
716 normal = GetGlobalVector(transform, solid.SurfaceNormal(localPoint));
717
718 return normal.unit();
719 }
720}
721
722//______________________________________________________________________________
724{
725 // Estimates isotropic distance to the surface of the solid. This must
726 // be either accurate or an underestimate.
727 // Two modes: - default/fast mode, sacrificing accuracy for speed
728 // - "precise" mode, requests accurate value if available.
729
730 std::vector<G4int> candidates;
731 G4ThreeVector localPoint;
732 G4double safetyMin = kInfinity;
733
734 // In general, the value return by DistanceToIn(p) will not be the exact
735 // but only an undervalue (cf. overlaps)
736 fVoxels.GetCandidatesVoxelArray(point, candidates);
737
738 G4int limit = candidates.size();
739 for (G4int i = 0; i < limit; ++i)
740 {
741 G4int candidate = candidates[i];
742
743 // The coordinates of the point are modified so as to fit the intrinsic
744 // solid local frame:
745 const G4Transform3D& transform = fTransformObjs[candidate];
746 localPoint = GetLocalPoint(transform, point);
747 G4VSolid& solid = *fSolids[candidate];
748 if (solid.Inside(localPoint) == EInside::kInside)
749 {
750 G4double safety = solid.DistanceToOut(localPoint);
751 if (safetyMin > safety) safetyMin = safety;
752 }
753 }
754 if (safetyMin == kInfinity) safetyMin = 0; // we are not inside
755
756 return safetyMin;
757}
758
759//______________________________________________________________________________
761{
762 // Estimates the isotropic safety from a point outside the current solid to
763 // any of its surfaces. The algorithm may be accurate or should provide a fast
764 // underestimate.
765
766 if (!fAccurate) { return fVoxels.DistanceToBoundingBox(point); }
767
768 const std::vector<G4VoxelBox>& boxes = fVoxels.GetBoxes();
769 G4double safetyMin = kInfinity;
770 G4ThreeVector localPoint;
771
772 G4int numNodes = fSolids.size();
773 for (G4int j = 0; j < numNodes; ++j)
774 {
775 G4ThreeVector dxyz;
776 if (j > 0)
777 {
778 const G4ThreeVector& pos = boxes[j].pos;
779 const G4ThreeVector& hlen = boxes[j].hlen;
780 for (auto i = 0; i <= 2; ++i)
781 // distance to middle point - hlength => distance from point to border
782 // of x,y,z
783 if ((dxyz[i] = std::abs(point[i] - pos[i]) - hlen[i]) > safetyMin)
784 continue;
785
786 G4double d2xyz = 0.;
787 for (auto i = 0; i <= 2; ++i)
788 if (dxyz[i] > 0) d2xyz += dxyz[i] * dxyz[i];
789
790 // minimal distance is at least this, but could be even higher. therefore,
791 // we can stop if previous was already lower, let us check if it does any
792 // chance to be better tha previous values...
793 if (d2xyz >= safetyMin * safetyMin)
794 {
795 continue;
796 }
797 }
799 localPoint = GetLocalPoint(transform, point);
800 G4VSolid& solid = *fSolids[j];
801
802 G4double safety = solid.DistanceToIn(localPoint);
803 if (safety <= 0) return safety;
804 // it was detected, that the point is not located outside
805 if (safetyMin > safety) safetyMin = safety;
806 }
807 return safetyMin;
808}
809
810//______________________________________________________________________________
812{
813 if (!fSurfaceArea)
814 {
815 fSurfaceArea = EstimateSurfaceArea(1000000, 0.001);
816 }
817 return fSurfaceArea;
818}
819
820//______________________________________________________________________________
822{
824}
825
826//______________________________________________________________________________
828 G4double& safetyMin) const
829{
830 // Method returning the closest node from a point located outside a
831 // G4MultiUnion.
832 // This is used to compute the normal in the case no candidate has been found.
833
834 const std::vector<G4VoxelBox>& boxes = fVoxels.GetBoxes();
835 safetyMin = kInfinity;
836 G4int safetyNode = 0;
837 G4ThreeVector localPoint;
838
839 G4int numNodes = fSolids.size();
840 for (G4int i = 0; i < numNodes; ++i)
841 {
842 G4double d2xyz = 0.;
843 G4double dxyz0 = std::abs(aPoint.x() - boxes[i].pos.x()) - boxes[i].hlen.x();
844 if (dxyz0 > safetyMin) continue;
845 G4double dxyz1 = std::abs(aPoint.y() - boxes[i].pos.y()) - boxes[i].hlen.y();
846 if (dxyz1 > safetyMin) continue;
847 G4double dxyz2 = std::abs(aPoint.z() - boxes[i].pos.z()) - boxes[i].hlen.z();
848 if (dxyz2 > safetyMin) continue;
849
850 if (dxyz0 > 0) d2xyz += dxyz0 * dxyz0;
851 if (dxyz1 > 0) d2xyz += dxyz1 * dxyz1;
852 if (dxyz2 > 0) d2xyz += dxyz2 * dxyz2;
853 if (d2xyz >= safetyMin * safetyMin) continue;
854
855 G4VSolid& solid = *fSolids[i];
857 localPoint = GetLocalPoint(transform, aPoint);
858 fAccurate = true;
859 G4double safety = solid.DistanceToIn(localPoint);
860 fAccurate = false;
861 if (safetyMin > safety)
862 {
863 safetyMin = safety;
864 safetyNode = i;
865 }
866 }
867 return safetyNode;
868}
869
870//______________________________________________________________________________
872 const G4Transform3D& transformation) const
873{
874 // The goal of this method is to convert the quantities min and max
875 // (representing the bounding box of a given solid in its local frame)
876 // to the main frame, using "transformation"
877
878 G4ThreeVector vertices[8] = // Detemination of the vertices thanks to
879 { // the extension of each solid:
880 G4ThreeVector(min.x(), min.y(), min.z()), // 1st vertice:
881 G4ThreeVector(min.x(), max.y(), min.z()), // 2nd vertice:
882 G4ThreeVector(max.x(), max.y(), min.z()),
883 G4ThreeVector(max.x(), min.y(), min.z()),
884 G4ThreeVector(min.x(), min.y(), max.z()),
885 G4ThreeVector(min.x(), max.y(), max.z()),
886 G4ThreeVector(max.x(), max.y(), max.z()),
887 G4ThreeVector(max.x(), min.y(), max.z())
888 };
889
892
893 // Loop on th vertices
894 G4int limit = sizeof(vertices) / sizeof(G4ThreeVector);
895 for (G4int i = 0 ; i < limit; ++i)
896 {
897 // From local frame to the global one:
898 // Current positions on the three axis:
899 G4ThreeVector current = GetGlobalPoint(transformation, vertices[i]);
900
901 // If need be, replacement of the min & max values:
902 if (current.x() > max.x()) max.setX(current.x());
903 if (current.x() < min.x()) min.setX(current.x());
904
905 if (current.y() > max.y()) max.setY(current.y());
906 if (current.y() < min.y()) min.setY(current.y());
907
908 if (current.z() > max.z()) max.setZ(current.z());
909 if (current.z() < min.z()) min.setZ(current.z());
910 }
911}
912
913// Stream object contents to an output stream
914//______________________________________________________________________________
915std::ostream& G4MultiUnion::StreamInfo(std::ostream& os) const
916{
917 G4int oldprc = os.precision(16);
918 os << "-----------------------------------------------------------\n"
919 << " *** Dump for solid - " << GetName() << " ***\n"
920 << " ===================================================\n"
921 << " Solid type: G4MultiUnion\n"
922 << " Parameters: \n";
923 G4int numNodes = fSolids.size();
924 for (G4int i = 0 ; i < numNodes ; ++i)
925 {
926 G4VSolid& solid = *fSolids[i];
927 solid.StreamInfo(os);
929 os << " Translation is " << transform.getTranslation() << " \n";
930 os << " Rotation is :" << " \n";
931 os << " " << transform.getRotation() << "\n";
932 }
933 os << " \n"
934 << "-----------------------------------------------------------\n";
935 os.precision(oldprc);
936
937 return os;
938}
939
940//______________________________________________________________________________
942{
943 G4ThreeVector point;
944
945 G4long size = fSolids.size();
946
947 do
948 {
949 G4long rnd = G4RandFlat::shootInt(G4long(0), size);
950 G4VSolid& solid = *fSolids[rnd];
951 point = solid.GetPointOnSurface();
953 point = GetGlobalPoint(transform, point);
954 }
955 while (Inside(point) != EInside::kSurface);
956
957 return point;
958}
959
960//______________________________________________________________________________
961void
963{
964 scene.AddSolid (*this);
965}
966
967//______________________________________________________________________________
969{
972
973 G4VSolid* solidA = GetSolid(0);
974 const G4Transform3D transform0=GetTransformation(0);
975 G4DisplacedSolid dispSolidA("placedA",solidA,transform0);
976
977 G4Polyhedron* top = new G4Polyhedron(*dispSolidA.GetPolyhedron());
978
979 for(G4int i=1; i<GetNumberOfSolids(); ++i)
980 {
981 G4VSolid* solidB = GetSolid(i);
983 G4DisplacedSolid dispSolidB("placedB",solidB,transform);
984 G4Polyhedron* operand = dispSolidB.GetPolyhedron();
985 processor.push_back (operation, *operand);
986 }
987
988 if (processor.execute(*top)) { return top; }
989 else { return 0; }
990}
991
992//______________________________________________________________________________
994{
995 if (fpPolyhedron == nullptr ||
999 {
1001 delete fpPolyhedron;
1003 fRebuildPolyhedron = false;
1004 l.unlock();
1005 }
1006 return fpPolyhedron;
1007}
static int operand(pchar begin, pchar end, double &result, pchar &endp, const dic_type &dictionary)
Definition: Evaluator.cc:163
static const G4double pos
static const G4double pMax
static const G4double pMin
static constexpr double s
Definition: G4SIunits.hh:154
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:83
long G4long
Definition: G4Types.hh:87
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4UniformRand()
Definition: Randomize.hh:52
double z() const
Hep3Vector unit() const
double x() const
double y() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4Polyhedron * GetPolyhedron() const
G4double GetRadialTolerance() const
static G4GeometryTolerance * GetInstance()
const G4Transform3D & GetTransformation(G4int index) const
G4int GetNumberOfSolids() const
G4double kRadTolerance
G4double DistanceToIn(const G4ThreeVector &aPoint) const
G4double GetSurfaceArea()
G4double DistanceToOutNoVoxels(const G4ThreeVector &aPoint, const G4ThreeVector &aDirection, G4ThreeVector *aNormalVector) const
G4int SafetyFromOutsideNumberNode(const G4ThreeVector &aPoint, G4double &safety) const
G4ThreeVector GetLocalVector(const G4Transform3D &trans, const G4ThreeVector &gvec) const
G4ThreeVector GetGlobalPoint(const G4Transform3D &trans, const G4ThreeVector &lpoint) const
G4double GetCubicVolume()
EInside InsideNoVoxels(const G4ThreeVector &aPoint) const
G4double DistanceToInNoVoxels(const G4ThreeVector &aPoint, const G4ThreeVector &aDirection) const
EInside Inside(const G4ThreeVector &aPoint) const
G4double DistanceToOut(const G4ThreeVector &aPoint) const
G4Polyhedron * CreatePolyhedron() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
std::vector< G4Transform3D > fTransformObjs
void BoundingLimits(G4ThreeVector &aMin, G4ThreeVector &aMax) const
G4Polyhedron * GetPolyhedron() const
void TransformLimits(G4ThreeVector &min, G4ThreeVector &max, const G4Transform3D &transformation) const
G4double DistanceToOutVoxels(const G4ThreeVector &aPoint, const G4ThreeVector &aDirection, G4ThreeVector *aNormalVector) const
G4double DistanceToInCandidates(const G4ThreeVector &aPoint, const G4ThreeVector &aDirection, std::vector< G4int > &candidates, G4SurfBits &bits) const
std::ostream & StreamInfo(std::ostream &os) const
G4ThreeVector GetGlobalVector(const G4Transform3D &trans, const G4ThreeVector &lvec) const
G4bool fRebuildPolyhedron
void DescribeYourselfTo(G4VGraphicsScene &scene) const
void AddNode(G4VSolid &solid, const G4Transform3D &trans)
Definition: G4MultiUnion.cc:69
G4Voxelizer fVoxels
G4double fSurfaceArea
void Extent(EAxis aAxis, G4double &aMin, G4double &aMax) const
G4VSolid * Clone() const
Definition: G4MultiUnion.cc:83
G4ThreeVector GetPointOnSurface() const
G4VSolid * GetSolid(G4int index) const
G4bool fAccurate
G4double fCubicVolume
G4ThreeVector GetLocalPoint(const G4Transform3D &trans, const G4ThreeVector &gpoint) const
EInside InsideWithExclusion(const G4ThreeVector &aPoint, G4SurfBits *bits=0) const
G4Polyhedron * fpPolyhedron
std::vector< G4VSolid * > fSolids
G4ThreeVector SurfaceNormal(const G4ThreeVector &aPoint) const
G4MultiUnion & operator=(const G4MultiUnion &rhs)
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
void ResetBitNumber(unsigned int bitnumber)
Definition: G4SurfBits.hh:154
void SetBitNumber(unsigned int bitnumber, G4bool value=true)
Definition: G4SurfBits.hh:114
virtual void AddSolid(const G4Box &)=0
G4double EstimateSurfaceArea(G4int nStat, G4double ell) const
Definition: G4VSolid.cc:265
G4String GetName() const
virtual std::ostream & StreamInfo(std::ostream &os) const =0
virtual EInside Inside(const G4ThreeVector &p) const =0
void SetName(const G4String &name)
Definition: G4VSolid.cc:127
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const =0
virtual G4ThreeVector GetPointOnSurface() const
Definition: G4VSolid.cc:152
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
virtual void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Definition: G4VSolid.cc:665
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:107
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
G4double DistanceToBoundingBox(const G4ThreeVector &point) const
const std::vector< G4VoxelBox > & GetBoxes() const
void GetVoxel(std::vector< G4int > &curVoxel, const G4ThreeVector &point) const
G4int GetBitsPerSlice() const
G4double DistanceToFirst(const G4ThreeVector &point, const G4ThreeVector &direction) const
G4int GetCandidatesVoxelArray(const G4ThreeVector &point, std::vector< G4int > &list, G4SurfBits *crossed=nullptr) const
Definition: G4Voxelizer.cc:973
G4double DistanceToNext(const G4ThreeVector &point, const G4ThreeVector &direction, std::vector< G4int > &curVoxel) const
void Voxelize(std::vector< G4VSolid * > &solids, std::vector< G4Transform3D > &transforms)
Definition: G4Voxelizer.cc:713
static G4int GetNumberOfRotationSteps()
EAxis
Definition: geomdefs.hh:54
@ kYAxis
Definition: geomdefs.hh:56
@ kXAxis
Definition: geomdefs.hh:55
@ kZAxis
Definition: geomdefs.hh:57
EInside
Definition: geomdefs.hh:67
@ kInside
Definition: geomdefs.hh:70
@ kOutside
Definition: geomdefs.hh:68
@ kSurface
Definition: geomdefs.hh:69
static const G4double kInfinity
Definition: geomdefs.hh:41
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:79
T max(const T t1, const T t2)
brief Return the largest of the two arguments
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
const char * name(G4int ptype)
G4bool transform(G4String &input, const G4String &type)
#define processor
Definition: xmlparse.cc:617