Geant4-11
G4TessellatedSolid.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 and of QinetiQ Ltd, *
20// * subject to DEFCON 705 IPR conditions. *
21// * By using, copying, modifying or distributing the software (or *
22// * any work based on the software) you agree to acknowledge its *
23// * use in resulting scientific publications, and indicate your *
24// * acceptance of all terms of the Geant4 Software license. *
25// ********************************************************************
26//
27// G4TessellatedSolid implementation
28//
29// 31.10.2004, P R Truscott, QinetiQ Ltd, UK - Created.
30// 17.09.2007, P R Truscott, QinetiQ Ltd & Richard Holmberg
31// Updated extensively prior to this date to deal with
32// concaved tessellated surfaces, based on the algorithm
33// of Richard Holmberg. This had been slightly modified
34// to determine with inside the geometry by projecting
35// random rays from the point provided. Now random rays
36// are predefined rather than making use of random
37// number generator at run-time.
38// 12.10.2012, M Gayer, CERN, complete rewrite reducing memory
39// requirements more than 50% and speedup by a factor of
40// tens or more depending on the number of facets, thanks
41// to voxelization of surface and improvements.
42// Speedup factor of thousands for solids with number of
43// facets in hundreds of thousands.
44// 23.10.2016, E Tcherniaev, reimplemented CalculateExtent() to make
45// use of G4BoundingEnvelope.
46// --------------------------------------------------------------------
47
48#include "G4TessellatedSolid.hh"
49
50#if !defined(G4GEOM_USE_UTESSELLATEDSOLID)
51
52#include <iostream>
53#include <stack>
54#include <iostream>
55#include <iomanip>
56#include <fstream>
57#include <algorithm>
58#include <list>
59#include <random>
60
61#include "geomdefs.hh"
62#include "Randomize.hh"
63#include "G4SystemOfUnits.hh"
66#include "G4VoxelLimits.hh"
67#include "G4AffineTransform.hh"
68#include "G4BoundingEnvelope.hh"
69
71#include "G4VGraphicsScene.hh"
72#include "G4VisExtent.hh"
73
74#include "G4AutoLock.hh"
75
76namespace
77{
79}
80
81using namespace std;
82
84//
85// Standard contructor has blank name and defines no fFacets.
86//
88{
89 Initialize();
90}
91
93//
94// Alternative constructor. Simple define name and geometry type - no fFacets
95// to detine.
96//
98 : G4VSolid(name)
99{
100 Initialize();
101}
102
104//
105// Fake default constructor - sets only member data and allocates memory
106// for usage restricted to object persistency.
107//
109{
110 Initialize();
111 fMinExtent.set(0,0,0);
112 fMaxExtent.set(0,0,0);
113}
114
115
118{
120}
121
123//
124// Copy constructor.
125//
127 : G4VSolid(ts)
128{
129 Initialize();
130
132}
133
135//
136// Assignment operator.
137//
140{
141 if (&ts == this) return *this;
142
143 // Copy base class data
145
146 DeleteObjects ();
147
148 Initialize();
149
150 CopyObjects (ts);
151
152 return *this;
153}
154
156//
158{
160
161 fRebuildPolyhedron = false; fpPolyhedron = nullptr;
162 fCubicVolume = 0.; fSurfaceArea = 0.;
163
164 fGeometryType = "G4TessellatedSolid";
165 fSolidClosed = false;
166
169
171}
172
174//
176{
177 G4int size = fFacets.size();
178 for (G4int i = 0; i < size; ++i) { delete fFacets[i]; }
179 fFacets.clear();
180 delete fpPolyhedron; fpPolyhedron = nullptr;
181}
182
184//
186{
187 G4ThreeVector reductionRatio;
188 G4int fmaxVoxels = fVoxels.GetMaxVoxels(reductionRatio);
189 if (fmaxVoxels < 0)
190 fVoxels.SetMaxVoxels(reductionRatio);
191 else
192 fVoxels.SetMaxVoxels(fmaxVoxels);
193
194 G4int n = ts.GetNumberOfFacets();
195 for (G4int i = 0; i < n; ++i)
196 {
197 G4VFacet *facetClone = (ts.GetFacet(i))->GetClone();
198 AddFacet(facetClone);
199 }
200 if (ts.GetSolidClosed()) SetSolidClosed(true);
201}
202
204//
205// Add a facet to the facet list.
206// Note that you can add, but you cannot delete.
207//
209{
210 // Add the facet to the vector.
211 //
212 if (fSolidClosed)
213 {
214 G4Exception("G4TessellatedSolid::AddFacet()", "GeomSolids1002",
215 JustWarning, "Attempt to add facets when solid is closed.");
216 return false;
217 }
218 else if (aFacet->IsDefined())
219 {
220 set<G4VertexInfo,G4VertexComparator>::iterator begin
221 = fFacetList.begin(), end = fFacetList.end(), pos, it;
222 G4ThreeVector p = aFacet->GetCircumcentre();
223 G4VertexInfo value;
224 value.id = fFacetList.size();
225 value.mag2 = p.x() + p.y() + p.z();
226
227 G4bool found = false;
229 {
230 G4double kCarTolerance3 = 3 * kCarTolerance;
231 pos = fFacetList.lower_bound(value);
232
233 it = pos;
234 while (!found && it != end) // Loop checking, 13.08.2015, G.Cosmo
235 {
236 G4int id = (*it).id;
237 G4VFacet *facet = fFacets[id];
238 G4ThreeVector q = facet->GetCircumcentre();
239 if ((found = (facet == aFacet))) break;
240 G4double dif = q.x() + q.y() + q.z() - value.mag2;
241 if (dif > kCarTolerance3) break;
242 it++;
243 }
244
245 if (fFacets.size() > 1)
246 {
247 it = pos;
248 while (!found && it != begin) // Loop checking, 13.08.2015, G.Cosmo
249 {
250 --it;
251 G4int id = (*it).id;
252 G4VFacet *facet = fFacets[id];
253 G4ThreeVector q = facet->GetCircumcentre();
254 found = (facet == aFacet);
255 if (found) break;
256 G4double dif = value.mag2 - (q.x() + q.y() + q.z());
257 if (dif > kCarTolerance3) break;
258 }
259 }
260 }
261
262 if (!found)
263 {
264 fFacets.push_back(aFacet);
265 fFacetList.insert(value);
266 }
267 return true;
268 }
269 else
270 {
271 G4Exception("G4TessellatedSolid::AddFacet()", "GeomSolids1002",
272 JustWarning, "Attempt to add facet not properly defined.");
273 aFacet->StreamInfo(G4cout);
274 return false;
275 }
276}
277
279//
280G4int G4TessellatedSolid::SetAllUsingStack(const std::vector<G4int>& voxel,
281 const std::vector<G4int>& max,
282 G4bool status, G4SurfBits& checked)
283{
284 vector<G4int> xyz = voxel;
285 stack<vector<G4int> > pos;
286 pos.push(xyz);
287 G4int filled = 0;
288 G4int cc = 0, nz = 0;
289
290 vector<G4int> candidates;
291
292 while (!pos.empty()) // Loop checking, 13.08.2015, G.Cosmo
293 {
294 xyz = pos.top();
295 pos.pop();
296 G4int index = fVoxels.GetVoxelsIndex(xyz);
297 if (!checked[index])
298 {
299 checked.SetBitNumber(index, true);
300 ++cc;
301
302 if (fVoxels.IsEmpty(index))
303 {
304 ++filled;
305
306 fInsides.SetBitNumber(index, status);
307
308 for (auto i = 0; i <= 2; ++i)
309 {
310 if (xyz[i] < max[i] - 1)
311 {
312 xyz[i]++;
313 pos.push(xyz);
314 xyz[i]--;
315 }
316
317 if (xyz[i] > 0)
318 {
319 xyz[i]--;
320 pos.push(xyz);
321 xyz[i]++;
322 }
323 }
324 }
325 else
326 {
327 ++nz;
328 }
329 }
330 }
331 return filled;
332}
333
335//
337{
338 vector<G4int> voxel(3), maxVoxels(3);
339 for (auto i = 0; i <= 2; ++i) maxVoxels[i] = fVoxels.GetBoundary(i).size();
340 G4int size = maxVoxels[0] * maxVoxels[1] * maxVoxels[2];
341
342 G4SurfBits checked(size-1);
343 fInsides.Clear();
344 fInsides.ResetBitNumber(size-1);
345
346 G4ThreeVector point;
347 for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
348 {
349 for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
350 {
351 for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
352 {
353 G4int index = fVoxels.GetVoxelsIndex(voxel);
354 if (!checked[index] && fVoxels.IsEmpty(index))
355 {
356 for (auto i = 0; i <= 2; ++i)
357 {
358 point[i] = fVoxels.GetBoundary(i)[voxel[i]];
359 }
360 G4bool inside = (G4bool) (InsideNoVoxels(point) == kInside);
361 SetAllUsingStack(voxel, maxVoxels, inside, checked);
362 }
363 else checked.SetBitNumber(index);
364 }
365 }
366 }
367}
368
370//
372{
373#ifdef G4SPECSDEBUG
374 G4cout << "Voxelizing..." << G4endl;
375#endif
377
378 if (fVoxels.Empty().GetNbits())
379 {
380#ifdef G4SPECSDEBUG
381 G4cout << "Precalculating Insides..." << G4endl;
382#endif
384 }
385}
386
388//
389// Compute extremeFacets, i.e. find those facets that have surface
390// planes that bound the volume.
391// Note that this is going to reject concaved surfaces as being extreme. Also
392// note that if the vertex is on the facet, displacement is zero, so IsInside
393// returns true. So will this work?? Need non-equality
394// "G4bool inside = displacement < 0.0;"
395// or
396// "G4bool inside = displacement <= -0.5*kCarTolerance"
397// (Notes from PT 13/08/2007).
398//
400{
401 // Copy vertices to local array
402 G4int vsize = fVertexList.size();
403 std::vector<G4ThreeVector> vertices(vsize);
404 for (G4int i = 0; i < vsize; ++i) { vertices[i] = fVertexList[i]; }
405
406 // Shuffle vertices
407 std::mt19937 gen(12345678);
408 std::shuffle(vertices.begin(), vertices.end(), gen);
409
410 // Select six extreme vertices in different directions
411 G4ThreeVector points[6];
412 for (G4int i=0; i < 6; ++i) { points[i] = vertices[0]; }
413 for (G4int i=1; i < vsize; ++i)
414 {
415 if (vertices[i].x() < points[0].x()) points[0] = vertices[i];
416 if (vertices[i].x() > points[1].x()) points[1] = vertices[i];
417 if (vertices[i].y() < points[2].y()) points[2] = vertices[i];
418 if (vertices[i].y() > points[3].y()) points[3] = vertices[i];
419 if (vertices[i].z() < points[4].z()) points[4] = vertices[i];
420 if (vertices[i].z() > points[5].z()) points[5] = vertices[i];
421 }
422
423 // Find extreme facets
424 G4int size = fFacets.size();
425 for (G4int j = 0; j < size; ++j)
426 {
427 G4VFacet &facet = *fFacets[j];
428
429 // Check extreme vertices
430 if (!facet.IsInside(points[0])) continue;
431 if (!facet.IsInside(points[1])) continue;
432 if (!facet.IsInside(points[2])) continue;
433 if (!facet.IsInside(points[3])) continue;
434 if (!facet.IsInside(points[4])) continue;
435 if (!facet.IsInside(points[5])) continue;
436
437 // Check vertices
438 G4bool isExtreme = true;
439 for (G4int i=0; i < vsize; ++i)
440 {
441 if (!facet.IsInside(vertices[i]))
442 {
443 isExtreme = false;
444 break;
445 }
446 }
447 if (isExtreme) fExtremeFacets.insert(&facet);
448 }
449}
450
452//
454{
455 // The algorithm:
456 // we will have additional vertexListSorted, where all the items will be
457 // sorted by magnitude of vertice vector.
458 // New candidate for fVertexList - we will determine the position fo first
459 // item which would be within its magnitude - 0.5*kCarTolerance.
460 // We will go trough until we will reach > +0.5 kCarTolerance.
461 // Comparison (q-p).mag() < 0.5*kCarTolerance will be made.
462 // They can be just stored in std::vector, with custom insertion based
463 // on binary search.
464
465 set<G4VertexInfo,G4VertexComparator> vertexListSorted;
466 set<G4VertexInfo,G4VertexComparator>::iterator begin
467 = vertexListSorted.begin(), end = vertexListSorted.end(), pos, it;
469 G4VertexInfo value;
470
471 fVertexList.clear();
472 G4int size = fFacets.size();
473
474 G4double kCarTolerance24 = kCarTolerance * kCarTolerance / 4.0;
475 G4double kCarTolerance3 = 3 * kCarTolerance;
476 vector<G4int> newIndex(100);
477
478 for (G4int k = 0; k < size; ++k)
479 {
480 G4VFacet &facet = *fFacets[k];
481 G4int max = facet.GetNumberOfVertices();
482
483 for (G4int i = 0; i < max; ++i)
484 {
485 p = facet.GetVertex(i);
486 value.id = fVertexList.size();
487 value.mag2 = p.x() + p.y() + p.z();
488
489 G4bool found = false;
490 G4int id = 0;
492 {
493 pos = vertexListSorted.lower_bound(value);
494 it = pos;
495 while (it != end) // Loop checking, 13.08.2015, G.Cosmo
496 {
497 id = (*it).id;
499 G4double dif = (q-p).mag2();
500 found = (dif < kCarTolerance24);
501 if (found) break;
502 dif = q.x() + q.y() + q.z() - value.mag2;
503 if (dif > kCarTolerance3) break;
504 it++;
505 }
506
507 if (!found && (fVertexList.size() > 1))
508 {
509 it = pos;
510 while (it != begin) // Loop checking, 13.08.2015, G.Cosmo
511 {
512 --it;
513 id = (*it).id;
515 G4double dif = (q-p).mag2();
516 found = (dif < kCarTolerance24);
517 if (found) break;
518 dif = value.mag2 - (q.x() + q.y() + q.z());
519 if (dif > kCarTolerance3) break;
520 }
521 }
522 }
523
524 if (!found)
525 {
526#ifdef G4SPECSDEBUG
527 G4cout << p.x() << ":" << p.y() << ":" << p.z() << G4endl;
528 G4cout << "Adding new vertex #" << i << " of facet " << k
529 << " id " << value.id << G4endl;
530 G4cout << "===" << G4endl;
531#endif
532 fVertexList.push_back(p);
533 vertexListSorted.insert(value);
534 begin = vertexListSorted.begin();
535 end = vertexListSorted.end();
536 newIndex[i] = value.id;
537 //
538 // Now update the maximum x, y and z limits of the volume.
539 //
540 if (value.id == 0) fMinExtent = fMaxExtent = p;
541 else
542 {
543 if (p.x() > fMaxExtent.x()) fMaxExtent.setX(p.x());
544 else if (p.x() < fMinExtent.x()) fMinExtent.setX(p.x());
545 if (p.y() > fMaxExtent.y()) fMaxExtent.setY(p.y());
546 else if (p.y() < fMinExtent.y()) fMinExtent.setY(p.y());
547 if (p.z() > fMaxExtent.z()) fMaxExtent.setZ(p.z());
548 else if (p.z() < fMinExtent.z()) fMinExtent.setZ(p.z());
549 }
550 }
551 else
552 {
553#ifdef G4SPECSDEBUG
554 G4cout << p.x() << ":" << p.y() << ":" << p.z() << G4endl;
555 G4cout << "Vertex #" << i << " of facet " << k
556 << " found, redirecting to " << id << G4endl;
557 G4cout << "===" << G4endl;
558#endif
559 newIndex[i] = id;
560 }
561 }
562 // only now it is possible to change vertices pointer
563 //
564 facet.SetVertices(&fVertexList);
565 for (G4int i = 0; i < max; ++i)
566 facet.SetVertexIndex(i,newIndex[i]);
567 }
568 vector<G4ThreeVector>(fVertexList).swap(fVertexList);
569
570#ifdef G4SPECSDEBUG
571 G4double previousValue = 0.;
572 for (auto res=vertexListSorted.cbegin(); res!=vertexListSorted.cend(); ++res)
573 {
574 G4int id = (*res).id;
575 G4ThreeVector vec = fVertexList[id];
576 G4double mvalue = vec.x() + vec.y() + vec.z();
577 if (previousValue && (previousValue - 1e-9 > mvalue))
578 G4cout << "Error in CreateVertexList: previousValue " << previousValue
579 << " is smaller than mvalue " << mvalue << G4endl;
580 previousValue = mvalue;
581 }
582#endif
583}
584
586//
588{
590 G4int with = AllocatedMemory();
591 G4double ratio = (G4double) with / without;
592 G4cout << "G4TessellatedSolid - Allocated memory without voxel overhead "
593 << without << "; with " << with << "; ratio: " << ratio << G4endl;
594}
595
597//
599{
600 if (t)
601 {
602#ifdef G4SPECSDEBUG
603 G4cout << "Creating vertex list..." << G4endl;
604#endif
606
607#ifdef G4SPECSDEBUG
608 G4cout << "Setting extreme facets..." << G4endl;
609#endif
611
612#ifdef G4SPECSDEBUG
613 G4cout << "Voxelizing..." << G4endl;
614#endif
615 Voxelize();
616
617#ifdef G4SPECSDEBUG
619#endif
620
621#ifdef G4SPECSDEBUG
622 G4cout << "Checking Structure..." << G4endl;
623#endif
624 G4int irep = CheckStructure();
625 if (irep != 0)
626 {
627 if (irep & 1)
628 {
629 std::ostringstream message;
630 message << "Defects in solid: " << GetName()
631 << " - negative cubic volume, please check orientation of facets!";
632 G4Exception("G4TessellatedSolid::SetSolidClosed()",
633 "GeomSolids1001", JustWarning, message);
634 }
635 if (irep & 2)
636 {
637 std::ostringstream message;
638 message << "Defects in solid: " << GetName()
639 << " - some facets have wrong orientation!";
640 G4Exception("G4TessellatedSolid::SetSolidClosed()",
641 "GeomSolids1001", JustWarning, message);
642 }
643 if (irep & 4)
644 {
645 std::ostringstream message;
646 message << "Defects in solid: " << GetName()
647 << " - there are holes in the surface!";
648 G4Exception("G4TessellatedSolid::SetSolidClosed()",
649 "GeomSolids1001", JustWarning, message);
650 }
651 }
652 }
653 fSolidClosed = t;
654}
655
657//
658// GetSolidClosed
659//
660// Used to determine whether the solid is closed to adding further fFacets.
661//
663{
664 return fSolidClosed;
665}
666
668//
669// CheckStructure
670//
671// Checks structure of the solid. Return value is a sum of the following
672// defect indicators, if any (0 means no defects):
673// 1 - cubic volume is negative, wrong orientation of facets
674// 2 - some facets have wrong orientation
675// 4 - holes in the surface
676//
678{
679 G4int nedge = 0;
680 G4int nface = fFacets.size();
681
682 // Calculate volume
683 //
684 G4double volume = 0.;
685 for (G4int i = 0; i < nface; ++i)
686 {
687 G4VFacet& facet = *fFacets[i];
688 nedge += facet.GetNumberOfVertices();
689 volume += facet.GetArea()*(facet.GetVertex(0).dot(facet.GetSurfaceNormal()));
690 }
691 G4int ivolume = (volume <= 0.);
692
693 // Create sorted vector of edges
694 //
695 std::vector<int64_t> iedge(nedge);
696 G4int kk = 0;
697 for (G4int i = 0; i < nface; ++i)
698 {
699 G4VFacet& facet = *fFacets[i];
700 G4int nnode = facet.GetNumberOfVertices();
701 for (G4int k = 0; k < nnode; ++k)
702 {
703 int64_t i1 = facet.GetVertexIndex((k == 0) ? nnode - 1 : k - 1);
704 int64_t i2 = facet.GetVertexIndex(k);
705 int64_t inverse = (i2 > i1);
706 if (inverse) std::swap(i1, i2);
707 iedge[kk++] = i1*1000000000 + i2*2 + inverse;
708 }
709 }
710 std::sort(iedge.begin(), iedge.end());
711
712 // Check edges, correct structure should consist of paired edges
713 // with different orientation
714 //
715 G4int iorder = 0;
716 G4int ihole = 0;
717 G4int i = 0;
718 while (i < nedge - 1)
719 {
720 if (iedge[i + 1] - iedge[i] == 1) // paired edges with different orientation
721 {
722 i += 2;
723 }
724 else if (iedge[i + 1] == iedge[i]) // paired edges with the same orientation
725 {
726 iorder = 2;
727 i += 2;
728 }
729 else // unpaired edge
730 {
731 ihole = 4;
732 i++;
733 }
734 }
735 return ivolume + iorder + ihole;
736}
737
739//
740// operator+=
741//
742// This operator allows the user to add two tessellated solids together, so
743// that the solid on the left then includes all of the facets in the solid
744// on the right. Note that copies of the facets are generated, rather than
745// using the original facet set of the solid on the right.
746//
749{
750 G4int size = right.GetNumberOfFacets();
751 for (G4int i = 0; i < size; ++i)
752 AddFacet(right.GetFacet(i)->GetClone());
753
754 return *this;
755}
756
758//
759// GetNumberOfFacets
760//
762{
763 return fFacets.size();
764}
765
767//
769{
770 //
771 // First the simple test - check if we're outside of the X-Y-Z extremes
772 // of the tessellated solid.
773 //
775 return kOutside;
776
777 vector<G4int> startingVoxel(3);
778 fVoxels.GetVoxel(startingVoxel, p);
779
780 const G4double dirTolerance = 1.0E-14;
781
782 const vector<G4int> &startingCandidates =
783 fVoxels.GetCandidates(startingVoxel);
784 G4int limit = startingCandidates.size();
785 if (limit == 0 && fInsides.GetNbits())
786 {
787 G4int index = fVoxels.GetPointIndex(p);
788 EInside location = fInsides[index] ? kInside : kOutside;
789 return location;
790 }
791
792 G4double minDist = kInfinity;
793
794 for(G4int i = 0; i < limit; ++i)
795 {
796 G4int candidate = startingCandidates[i];
797 G4VFacet &facet = *fFacets[candidate];
798 G4double dist = facet.Distance(p,minDist);
799 if (dist < minDist) minDist = dist;
800 if (dist <= kCarToleranceHalf)
801 return kSurface;
802 }
803
804 // The following is something of an adaptation of the method implemented by
805 // Rickard Holmberg augmented with information from Schneider & Eberly,
806 // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence,
807 // we're trying to determine whether we're inside the volume by projecting
808 // a few rays and determining if the first surface crossed is has a normal
809 // vector between 0 to pi/2 (out-going) or pi/2 to pi (in-going).
810 // We should also avoid rays which are nearly within the plane of the
811 // tessellated surface, and therefore produce rays randomly.
812 // For the moment, this is a bit over-engineered (belt-braces-and-ducttape).
813 //
814 G4double distOut = kInfinity;
815 G4double distIn = kInfinity;
816 G4double distO = 0.0;
817 G4double distI = 0.0;
818 G4double distFromSurfaceO = 0.0;
819 G4double distFromSurfaceI = 0.0;
820 G4ThreeVector normalO, normalI;
821 G4bool crossingO = false;
822 G4bool crossingI = false;
823 EInside location = kOutside;
824 G4int sm = 0;
825
826 G4bool nearParallel = false;
827 do // Loop checking, 13.08.2015, G.Cosmo
828 {
829 // We loop until we find direction where the vector is not nearly parallel
830 // to the surface of any facet since this causes ambiguities. The usual
831 // case is that the angles should be sufficiently different, but there
832 // are 20 random directions to select from - hopefully sufficient.
833 //
834 distOut = distIn = kInfinity;
835 const G4ThreeVector& v = fRandir[sm];
836 ++sm;
837 //
838 // This code could be voxelized by the same algorithm, which is used for
839 // DistanceToOut(). We will traverse through fVoxels. we will call
840 // intersect only for those, which would be candidates and was not
841 // checked before.
842 //
843 G4ThreeVector currentPoint = p;
844 G4ThreeVector direction = v.unit();
845 // G4SurfBits exclusion(fVoxels.GetBitsPerSlice());
846 vector<G4int> curVoxel(3);
847 curVoxel = startingVoxel;
848 G4double shiftBonus = kCarTolerance;
849
850 G4bool crossed = false;
851 G4bool started = true;
852
853 do // Loop checking, 13.08.2015, G.Cosmo
854 {
855 const vector<G4int> &candidates =
856 started ? startingCandidates : fVoxels.GetCandidates(curVoxel);
857 started = false;
858 if (G4int candidatesCount = candidates.size())
859 {
860 for (G4int i = 0 ; i < candidatesCount; ++i)
861 {
862 G4int candidate = candidates[i];
863 // bits.SetBitNumber(candidate);
864 G4VFacet& facet = *fFacets[candidate];
865
866 crossingO = facet.Intersect(p,v,true,distO,distFromSurfaceO,normalO);
867 crossingI = facet.Intersect(p,v,false,distI,distFromSurfaceI,normalI);
868
869 if (crossingO || crossingI)
870 {
871 crossed = true;
872
873 nearParallel = (crossingO
874 && std::fabs(normalO.dot(v))<dirTolerance)
875 || (crossingI && std::fabs(normalI.dot(v))<dirTolerance);
876 if (!nearParallel)
877 {
878 if (crossingO && distO > 0.0 && distO < distOut)
879 distOut = distO;
880 if (crossingI && distI > 0.0 && distI < distIn)
881 distIn = distI;
882 }
883 else break;
884 }
885 }
886 if (nearParallel) break;
887 }
888 else
889 {
890 if (!crossed)
891 {
892 G4int index = fVoxels.GetVoxelsIndex(curVoxel);
893 G4bool inside = fInsides[index];
894 location = inside ? kInside : kOutside;
895 return location;
896 }
897 }
898
899 G4double shift=fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
900 if (shift == kInfinity) break;
901
902 currentPoint += direction * (shift + shiftBonus);
903 }
904 while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
905
906 }
907 while (nearParallel && sm != fMaxTries);
908 //
909 // Here we loop through the facets to find out if there is an intersection
910 // between the ray and that facet. The test if performed separately whether
911 // the ray is entering the facet or exiting.
912 //
913#ifdef G4VERBOSE
914 if (sm == fMaxTries)
915 {
916 //
917 // We've run out of random vector directions. If nTries is set sufficiently
918 // low (nTries <= 0.5*maxTries) then this would indicate that there is
919 // something wrong with geometry.
920 //
921 std::ostringstream message;
922 G4int oldprc = message.precision(16);
923 message << "Cannot determine whether point is inside or outside volume!"
924 << G4endl
925 << "Solid name = " << GetName() << G4endl
926 << "Geometry Type = " << fGeometryType << G4endl
927 << "Number of facets = " << fFacets.size() << G4endl
928 << "Position:" << G4endl << G4endl
929 << "p.x() = " << p.x()/mm << " mm" << G4endl
930 << "p.y() = " << p.y()/mm << " mm" << G4endl
931 << "p.z() = " << p.z()/mm << " mm";
932 message.precision(oldprc);
933 G4Exception("G4TessellatedSolid::Inside()",
934 "GeomSolids1002", JustWarning, message);
935 }
936#endif
937
938 // In the next if-then-elseif G4String the logic is as follows:
939 // (1) You don't hit anything so cannot be inside volume, provided volume
940 // constructed correctly!
941 // (2) Distance to inside (ie. nearest facet such that you enter facet) is
942 // shorter than distance to outside (nearest facet such that you exit
943 // facet) - on condition of safety distance - therefore we're outside.
944 // (3) Distance to outside is shorter than distance to inside therefore
945 // we're inside.
946 //
947 if (distIn == kInfinity && distOut == kInfinity)
948 location = kOutside;
949 else if (distIn <= distOut - kCarToleranceHalf)
950 location = kOutside;
951 else if (distOut <= distIn - kCarToleranceHalf)
952 location = kInside;
953
954 return location;
955}
956
958//
960{
961 //
962 // First the simple test - check if we're outside of the X-Y-Z extremes
963 // of the tessellated solid.
964 //
966 return kOutside;
967
968 const G4double dirTolerance = 1.0E-14;
969
970 G4double minDist = kInfinity;
971 //
972 // Check if we are close to a surface
973 //
974 G4int size = fFacets.size();
975 for (G4int i = 0; i < size; ++i)
976 {
977 G4VFacet& facet = *fFacets[i];
978 G4double dist = facet.Distance(p,minDist);
979 if (dist < minDist) minDist = dist;
980 if (dist <= kCarToleranceHalf)
981 {
982 return kSurface;
983 }
984 }
985 //
986 // The following is something of an adaptation of the method implemented by
987 // Rickard Holmberg augmented with information from Schneider & Eberly,
988 // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence, we're
989 // trying to determine whether we're inside the volume by projecting a few
990 // rays and determining if the first surface crossed is has a normal vector
991 // between 0 to pi/2 (out-going) or pi/2 to pi (in-going). We should also
992 // avoid rays which are nearly within the plane of the tessellated surface,
993 // and therefore produce rays randomly. For the moment, this is a bit
994 // over-engineered (belt-braces-and-ducttape).
995 //
996#if G4SPECSDEBUG
997 G4int nTry = 7;
998#else
999 G4int nTry = 3;
1000#endif
1001 G4double distOut = kInfinity;
1002 G4double distIn = kInfinity;
1003 G4double distO = 0.0;
1004 G4double distI = 0.0;
1005 G4double distFromSurfaceO = 0.0;
1006 G4double distFromSurfaceI = 0.0;
1007 G4ThreeVector normalO(0.0,0.0,0.0);
1008 G4ThreeVector normalI(0.0,0.0,0.0);
1009 G4bool crossingO = false;
1010 G4bool crossingI = false;
1011 EInside location = kOutside;
1012 EInside locationprime = kOutside;
1013 G4int sm = 0;
1014
1015 for (G4int i=0; i<nTry; ++i)
1016 {
1017 G4bool nearParallel = false;
1018 do // Loop checking, 13.08.2015, G.Cosmo
1019 {
1020 //
1021 // We loop until we find direction where the vector is not nearly parallel
1022 // to the surface of any facet since this causes ambiguities. The usual
1023 // case is that the angles should be sufficiently different, but there
1024 // are 20 random directions to select from - hopefully sufficient.
1025 //
1026 distOut = distIn = kInfinity;
1028 sm++;
1029 vector<G4VFacet*>::const_iterator f = fFacets.begin();
1030
1031 do // Loop checking, 13.08.2015, G.Cosmo
1032 {
1033 //
1034 // Here we loop through the facets to find out if there is an
1035 // intersection between the ray and that facet. The test if performed
1036 // separately whether the ray is entering the facet or exiting.
1037 //
1038 crossingO = ((*f)->Intersect(p,v,true,distO,distFromSurfaceO,normalO));
1039 crossingI = ((*f)->Intersect(p,v,false,distI,distFromSurfaceI,normalI));
1040 if (crossingO || crossingI)
1041 {
1042 nearParallel = (crossingO && std::fabs(normalO.dot(v))<dirTolerance)
1043 || (crossingI && std::fabs(normalI.dot(v))<dirTolerance);
1044 if (!nearParallel)
1045 {
1046 if (crossingO && distO > 0.0 && distO < distOut) distOut = distO;
1047 if (crossingI && distI > 0.0 && distI < distIn) distIn = distI;
1048 }
1049 }
1050 } while (!nearParallel && ++f != fFacets.end());
1051 } while (nearParallel && sm != fMaxTries);
1052
1053#ifdef G4VERBOSE
1054 if (sm == fMaxTries)
1055 {
1056 //
1057 // We've run out of random vector directions. If nTries is set
1058 // sufficiently low (nTries <= 0.5*maxTries) then this would indicate
1059 // that there is something wrong with geometry.
1060 //
1061 std::ostringstream message;
1062 G4int oldprc = message.precision(16);
1063 message << "Cannot determine whether point is inside or outside volume!"
1064 << G4endl
1065 << "Solid name = " << GetName() << G4endl
1066 << "Geometry Type = " << fGeometryType << G4endl
1067 << "Number of facets = " << fFacets.size() << G4endl
1068 << "Position:" << G4endl << G4endl
1069 << "p.x() = " << p.x()/mm << " mm" << G4endl
1070 << "p.y() = " << p.y()/mm << " mm" << G4endl
1071 << "p.z() = " << p.z()/mm << " mm";
1072 message.precision(oldprc);
1073 G4Exception("G4TessellatedSolid::Inside()",
1074 "GeomSolids1002", JustWarning, message);
1075 }
1076#endif
1077 //
1078 // In the next if-then-elseif G4String the logic is as follows:
1079 // (1) You don't hit anything so cannot be inside volume, provided volume
1080 // constructed correctly!
1081 // (2) Distance to inside (ie. nearest facet such that you enter facet) is
1082 // shorter than distance to outside (nearest facet such that you exit
1083 // facet) - on condition of safety distance - therefore we're outside.
1084 // (3) Distance to outside is shorter than distance to inside therefore
1085 // we're inside.
1086 //
1087 if (distIn == kInfinity && distOut == kInfinity)
1088 locationprime = kOutside;
1089 else if (distIn <= distOut - kCarToleranceHalf)
1090 locationprime = kOutside;
1091 else if (distOut <= distIn - kCarToleranceHalf)
1092 locationprime = kInside;
1093
1094 if (i == 0) location = locationprime;
1095 }
1096
1097 return location;
1098}
1099
1101//
1102// Return index of the facet closest to the point p, normally the point should
1103// be located on the surface. Return -1 if no facet selected.
1104//
1106{
1107 G4int index = -1;
1108
1109 if (fVoxels.GetCountOfVoxels() > 1)
1110 {
1111 vector<G4int> curVoxel(3);
1112 fVoxels.GetVoxel(curVoxel, p);
1113 const vector<G4int> &candidates = fVoxels.GetCandidates(curVoxel);
1114 if (G4int limit = candidates.size())
1115 {
1116 G4double minDist = kInfinity;
1117 for(G4int i = 0 ; i < limit ; ++i)
1118 {
1119 G4int candidate = candidates[i];
1120 G4VFacet& facet = *fFacets[candidate];
1121 G4double dist = facet.Distance(p, minDist);
1122 if (dist <= kCarToleranceHalf) return index = candidate;
1123 if (dist < minDist)
1124 {
1125 minDist = dist;
1126 index = candidate;
1127 }
1128 }
1129 }
1130 }
1131 else
1132 {
1133 G4double minDist = kInfinity;
1134 G4int size = fFacets.size();
1135 for (G4int i = 0; i < size; ++i)
1136 {
1137 G4VFacet& facet = *fFacets[i];
1138 G4double dist = facet.Distance(p, minDist);
1139 if (dist < minDist)
1140 {
1141 minDist = dist;
1142 index = i;
1143 }
1144 }
1145 }
1146 return index;
1147}
1148
1150//
1151// Return the outwards pointing unit normal of the shape for the
1152// surface closest to the point at offset p.
1153//
1155 G4ThreeVector& aNormal) const
1156{
1157 G4double minDist;
1158 G4VFacet* facet = nullptr;
1159
1160 if (fVoxels.GetCountOfVoxels() > 1)
1161 {
1162 vector<G4int> curVoxel(3);
1163 fVoxels.GetVoxel(curVoxel, p);
1164 const vector<G4int> &candidates = fVoxels.GetCandidates(curVoxel);
1165 // fVoxels.GetCandidatesVoxelArray(p, candidates, 0);
1166
1167 if (G4int limit = candidates.size())
1168 {
1169 minDist = kInfinity;
1170 for(G4int i = 0 ; i < limit ; ++i)
1171 {
1172 G4int candidate = candidates[i];
1173 G4VFacet &fct = *fFacets[candidate];
1174 G4double dist = fct.Distance(p,minDist);
1175 if (dist < minDist) minDist = dist;
1176 if (dist <= kCarToleranceHalf)
1177 {
1178 aNormal = fct.GetSurfaceNormal();
1179 return true;
1180 }
1181 }
1182 }
1183 minDist = MinDistanceFacet(p, true, facet);
1184 }
1185 else
1186 {
1187 minDist = kInfinity;
1188 G4int size = fFacets.size();
1189 for (G4int i = 0; i < size; ++i)
1190 {
1191 G4VFacet& f = *fFacets[i];
1192 G4double dist = f.Distance(p, minDist);
1193 if (dist < minDist)
1194 {
1195 minDist = dist;
1196 facet = &f;
1197 }
1198 }
1199 }
1200
1201 if (minDist != kInfinity)
1202 {
1203 if (facet) { aNormal = facet->GetSurfaceNormal(); }
1204 return minDist <= kCarToleranceHalf;
1205 }
1206 else
1207 {
1208#ifdef G4VERBOSE
1209 std::ostringstream message;
1210 message << "Point p is not on surface !?" << G4endl
1211 << " No facets found for point: " << p << " !" << G4endl
1212 << " Returning approximated value for normal.";
1213
1214 G4Exception("G4TessellatedSolid::SurfaceNormal(p)",
1215 "GeomSolids1002", JustWarning, message );
1216#endif
1217 aNormal = (p.z() > 0 ? G4ThreeVector(0,0,1) : G4ThreeVector(0,0,-1));
1218 return false;
1219 }
1220}
1221
1223//
1224// G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)
1225//
1226// Return the distance along the normalised vector v to the shape,
1227// from the point at offset p. If there is no intersection, return
1228// kInfinity. The first intersection resulting from 'leaving' a
1229// surface/volume is discarded. Hence, this is tolerant of points on
1230// surface of shape.
1231//
1234 const G4ThreeVector& v,
1235 G4double /*aPstep*/) const
1236{
1237 G4double minDist = kInfinity;
1238 G4double dist = 0.0;
1239 G4double distFromSurface = 0.0;
1241
1242#if G4SPECSDEBUG
1243 if (Inside(p) == kInside )
1244 {
1245 std::ostringstream message;
1246 G4int oldprc = message.precision(16) ;
1247 message << "Point p is already inside!?" << G4endl
1248 << "Position:" << G4endl << G4endl
1249 << " p.x() = " << p.x()/mm << " mm" << G4endl
1250 << " p.y() = " << p.y()/mm << " mm" << G4endl
1251 << " p.z() = " << p.z()/mm << " mm" << G4endl
1252 << "DistanceToOut(p) == " << DistanceToOut(p);
1253 message.precision(oldprc) ;
1254 G4Exception("G4TriangularFacet::DistanceToIn(p,v)",
1255 "GeomSolids1002", JustWarning, message);
1256 }
1257#endif
1258
1259 G4int size = fFacets.size();
1260 for (G4int i = 0; i < size; ++i)
1261 {
1262 G4VFacet& facet = *fFacets[i];
1263 if (facet.Intersect(p,v,false,dist,distFromSurface,normal))
1264 {
1265 //
1266 // set minDist to the new distance to current facet if distFromSurface
1267 // is in positive direction and point is not at surface. If the point is
1268 // within 0.5*kCarTolerance of the surface, then force distance to be
1269 // zero and leave member function immediately (for efficiency), as
1270 // proposed by & credit to Akira Okumura.
1271 //
1272 if (distFromSurface > kCarToleranceHalf && dist >= 0.0 && dist < minDist)
1273 {
1274 minDist = dist;
1275 }
1276 else
1277 {
1278 if (-kCarToleranceHalf <= dist && dist <= kCarToleranceHalf)
1279 {
1280 return 0.0;
1281 }
1282 else
1283 {
1284 if (distFromSurface > -kCarToleranceHalf
1285 && distFromSurface < kCarToleranceHalf)
1286 {
1287 minDist = dist;
1288 }
1289 }
1290 }
1291 }
1292 }
1293 return minDist;
1294}
1295
1297//
1300 const G4ThreeVector& v,
1301 G4ThreeVector& aNormalVector,
1302 G4bool& aConvex,
1303 G4double /*aPstep*/) const
1304{
1305 G4double minDist = kInfinity;
1306 G4double dist = 0.0;
1307 G4double distFromSurface = 0.0;
1308 G4ThreeVector normal, minNormal;
1309
1310#if G4SPECSDEBUG
1311 if ( Inside(p) == kOutside )
1312 {
1313 std::ostringstream message;
1314 G4int oldprc = message.precision(16) ;
1315 message << "Point p is already outside!?" << G4endl
1316 << "Position:" << G4endl << G4endl
1317 << " p.x() = " << p.x()/mm << " mm" << G4endl
1318 << " p.y() = " << p.y()/mm << " mm" << G4endl
1319 << " p.z() = " << p.z()/mm << " mm" << G4endl
1320 << "DistanceToIn(p) == " << DistanceToIn(p);
1321 message.precision(oldprc) ;
1322 G4Exception("G4TriangularFacet::DistanceToOut(p)",
1323 "GeomSolids1002", JustWarning, message);
1324 }
1325#endif
1326
1327 G4bool isExtreme = false;
1328 G4int size = fFacets.size();
1329 for (G4int i = 0; i < size; ++i)
1330 {
1331 G4VFacet& facet = *fFacets[i];
1332 if (facet.Intersect(p,v,true,dist,distFromSurface,normal))
1333 {
1334 if (distFromSurface > 0.0 && distFromSurface <= kCarToleranceHalf
1336 {
1337 // We are on a surface. Return zero.
1338 aConvex = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1339 // Normal(p, aNormalVector);
1340 // aNormalVector = facet.GetSurfaceNormal();
1341 aNormalVector = normal;
1342 return 0.0;
1343 }
1344 if (dist >= 0.0 && dist < minDist)
1345 {
1346 minDist = dist;
1347 minNormal = normal;
1348 isExtreme = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1349 }
1350 }
1351 }
1352 if (minDist < kInfinity)
1353 {
1354 aNormalVector = minNormal;
1355 aConvex = isExtreme;
1356 return minDist;
1357 }
1358 else
1359 {
1360 // No intersection found
1361 aConvex = false;
1362 Normal(p, aNormalVector);
1363 return 0.0;
1364 }
1365}
1366
1368//
1370DistanceToOutCandidates(const std::vector<G4int>& candidates,
1371 const G4ThreeVector& aPoint,
1372 const G4ThreeVector& direction,
1373 G4double& minDist, G4ThreeVector& minNormal,
1374 G4int& minCandidate ) const
1375{
1376 G4int candidatesCount = candidates.size();
1377 G4double dist = 0.0;
1378 G4double distFromSurface = 0.0;
1380
1381 for (G4int i = 0 ; i < candidatesCount; ++i)
1382 {
1383 G4int candidate = candidates[i];
1384 G4VFacet& facet = *fFacets[candidate];
1385 if (facet.Intersect(aPoint,direction,true,dist,distFromSurface,normal))
1386 {
1387 if (distFromSurface > 0.0 && distFromSurface <= kCarToleranceHalf
1388 && facet.Distance(aPoint,kCarTolerance) <= kCarToleranceHalf)
1389 {
1390 // We are on a surface
1391 //
1392 minDist = 0.0;
1393 minNormal = normal;
1394 minCandidate = candidate;
1395 break;
1396 }
1397 if (dist >= 0.0 && dist < minDist)
1398 {
1399 minDist = dist;
1400 minNormal = normal;
1401 minCandidate = candidate;
1402 }
1403 }
1404 }
1405}
1406
1408//
1411 const G4ThreeVector& aDirection,
1412 G4ThreeVector& aNormalVector,
1413 G4bool &aConvex,
1414 G4double aPstep) const
1415{
1416 G4double minDistance;
1417
1418 if (fVoxels.GetCountOfVoxels() > 1)
1419 {
1420 minDistance = kInfinity;
1421
1422 G4ThreeVector currentPoint = aPoint;
1423 G4ThreeVector direction = aDirection.unit();
1424 G4double totalShift = 0.;
1425 vector<G4int> curVoxel(3);
1426 if (!fVoxels.Contains(aPoint)) return 0.;
1427
1428 fVoxels.GetVoxel(curVoxel, currentPoint);
1429
1430 G4double shiftBonus = kCarTolerance;
1431
1432 const vector<G4int>* old = nullptr;
1433
1434 G4int minCandidate = -1;
1435 do // Loop checking, 13.08.2015, G.Cosmo
1436 {
1437 const vector<G4int>& candidates = fVoxels.GetCandidates(curVoxel);
1438 if (old == &candidates)
1439 ++old;
1440 if (old != &candidates && candidates.size())
1441 {
1442 DistanceToOutCandidates(candidates, aPoint, direction, minDistance,
1443 aNormalVector, minCandidate);
1444 if (minDistance <= totalShift) break;
1445 }
1446
1447 G4double shift=fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
1448 if (shift == kInfinity) break;
1449
1450 totalShift += shift;
1451 if (minDistance <= totalShift) break;
1452
1453 currentPoint += direction * (shift + shiftBonus);
1454
1455 old = &candidates;
1456 }
1457 while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
1458
1459 if (minCandidate < 0)
1460 {
1461 // No intersection found
1462 minDistance = 0.;
1463 aConvex = false;
1464 Normal(aPoint, aNormalVector);
1465 }
1466 else
1467 {
1468 aConvex = (fExtremeFacets.find(fFacets[minCandidate])
1469 != fExtremeFacets.end());
1470 }
1471 }
1472 else
1473 {
1474 minDistance = DistanceToOutNoVoxels(aPoint, aDirection, aNormalVector,
1475 aConvex, aPstep);
1476 }
1477 return minDistance;
1478}
1479
1481//
1483DistanceToInCandidates(const std::vector<G4int>& candidates,
1484 const G4ThreeVector& aPoint,
1485 const G4ThreeVector& direction) const
1486{
1487 G4int candidatesCount = candidates.size();
1488 G4double dist = 0.0;
1489 G4double distFromSurface = 0.0;
1491
1492 G4double minDistance = kInfinity;
1493 for (G4int i = 0 ; i < candidatesCount; ++i)
1494 {
1495 G4int candidate = candidates[i];
1496 G4VFacet& facet = *fFacets[candidate];
1497 if (facet.Intersect(aPoint,direction,false,dist,distFromSurface,normal))
1498 {
1499 //
1500 // Set minDist to the new distance to current facet if distFromSurface is
1501 // in positive direction and point is not at surface. If the point is
1502 // within 0.5*kCarTolerance of the surface, then force distance to be
1503 // zero and leave member function immediately (for efficiency), as
1504 // proposed by & credit to Akira Okumura.
1505 //
1506 if ( (distFromSurface > kCarToleranceHalf)
1507 && (dist >= 0.0) && (dist < minDistance))
1508 {
1509 minDistance = dist;
1510 }
1511 else
1512 {
1513 if (-kCarToleranceHalf <= dist && dist <= kCarToleranceHalf)
1514 {
1515 return 0.0;
1516 }
1517 else if (distFromSurface > -kCarToleranceHalf
1518 && distFromSurface < kCarToleranceHalf)
1519 {
1520 minDistance = dist;
1521 }
1522 }
1523 }
1524 }
1525 return minDistance;
1526}
1527
1529//
1532 const G4ThreeVector& aDirection,
1533 G4double aPstep) const
1534{
1535 G4double minDistance;
1536
1537 if (fVoxels.GetCountOfVoxels() > 1)
1538 {
1539 minDistance = kInfinity;
1540 G4ThreeVector currentPoint = aPoint;
1541 G4ThreeVector direction = aDirection.unit();
1542 G4double shift = fVoxels.DistanceToFirst(currentPoint, direction);
1543 if (shift == kInfinity) return shift;
1544 G4double shiftBonus = kCarTolerance;
1545 if (shift)
1546 currentPoint += direction * (shift + shiftBonus);
1547 // if (!fVoxels.Contains(currentPoint)) return minDistance;
1548 G4double totalShift = shift;
1549
1550 // G4SurfBits exclusion; // (1/*fVoxels.GetBitsPerSlice()*/);
1551 vector<G4int> curVoxel(3);
1552
1553 fVoxels.GetVoxel(curVoxel, currentPoint);
1554 do // Loop checking, 13.08.2015, G.Cosmo
1555 {
1556 const vector<G4int>& candidates = fVoxels.GetCandidates(curVoxel);
1557 if (candidates.size())
1558 {
1559 G4double distance=DistanceToInCandidates(candidates, aPoint, direction);
1560 if (minDistance > distance) minDistance = distance;
1561 if (distance < totalShift) break;
1562 }
1563
1564 shift = fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
1565 if (shift == kInfinity /*|| shift == 0*/) break;
1566
1567 totalShift += shift;
1568 if (minDistance < totalShift) break;
1569
1570 currentPoint += direction * (shift + shiftBonus);
1571 }
1572 while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
1573 }
1574 else
1575 {
1576 minDistance = DistanceToInNoVoxels(aPoint, aDirection, aPstep);
1577 }
1578
1579 return minDistance;
1580}
1581
1583//
1584G4bool
1585G4TessellatedSolid::CompareSortedVoxel(const std::pair<G4int, G4double>& l,
1586 const std::pair<G4int, G4double>& r)
1587{
1588 return l.second < r.second;
1589}
1590
1592//
1595 G4bool simple,
1596 G4VFacet* &minFacet) const
1597{
1598 G4double minDist = kInfinity;
1599
1601 vector<pair<G4int, G4double> > voxelsSorted(size);
1602
1603 pair<G4int, G4double> info;
1604
1605 for (G4int i = 0; i < size; ++i)
1606 {
1607 const G4VoxelBox& voxelBox = fVoxels.GetVoxelBox(i);
1608
1609 G4ThreeVector pointShifted = p - voxelBox.pos;
1610 G4double safety = fVoxels.MinDistanceToBox(pointShifted, voxelBox.hlen);
1611 info.first = i;
1612 info.second = safety;
1613 voxelsSorted[i] = info;
1614 }
1615
1616 std::sort(voxelsSorted.begin(), voxelsSorted.end(),
1618
1619 for (G4int i = 0; i < size; ++i)
1620 {
1621 const pair<G4int,G4double>& inf = voxelsSorted[i];
1622 G4double dist = inf.second;
1623 if (dist > minDist) break;
1624
1625 const vector<G4int>& candidates = fVoxels.GetVoxelBoxCandidates(inf.first);
1626 G4int csize = candidates.size();
1627 for (G4int j = 0; j < csize; ++j)
1628 {
1629 G4int candidate = candidates[j];
1630 G4VFacet& facet = *fFacets[candidate];
1631 dist = simple ? facet.Distance(p,minDist)
1632 : facet.Distance(p,minDist,false);
1633 if (dist < minDist)
1634 {
1635 minDist = dist;
1636 minFacet = &facet;
1637 }
1638 }
1639 }
1640 return minDist;
1641}
1642
1644//
1646 G4bool aAccurate) const
1647{
1648#if G4SPECSDEBUG
1649 if ( Inside(p) == kInside )
1650 {
1651 std::ostringstream message;
1652 G4int oldprc = message.precision(16) ;
1653 message << "Point p is already inside!?" << G4endl
1654 << "Position:" << G4endl << G4endl
1655 << "p.x() = " << p.x()/mm << " mm" << G4endl
1656 << "p.y() = " << p.y()/mm << " mm" << G4endl
1657 << "p.z() = " << p.z()/mm << " mm" << G4endl
1658 << "DistanceToOut(p) == " << DistanceToOut(p);
1659 message.precision(oldprc) ;
1660 G4Exception("G4TriangularFacet::DistanceToIn(p)",
1661 "GeomSolids1002", JustWarning, message);
1662 }
1663#endif
1664
1665 G4double minDist;
1666
1667 if (fVoxels.GetCountOfVoxels() > 1)
1668 {
1669 if (!aAccurate)
1671
1673 {
1674 vector<G4int> startingVoxel(3);
1675 fVoxels.GetVoxel(startingVoxel, p);
1676 const vector<G4int> &candidates = fVoxels.GetCandidates(startingVoxel);
1677 if (candidates.size() == 0 && fInsides.GetNbits())
1678 {
1679 G4int index = fVoxels.GetPointIndex(p);
1680 if (fInsides[index]) return 0.;
1681 }
1682 }
1683
1684 G4VFacet* facet;
1685 minDist = MinDistanceFacet(p, true, facet);
1686 }
1687 else
1688 {
1689 minDist = kInfinity;
1690 G4int size = fFacets.size();
1691 for (G4int i = 0; i < size; ++i)
1692 {
1693 G4VFacet& facet = *fFacets[i];
1694 G4double dist = facet.Distance(p,minDist);
1695 if (dist < minDist) minDist = dist;
1696 }
1697 }
1698 return minDist;
1699}
1700
1702//
1705{
1706#if G4SPECSDEBUG
1707 if ( Inside(p) == kOutside )
1708 {
1709 std::ostringstream message;
1710 G4int oldprc = message.precision(16) ;
1711 message << "Point p is already outside!?" << G4endl
1712 << "Position:" << G4endl << G4endl
1713 << "p.x() = " << p.x()/mm << " mm" << G4endl
1714 << "p.y() = " << p.y()/mm << " mm" << G4endl
1715 << "p.z() = " << p.z()/mm << " mm" << G4endl
1716 << "DistanceToIn(p) == " << DistanceToIn(p);
1717 message.precision(oldprc) ;
1718 G4Exception("G4TriangularFacet::DistanceToOut(p)",
1719 "GeomSolids1002", JustWarning, message);
1720 }
1721#endif
1722
1723 G4double minDist;
1724
1725 if (OutsideOfExtent(p, kCarTolerance)) return 0.0;
1726
1727 if (fVoxels.GetCountOfVoxels() > 1)
1728 {
1729 G4VFacet* facet;
1730 minDist = MinDistanceFacet(p, true, facet);
1731 }
1732 else
1733 {
1734 minDist = kInfinity;
1735 G4double dist = 0.0;
1736 G4int size = fFacets.size();
1737 for (G4int i = 0; i < size; ++i)
1738 {
1739 G4VFacet& facet = *fFacets[i];
1740 dist = facet.Distance(p,minDist);
1741 if (dist < minDist) minDist = dist;
1742 }
1743 }
1744 return minDist;
1745}
1746
1748//
1749// G4GeometryType GetEntityType() const;
1750//
1751// Provide identification of the class of an object
1752//
1754{
1755 return fGeometryType;
1756}
1757
1759//
1760std::ostream &G4TessellatedSolid::StreamInfo(std::ostream &os) const
1761{
1762 os << G4endl;
1763 os << "Solid name = " << GetName() << G4endl;
1764 os << "Geometry Type = " << fGeometryType << G4endl;
1765 os << "Number of facets = " << fFacets.size() << G4endl;
1766
1767 G4int size = fFacets.size();
1768 for (G4int i = 0; i < size; ++i)
1769 {
1770 os << "FACET # = " << i + 1 << G4endl;
1771 G4VFacet &facet = *fFacets[i];
1772 facet.StreamInfo(os);
1773 }
1774 os << G4endl;
1775
1776 return os;
1777}
1778
1780//
1781// Make a clone of the object
1782//
1784{
1785 return new G4TessellatedSolid(*this);
1786}
1787
1789//
1790// EInside G4TessellatedSolid::Inside (const G4ThreeVector &p) const
1791//
1792// This method must return:
1793// * kOutside if the point at offset p is outside the shape
1794// boundaries plus kCarTolerance/2,
1795// * kSurface if the point is <= kCarTolerance/2 from a surface, or
1796// * kInside otherwise.
1797//
1799{
1800 EInside location;
1801
1802 if (fVoxels.GetCountOfVoxels() > 1)
1803 {
1804 location = InsideVoxels(aPoint);
1805 }
1806 else
1807 {
1808 location = InsideNoVoxels(aPoint);
1809 }
1810 return location;
1811}
1812
1814//
1816{
1818 Normal(p, n);
1819 return n;
1820}
1821
1823//
1824// G4double DistanceToIn(const G4ThreeVector& p)
1825//
1826// Calculate distance to nearest surface of shape from an outside point p. The
1827// distance can be an underestimate.
1828//
1830{
1831 return SafetyFromOutside(p, false);
1832}
1833
1835//
1837 const G4ThreeVector& v)const
1838{
1840#ifdef G4SPECSDEBUG
1841 if (dist < kInfinity)
1842 {
1843 if (Inside(p + dist*v) != kSurface)
1844 {
1845 std::ostringstream message;
1846 message << "Invalid response from facet in solid '" << GetName() << "',"
1847 << G4endl
1848 << "at point: " << p << "and direction: " << v;
1849 G4Exception("G4TessellatedSolid::DistanceToIn(p,v)",
1850 "GeomSolids1002", JustWarning, message);
1851 }
1852 }
1853#endif
1854 return dist;
1855}
1856
1858//
1859// G4double DistanceToOut(const G4ThreeVector& p)
1860//
1861// Calculate distance to nearest surface of shape from an inside
1862// point. The distance can be an underestimate.
1863//
1865{
1866 return SafetyFromInside(p, false);
1867}
1868
1870//
1871// G4double DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
1872// const G4bool calcNorm=false,
1873// G4bool *validNorm=0, G4ThreeVector *n=0);
1874//
1875// Return distance along the normalised vector v to the shape, from a
1876// point at an offset p inside or on the surface of the
1877// shape. Intersections with surfaces, when the point is not greater
1878// than kCarTolerance/2 from a surface, must be ignored.
1879// If calcNorm is true, then it must also set validNorm to either
1880// * true, if the solid lies entirely behind or on the exiting
1881// surface. Then it must set n to the outwards normal vector
1882// (the Magnitude of the vector is not defined).
1883// * false, if the solid does not lie entirely behind or on the
1884// exiting surface.
1885// If calcNorm is false, then validNorm and n are unused.
1886//
1888 const G4ThreeVector& v,
1889 const G4bool calcNorm,
1890 G4bool* validNorm,
1891 G4ThreeVector* norm) const
1892{
1894 G4bool valid;
1895
1896 G4double dist = DistanceToOutCore(p, v, n, valid);
1897 if (calcNorm)
1898 {
1899 *norm = n;
1900 *validNorm = valid;
1901 }
1902#ifdef G4SPECSDEBUG
1903 if (dist < kInfinity)
1904 {
1905 if (Inside(p + dist*v) != kSurface)
1906 {
1907 std::ostringstream message;
1908 message << "Invalid response from facet in solid '" << GetName() << "',"
1909 << G4endl
1910 << "at point: " << p << "and direction: " << v;
1911 G4Exception("G4TessellatedSolid::DistanceToOut(p,v,..)",
1912 "GeomSolids1002", JustWarning, message);
1913 }
1914 }
1915#endif
1916 return dist;
1917}
1918
1920//
1922{
1923 scene.AddSolid (*this);
1924}
1925
1927//
1929{
1930 G4int nVertices = fVertexList.size();
1931 G4int nFacets = fFacets.size();
1932 G4PolyhedronArbitrary* polyhedron =
1933 new G4PolyhedronArbitrary (nVertices, nFacets);
1934 for (auto v= fVertexList.cbegin(); v!=fVertexList.cend(); ++v)
1935 {
1936 polyhedron->AddVertex(*v);
1937 }
1938
1939 G4int size = fFacets.size();
1940 for (G4int i = 0; i < size; ++i)
1941 {
1942 G4VFacet* facet = fFacets[i];
1943 G4int v[4] = {0};
1944 G4int n = facet->GetNumberOfVertices();
1945 if (n > 4) n = 4;
1946 for (G4int j=0; j<n; ++j)
1947 {
1948 G4int k = facet->GetVertexIndex(j);
1949 v[j] = k+1;
1950 }
1951 polyhedron->AddFacet(v[0],v[1],v[2],v[3]);
1952 }
1953 polyhedron->SetReferences();
1954
1955 return (G4Polyhedron*) polyhedron;
1956}
1957
1959//
1960// GetPolyhedron
1961//
1963{
1964 if (fpPolyhedron == nullptr ||
1968 {
1970 delete fpPolyhedron;
1972 fRebuildPolyhedron = false;
1973 l.unlock();
1974 }
1975 return fpPolyhedron;
1976}
1977
1979//
1980// Get bounding box
1981//
1983 G4ThreeVector& pMax) const
1984{
1985 pMin = fMinExtent;
1986 pMax = fMaxExtent;
1987
1988 // Check correctness of the bounding box
1989 //
1990 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
1991 {
1992 std::ostringstream message;
1993 message << "Bad bounding box (min >= max) for solid: "
1994 << GetName() << " !"
1995 << "\npMin = " << pMin
1996 << "\npMax = " << pMax;
1997 G4Exception("G4TessellatedSolid::BoundingLimits()",
1998 "GeomMgt0001", JustWarning, message);
1999 DumpInfo();
2000 }
2001}
2002
2004//
2005// Calculate extent under transform and specified limit
2006//
2007G4bool
2009 const G4VoxelLimits& pVoxelLimit,
2010 const G4AffineTransform& pTransform,
2011 G4double& pMin, G4double& pMax) const
2012{
2013 G4ThreeVector bmin, bmax;
2014
2015 // Check bounding box (bbox)
2016 //
2017 BoundingLimits(bmin,bmax);
2018 G4BoundingEnvelope bbox(bmin,bmax);
2019
2020 // Use simple bounding-box to help in the case of complex meshes
2021 //
2022 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
2023
2024#if 0
2025 // Precise extent computation (disabled by default for this shape)
2026 //
2027 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
2028 {
2029 return (pMin < pMax) ? true : false;
2030 }
2031
2032 // The extent is calculated as cumulative extent of the pyramids
2033 // formed by facets and the center of the bounding box.
2034 //
2035 G4double eminlim = pVoxelLimit.GetMinExtent(pAxis);
2036 G4double emaxlim = pVoxelLimit.GetMaxExtent(pAxis);
2037
2038 G4ThreeVectorList base;
2039 G4ThreeVectorList apex(1);
2040 std::vector<const G4ThreeVectorList *> pyramid(2);
2041 pyramid[0] = &base;
2042 pyramid[1] = &apex;
2043 apex[0] = (bmin+bmax)*0.5;
2044
2045 // main loop along facets
2046 pMin = kInfinity;
2047 pMax = -kInfinity;
2048 for (G4int i=0; i<GetNumberOfFacets(); ++i)
2049 {
2050 G4VFacet* facet = GetFacet(i);
2051 if (std::abs((facet->GetSurfaceNormal()).dot(facet->GetVertex(0)-apex[0]))
2052 < kCarToleranceHalf) continue;
2053
2054 G4int nv = facet->GetNumberOfVertices();
2055 base.resize(nv);
2056 for (G4int k=0; k<nv; ++k) { base[k] = facet->GetVertex(k); }
2057
2058 G4double emin,emax;
2059 G4BoundingEnvelope benv(pyramid);
2060 if (!benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,emin,emax)) continue;
2061 if (emin < pMin) pMin = emin;
2062 if (emax > pMax) pMax = emax;
2063 if (eminlim > pMin && emaxlim < pMax) break; // max possible extent
2064 }
2065 return (pMin < pMax);
2066#endif
2067}
2068
2070//
2072{
2073 return fMinExtent.x();
2074}
2075
2077//
2079{
2080 return fMaxExtent.x();
2081}
2082
2084//
2086{
2087 return fMinExtent.y();
2088}
2089
2091//
2093{
2094 return fMaxExtent.y();
2095}
2096
2098//
2100{
2101 return fMinExtent.z();
2102}
2103
2105//
2107{
2108 return fMaxExtent.z();
2109}
2110
2112//
2114{
2115 return G4VisExtent (fMinExtent.x(), fMaxExtent.x(),
2116 fMinExtent.y(), fMaxExtent.y(),
2117 fMinExtent.z(), fMaxExtent.z());
2118}
2119
2121//
2123{
2124 if (fCubicVolume != 0.) return fCubicVolume;
2125
2126 // For explanation of the following algorithm see:
2127 // https://en.wikipedia.org/wiki/Polyhedron#Volume
2128 // http://wwwf.imperial.ac.uk/~rn/centroid.pdf
2129
2130 G4int size = fFacets.size();
2131 for (G4int i = 0; i < size; ++i)
2132 {
2133 G4VFacet &facet = *fFacets[i];
2134 G4double area = facet.GetArea();
2135 G4ThreeVector unit_normal = facet.GetSurfaceNormal();
2136 fCubicVolume += area * (facet.GetVertex(0).dot(unit_normal));
2137 }
2138 fCubicVolume /= 3.;
2139 return fCubicVolume;
2140}
2141
2143//
2145{
2146 if (fSurfaceArea != 0.) return fSurfaceArea;
2147
2148 G4int size = fFacets.size();
2149 for (G4int i = 0; i < size; ++i)
2150 {
2151 G4VFacet &facet = *fFacets[i];
2152 fSurfaceArea += facet.GetArea();
2153 }
2154 return fSurfaceArea;
2155}
2156
2158//
2160{
2161 // Select randomly a facet and return a random point on it
2162
2163 G4int i = (G4int) G4RandFlat::shoot(0., fFacets.size());
2164 return fFacets[i]->GetPointOnFace();
2165}
2166
2168//
2169// SetRandomVectorSet
2170//
2171// This is a set of predefined random vectors (if that isn't a contradition
2172// in terms!) used to generate rays from a user-defined point. The member
2173// function Inside uses these to determine whether the point is inside or
2174// outside of the tessellated solid. All vectors should be unit vectors.
2175//
2177{
2178 fRandir.resize(20);
2179 fRandir[0] =
2180 G4ThreeVector(-0.9577428892113370, 0.2732676269591740, 0.0897405271949221);
2181 fRandir[1] =
2182 G4ThreeVector(-0.8331264504940770,-0.5162067214954600,-0.1985722492445700);
2183 fRandir[2] =
2184 G4ThreeVector(-0.1516671651108820, 0.9666292616127460, 0.2064580868390110);
2185 fRandir[3] =
2186 G4ThreeVector( 0.6570250350323190,-0.6944539025883300, 0.2933460081893360);
2187 fRandir[4] =
2188 G4ThreeVector(-0.4820456281280320,-0.6331060000098690,-0.6056474264406270);
2189 fRandir[5] =
2190 G4ThreeVector( 0.7629032554236800 , 0.1016854697539910,-0.6384658864065180);
2191 fRandir[6] =
2192 G4ThreeVector( 0.7689540409061150, 0.5034929891988220, 0.3939600142169160);
2193 fRandir[7] =
2194 G4ThreeVector( 0.5765188359255740, 0.5997271636278330,-0.5549354566343150);
2195 fRandir[8] =
2196 G4ThreeVector( 0.6660632777862070,-0.6362809868288380, 0.3892379937580790);
2197 fRandir[9] =
2198 G4ThreeVector( 0.3824415020414780, 0.6541792713761380,-0.6525243125110690);
2199 fRandir[10] =
2200 G4ThreeVector(-0.5107726564526760, 0.6020905056811610, 0.6136760679616570);
2201 fRandir[11] =
2202 G4ThreeVector( 0.7459135439578050, 0.6618796061649330, 0.0743530220183488);
2203 fRandir[12] =
2204 G4ThreeVector( 0.1536405855311580, 0.8117477913978260,-0.5634359711967240);
2205 fRandir[13] =
2206 G4ThreeVector( 0.0744395301705579,-0.8707110101772920,-0.4861286795736560);
2207 fRandir[14] =
2208 G4ThreeVector(-0.1665874645185400, 0.6018553940549240,-0.7810369397872780);
2209 fRandir[15] =
2210 G4ThreeVector( 0.7766902003633100, 0.6014617505959970,-0.1870724331097450);
2211 fRandir[16] =
2212 G4ThreeVector(-0.8710128685847430,-0.1434320216603030,-0.4698551243971010);
2213 fRandir[17] =
2214 G4ThreeVector( 0.8901082092766820,-0.4388411398893870, 0.1229871120030100);
2215 fRandir[18] =
2216 G4ThreeVector(-0.6430417431544370,-0.3295938228697690, 0.6912779675984150);
2217 fRandir[19] =
2218 G4ThreeVector( 0.6331124368380410, 0.6306211461665000, 0.4488714875425340);
2219
2220 fMaxTries = 20;
2221}
2222
2224//
2226{
2227 G4int base = sizeof(*this);
2228 base += fVertexList.capacity() * sizeof(G4ThreeVector);
2229 base += fRandir.capacity() * sizeof(G4ThreeVector);
2230
2231 G4int limit = fFacets.size();
2232 for (G4int i = 0; i < limit; ++i)
2233 {
2234 G4VFacet& facet = *fFacets[i];
2235 base += facet.AllocatedMemory();
2236 }
2237
2238 for (auto it = fExtremeFacets.cbegin(); it != fExtremeFacets.cend(); ++it)
2239 {
2240 G4VFacet &facet = *(*it);
2241 base += facet.AllocatedMemory();
2242 }
2243 return base;
2244}
2245
2247//
2249{
2251 G4int sizeInsides = fInsides.GetNbytes();
2252 G4int sizeVoxels = fVoxels.AllocatedMemory();
2253 size += sizeInsides + sizeVoxels;
2254 return size;
2255}
2256
2257#endif
std::vector< G4ThreeVector > G4ThreeVectorList
static const G4double emax
static const G4double pos
@ JustWarning
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:35
static const G4double pMax
static const G4double pMin
static constexpr double mm
Definition: G4SIunits.hh:95
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
double z() const
Hep3Vector unit() const
double x() const
void setY(double)
double y() const
double dot(const Hep3Vector &) const
void setZ(double)
void set(double x, double y, double z)
void setX(double)
G4bool BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
void AddFacet(const G4int iv1, const G4int iv2, const G4int iv3, const G4int iv4=0)
void AddVertex(const G4ThreeVector &v)
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
unsigned int GetNbits() const
Definition: G4SurfBits.hh:92
unsigned int GetNbytes() const
Definition: G4SurfBits.hh:93
void Clear()
Definition: G4SurfBits.cc:89
void ResetBitNumber(unsigned int bitnumber)
Definition: G4SurfBits.hh:154
void SetBitNumber(unsigned int bitnumber, G4bool value=true)
Definition: G4SurfBits.hh:114
std::vector< G4ThreeVector > fRandir
virtual G4bool Normal(const G4ThreeVector &p, G4ThreeVector &n) const
G4double GetMinYExtent() const
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
void CopyObjects(const G4TessellatedSolid &s)
G4int CheckStructure() const
virtual G4Polyhedron * GetPolyhedron() const
virtual G4double GetSurfaceArea()
G4double GetMinZExtent() const
virtual std::ostream & StreamInfo(std::ostream &os) const
EInside InsideVoxels(const G4ThreeVector &aPoint) const
G4double MinDistanceFacet(const G4ThreeVector &p, G4bool simple, G4VFacet *&facet) const
G4double DistanceToOutCore(const G4ThreeVector &p, const G4ThreeVector &v, G4ThreeVector &aNormalVector, G4bool &aConvex, G4double aPstep=kInfinity) const
G4Polyhedron * fpPolyhedron
G4TessellatedSolid & operator=(const G4TessellatedSolid &right)
G4bool OutsideOfExtent(const G4ThreeVector &p, G4double tolerance=0.0) const
G4TessellatedSolid & operator+=(const G4TessellatedSolid &right)
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4bool AddFacet(G4VFacet *aFacet)
std::set< G4VFacet * > fExtremeFacets
static G4bool CompareSortedVoxel(const std::pair< G4int, G4double > &l, const std::pair< G4int, G4double > &r)
G4int GetNumberOfFacets() const
G4double GetMaxYExtent() const
EInside InsideNoVoxels(const G4ThreeVector &p) const
G4double GetMaxZExtent() const
G4double GetMaxXExtent() const
G4bool GetSolidClosed() const
virtual G4double DistanceToOut(const G4ThreeVector &p) const
G4VFacet * GetFacet(G4int i) const
virtual G4double SafetyFromInside(const G4ThreeVector &p, G4bool aAccurate=false) const
G4double DistanceToOutNoVoxels(const G4ThreeVector &p, const G4ThreeVector &v, G4ThreeVector &aNormalVector, G4bool &aConvex, G4double aPstep=kInfinity) const
G4double GetMinXExtent() const
virtual void DescribeYourselfTo(G4VGraphicsScene &scene) const
void SetSolidClosed(const G4bool t)
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
G4int SetAllUsingStack(const std::vector< G4int > &voxel, const std::vector< G4int > &max, G4bool status, G4SurfBits &checked)
virtual G4VisExtent GetExtent() const
virtual G4Polyhedron * CreatePolyhedron() const
virtual G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
G4double DistanceToInCore(const G4ThreeVector &p, const G4ThreeVector &v, G4double aPstep=kInfinity) const
G4double DistanceToInNoVoxels(const G4ThreeVector &p, const G4ThreeVector &v, G4double aPstep=kInfinity) const
std::set< G4VertexInfo, G4VertexComparator > fFacetList
virtual G4GeometryType GetEntityType() const
G4double DistanceToInCandidates(const std::vector< G4int > &candidates, const G4ThreeVector &aPoint, const G4ThreeVector &aDirection) const
virtual EInside Inside(const G4ThreeVector &p) const
G4int GetFacetIndex(const G4ThreeVector &p) const
virtual G4double SafetyFromOutside(const G4ThreeVector &p, G4bool aAccurate=false) const
void DistanceToOutCandidates(const std::vector< G4int > &candidates, const G4ThreeVector &aPoint, const G4ThreeVector &direction, G4double &minDist, G4ThreeVector &minNormal, G4int &minCandidate) const
std::vector< G4ThreeVector > fVertexList
virtual G4double GetCubicVolume()
virtual G4VSolid * Clone() const
G4GeometryType fGeometryType
virtual G4ThreeVector GetPointOnSurface() const
std::vector< G4VFacet * > fFacets
virtual void SetVertexIndex(G4int i, G4int j)=0
virtual G4int AllocatedMemory()=0
virtual G4ThreeVector GetCircumcentre() const =0
std::ostream & StreamInfo(std::ostream &os) const
Definition: G4VFacet.cc:96
G4bool IsInside(const G4ThreeVector &p) const
Definition: G4VFacet.cc:112
virtual G4ThreeVector GetSurfaceNormal() const =0
virtual G4ThreeVector GetVertex(G4int i) const =0
virtual G4double GetArea() const =0
virtual G4int GetNumberOfVertices() const =0
virtual G4int GetVertexIndex(G4int i) const =0
virtual G4VFacet * GetClone()=0
virtual G4double Distance(const G4ThreeVector &, G4double)=0
virtual void SetVertices(std::vector< G4ThreeVector > *vertices)=0
virtual G4bool IsDefined() const =0
virtual G4bool Intersect(const G4ThreeVector &, const G4ThreeVector &, const G4bool, G4double &, G4double &, G4ThreeVector &)=0
virtual void AddSolid(const G4Box &)=0
G4String GetName() const
void DumpInfo() const
G4double kCarTolerance
Definition: G4VSolid.hh:299
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:107
G4double GetMinExtent(const EAxis pAxis) const
G4double GetMaxExtent(const EAxis pAxis) const
const G4SurfBits & Empty() const
G4double DistanceToBoundingBox(const G4ThreeVector &point) const
long long GetCountOfVoxels() const
const std::vector< G4double > & GetBoundary(G4int index) const
G4bool IsEmpty(G4int index) const
G4bool UpdateCurrentVoxel(const G4ThreeVector &point, const G4ThreeVector &direction, std::vector< G4int > &curVoxel) const
void GetVoxel(std::vector< G4int > &curVoxel, const G4ThreeVector &point) const
G4int GetMaxVoxels(G4ThreeVector &ratioOfReduction)
G4double DistanceToFirst(const G4ThreeVector &point, const G4ThreeVector &direction) const
G4int GetVoxelBoxesSize() const
static G4double MinDistanceToBox(const G4ThreeVector &aPoint, const G4ThreeVector &f)
void SetMaxVoxels(G4int max)
const G4VoxelBox & GetVoxelBox(G4int i) const
G4int AllocatedMemory()
G4int GetPointIndex(const G4ThreeVector &p) const
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
const std::vector< G4int > & GetVoxelBoxCandidates(G4int i) const
G4int GetVoxelsIndex(G4int x, G4int y, G4int z) const
G4bool Contains(const G4ThreeVector &point) const
const std::vector< G4int > & GetCandidates(std::vector< G4int > &curVoxel) const
static G4int GetNumberOfRotationSteps()
EAxis
Definition: geomdefs.hh:54
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
ThreeVector shoot(const G4int Ap, const G4int Af)
T max(const T t1, const T t2)
brief Return the largest of the two arguments
const char * name(G4int ptype)
G4ThreeVector hlen
Definition: G4Voxelizer.hh:51
G4ThreeVector pos
Definition: G4Voxelizer.hh:52