Geant4  10.00.p02
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 // $Id: G4TessellatedSolid.cc 81641 2014-06-04 09:11:38Z gcosmo $
28 //
29 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 //
31 // CHANGE HISTORY
32 // --------------
33 // 12 October 2012, M Gayer, CERN, complete rewrite reducing memory
34 // requirements more than 50% and speedup by a factor of
35 // tens or more depending on the number of facets, thanks
36 // to voxelization of surface and improvements.
37 // Speedup factor of thousands for solids with number of
38 // facets in hundreds of thousands.
39 //
40 // 22 August 2011, I Hrivnacova, Orsay, fix in DistanceToOut(p) and
41 // DistanceToIn(p) to exactly compute distance from facet
42 // avoiding use of 'outgoing' flag shortcut variant.
43 //
44 // 04 August 2011, T Nikitina, CERN, added SetReferences() to
45 // CreatePolyhedron() for Visualization of Boolean Operations
46 //
47 // 12 April 2010, P R Truscott, QinetiQ, bug fixes to treat optical
48 // photon transport, in particular internal reflection
49 // at surface.
50 //
51 // 14 November 2007, P R Truscott, QinetiQ & Stan Seibert, U Texas
52 // Bug fixes to CalculateExtent
53 //
54 // 17 September 2007, P R Truscott, QinetiQ Ltd & Richard Holmberg
55 // Updated extensively prior to this date to deal with
56 // concaved tessellated surfaces, based on the algorithm
57 // of Richard Holmberg. This had been slightly modified
58 // to determine with inside the geometry by projecting
59 // random rays from the point provided. Now random rays
60 // are predefined rather than making use of random
61 // number generator at run-time.
62 //
63 // 22 November 2005, F Lei
64 // - Changed ::DescribeYourselfTo(), line 464
65 // - added GetPolyHedron()
66 //
67 // 31 October 2004, P R Truscott, QinetiQ Ltd, UK
68 // - Created.
69 //
70 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 
72 #include <iostream>
73 #include <stack>
74 #include <iostream>
75 #include <iomanip>
76 #include <fstream>
77 #include <algorithm>
78 #include <list>
79 
80 #include "G4TessellatedSolid.hh"
81 
82 #include "geomdefs.hh"
83 #include "Randomize.hh"
84 #include "G4SystemOfUnits.hh"
85 #include "G4PhysicalConstants.hh"
86 #include "G4GeometryTolerance.hh"
87 #include "G4VFacet.hh"
88 #include "G4VoxelLimits.hh"
89 #include "G4AffineTransform.hh"
90 
91 #include "G4PolyhedronArbitrary.hh"
92 #include "G4VGraphicsScene.hh"
93 #include "G4VisExtent.hh"
94 
95 using namespace std;
96 
98 //
99 // Standard contructor has blank name and defines no fFacets.
100 //
102 {
103  Initialize();
104 }
105 
107 //
108 // Alternative constructor. Simple define name and geometry type - no fFacets
109 // to detine.
110 //
112  : G4VSolid(name)
113 {
114  Initialize();
115 }
116 
118 //
119 // Fake default constructor - sets only member data and allocates memory
120 // for usage restricted to object persistency.
121 //
123 {
124  Initialize();
125  fMinExtent.set(0,0,0);
126  fMaxExtent.set(0,0,0);
127 }
128 
129 
132 {
133  DeleteObjects ();
134 }
135 
137 //
138 // Copy constructor.
139 //
141  : G4VSolid(ts), fpPolyhedron(0)
142 {
143  Initialize();
144 
145  CopyObjects(ts);
146 }
147 
149 //
150 // Assignment operator.
151 //
154 {
155  if (&ts == this) return *this;
156 
157  // Copy base class data
159 
160  DeleteObjects ();
161 
162  Initialize();
163 
164  CopyObjects (ts);
165 
166  return *this;
167 }
168 
170 //
172 {
174 
175  fpPolyhedron = 0; fCubicVolume = 0.; fSurfaceArea = 0.;
176 
177  fGeometryType = "G4TessellatedSolid";
178  fSolidClosed = false;
179 
182 
184 }
185 
187 //
189 {
190  G4int size = fFacets.size();
191  for (G4int i = 0; i < size; ++i) { delete fFacets[i]; }
192  fFacets.clear();
193  delete fpPolyhedron; fpPolyhedron = 0;
194 }
195 
197 //
199 {
200  G4ThreeVector reductionRatio;
201  G4int fmaxVoxels = fVoxels.GetMaxVoxels(reductionRatio);
202  if (fmaxVoxels < 0)
203  fVoxels.SetMaxVoxels(reductionRatio);
204  else
205  fVoxels.SetMaxVoxels(fmaxVoxels);
206 
207  G4int n = ts.GetNumberOfFacets();
208  for (G4int i = 0; i < n; ++i)
209  {
210  G4VFacet *facetClone = (ts.GetFacet(i))->GetClone();
211  AddFacet(facetClone);
212  }
213  if (ts.GetSolidClosed()) SetSolidClosed(true);
215 }
216 
218 //
219 // Add a facet to the facet list.
220 // Note that you can add, but you cannot delete.
221 //
223 {
224  // Add the facet to the vector.
225  //
226  if (fSolidClosed)
227  {
228  G4Exception("G4TessellatedSolid::AddFacet()", "GeomSolids1002",
229  JustWarning, "Attempt to add facets when solid is closed.");
230  return false;
231  }
232  else if (aFacet->IsDefined())
233  {
234  set<G4VertexInfo,G4VertexComparator>::iterator begin
235  = fFacetList.begin(), end = fFacetList.end(), pos, it;
236  G4ThreeVector p = aFacet->GetCircumcentre();
237  G4VertexInfo value;
238  value.id = fFacetList.size();
239  value.mag2 = p.x() + p.y() + p.z();
240 
241  G4bool found = false;
243  {
244  G4double kCarTolerance3 = 3 * kCarTolerance;
245  pos = fFacetList.lower_bound(value);
246 
247  it = pos;
248  while (!found && it != end)
249  {
250  G4int id = (*it).id;
251  G4VFacet *facet = fFacets[id];
252  G4ThreeVector q = facet->GetCircumcentre();
253  if ((found = (facet == aFacet))) break;
254  G4double dif = q.x() + q.y() + q.z() - value.mag2;
255  if (dif > kCarTolerance3) break;
256  it++;
257  }
258 
259  if (fFacets.size() > 1)
260  {
261  it = pos;
262  while (!found && it != begin)
263  {
264  --it;
265  G4int id = (*it).id;
266  G4VFacet *facet = fFacets[id];
267  G4ThreeVector q = facet->GetCircumcentre();
268  found = (facet == aFacet);
269  if (found) break;
270  G4double dif = value.mag2 - (q.x() + q.y() + q.z());
271  if (dif > kCarTolerance3) break;
272  }
273  }
274  }
275 
276  if (!found)
277  {
278  fFacets.push_back(aFacet);
279  fFacetList.insert(value);
280  }
281 
282  return true;
283  }
284  else
285  {
286  G4Exception("G4TessellatedSolid::AddFacet()", "GeomSolids1002",
287  JustWarning, "Attempt to add facet not properly defined.");
288  aFacet->StreamInfo(G4cout);
289  return false;
290  }
291 }
292 
294 //
295 G4int G4TessellatedSolid::SetAllUsingStack(const std::vector<G4int> &voxel,
296  const std::vector<G4int> &max,
297  G4bool status, G4SurfBits &checked)
298 {
299  vector<G4int> xyz = voxel;
300  stack<vector<G4int> > pos;
301  pos.push(xyz);
302  G4int filled = 0;
303  G4int cc = 0, nz = 0;
304 
305  vector<G4int> candidates;
306 
307  while (!pos.empty())
308  {
309  xyz = pos.top();
310  pos.pop();
311  G4int index = fVoxels.GetVoxelsIndex(xyz);
312  if (!checked[index])
313  {
314  checked.SetBitNumber(index, true);
315  cc++;
316 
317  if (fVoxels.IsEmpty(index))
318  {
319  filled++;
320 
321  fInsides.SetBitNumber(index, status);
322 
323  for (G4int i = 0; i <= 2; ++i)
324  {
325  if (xyz[i] < max[i] - 1)
326  {
327  xyz[i]++;
328  pos.push(xyz);
329  xyz[i]--;
330  }
331 
332  if (xyz[i] > 0)
333  {
334  xyz[i]--;
335  pos.push(xyz);
336  xyz[i]++;
337  }
338  }
339  }
340  else
341  {
342  nz++;
343  }
344  }
345  }
346  return filled;
347 }
348 
350 //
352 {
353  vector<G4int> voxel(3), maxVoxels(3);
354  for (G4int i = 0; i <= 2; ++i) maxVoxels[i] = fVoxels.GetBoundary(i).size();
355  G4int size = maxVoxels[0] * maxVoxels[1] * maxVoxels[2];
356 
357  G4SurfBits checked(size-1);
358  fInsides.Clear();
359  fInsides.ResetBitNumber(size-1);
360 
361  G4ThreeVector point;
362  for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
363  {
364  for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
365  {
366  for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
367  {
368  G4int index = fVoxels.GetVoxelsIndex(voxel);
369  if (!checked[index] && fVoxels.IsEmpty(index))
370  {
371  for (G4int i = 0; i <= 2; ++i) point[i] = fVoxels.GetBoundary(i)[voxel[i]];
372  G4bool inside = (G4bool) (InsideNoVoxels(point) == kInside);
373  SetAllUsingStack(voxel, maxVoxels, inside, checked);
374  }
375  else checked.SetBitNumber(index);
376  }
377  }
378  }
379 }
380 
382 //
384 {
385 #ifdef G4SPECSDEBUG
386  G4cout << "Voxelizing..." << G4endl;
387 #endif
389 
390  if (fVoxels.Empty().GetNbits())
391  {
392 #ifdef G4SPECSDEBUG
393  G4cout << "Precalculating Insides..." << G4endl;
394 #endif
396  }
397 }
398 
400 //
401 // Compute extremeFacets, i.e. find those facets that have surface
402 // planes that bound the volume.
403 // Note that this is going to reject concaved surfaces as being extreme. Also
404 // note that if the vertex is on the facet, displacement is zero, so IsInside
405 // returns true. So will this work?? Need non-equality
406 // "G4bool inside = displacement < 0.0;"
407 // or
408 // "G4bool inside = displacement <= -0.5*kCarTolerance"
409 // (Notes from PT 13/08/2007).
410 //
412 {
413  G4int size = fFacets.size();
414  for (G4int j = 0; j < size; ++j)
415  {
416  G4VFacet &facet = *fFacets[j];
417 
418  G4bool isExtreme = true;
419  G4int vsize = fVertexList.size();
420  for (G4int i=0; i < vsize; ++i)
421  {
422  if (!facet.IsInside(fVertexList[i]))
423  {
424  isExtreme = false;
425  break;
426  }
427  }
428  if (isExtreme) fExtremeFacets.insert(&facet);
429  }
430 }
431 
433 //
435 {
436  // The algorithm:
437  // we will have additional vertexListSorted, where all the items will be
438  // sorted by magnitude of vertice vector.
439  // New candidate for fVertexList - we will determine the position fo first
440  // item which would be within its magnitude - 0.5*kCarTolerance.
441  // We will go trough until we will reach > +0.5 kCarTolerance.
442  // Comparison (q-p).mag() < 0.5*kCarTolerance will be made.
443  // They can be just stored in std::vector, with custom insertion based
444  // on binary search.
445 
446  set<G4VertexInfo,G4VertexComparator> vertexListSorted;
447  set<G4VertexInfo,G4VertexComparator>::iterator begin
448  = vertexListSorted.begin(), end = vertexListSorted.end(), pos, it;
449  G4ThreeVector p;
450  G4VertexInfo value;
451 
452  fVertexList.clear();
453  G4int size = fFacets.size();
454 
455  G4double kCarTolerance24 = kCarTolerance * kCarTolerance / 4.0;
456  G4double kCarTolerance3 = 3 * kCarTolerance;
457  vector<G4int> newIndex(100);
458 
459  for (G4int k = 0; k < size; ++k)
460  {
461  G4VFacet &facet = *fFacets[k];
462  G4int max = facet.GetNumberOfVertices();
463 
464  for (G4int i = 0; i < max; ++i)
465  {
466  p = facet.GetVertex(i);
467  value.id = fVertexList.size();
468  value.mag2 = p.x() + p.y() + p.z();
469 
470  G4bool found = false;
471  G4int id = 0;
473  {
474  pos = vertexListSorted.lower_bound(value);
475  it = pos;
476  while (it != end)
477  {
478  id = (*it).id;
479  G4ThreeVector q = fVertexList[id];
480  G4double dif = (q-p).mag2();
481  found = (dif < kCarTolerance24);
482  if (found) break;
483  dif = q.x() + q.y() + q.z() - value.mag2;
484  if (dif > kCarTolerance3) break;
485  it++;
486  }
487 
488  if (!found && (fVertexList.size() > 1))
489  {
490  it = pos;
491  while (it != begin)
492  {
493  --it;
494  id = (*it).id;
495  G4ThreeVector q = fVertexList[id];
496  G4double dif = (q-p).mag2();
497  found = (dif < kCarTolerance24);
498  if (found) break;
499  dif = value.mag2 - (q.x() + q.y() + q.z());
500  if (dif > kCarTolerance3) break;
501  }
502  }
503  }
504 
505  if (!found)
506  {
507 #ifdef G4SPECSDEBUG
508  G4cout << p.x() << ":" << p.y() << ":" << p.z() << G4endl;
509  G4cout << "Adding new vertex #" << i << " of facet " << k
510  << " id " << value.id << G4endl;
511  G4cout << "===" << G4endl;
512 #endif
513  fVertexList.push_back(p);
514  vertexListSorted.insert(value);
515  begin = vertexListSorted.begin();
516  end = vertexListSorted.end();
517  newIndex[i] = value.id;
518  //
519  // Now update the maximum x, y and z limits of the volume.
520  //
521  if (value.id == 0) fMinExtent = fMaxExtent = p;
522  else
523  {
524  if (p.x() > fMaxExtent.x()) fMaxExtent.setX(p.x());
525  else if (p.x() < fMinExtent.x()) fMinExtent.setX(p.x());
526  if (p.y() > fMaxExtent.y()) fMaxExtent.setY(p.y());
527  else if (p.y() < fMinExtent.y()) fMinExtent.setY(p.y());
528  if (p.z() > fMaxExtent.z()) fMaxExtent.setZ(p.z());
529  else if (p.z() < fMinExtent.z()) fMinExtent.setZ(p.z());
530  }
531  }
532  else
533  {
534 #ifdef G4SPECSDEBUG
535  G4cout << p.x() << ":" << p.y() << ":" << p.z() << G4endl;
536  G4cout << "Vertex #" << i << " of facet " << k
537  << " found, redirecting to " << id << G4endl;
538  G4cout << "===" << G4endl;
539 #endif
540  newIndex[i] = id;
541  }
542  }
543  // only now it is possible to change vertices pointer
544  //
545  facet.SetVertices(&fVertexList);
546  for (G4int i = 0; i < max; i++)
547  facet.SetVertexIndex(i,newIndex[i]);
548  }
549  vector<G4ThreeVector>(fVertexList).swap(fVertexList);
550 
551 #ifdef G4SPECSDEBUG
552  G4double previousValue = 0;
553  for (set<G4VertexInfo,G4VertexComparator>::iterator res=
554  vertexListSorted.begin(); res!=vertexListSorted.end(); ++res)
555  {
556  G4int id = (*res).id;
557  G4ThreeVector vec = fVertexList[id];
558  G4double mvalue = vec.x() + vec.y() + vec.z();
559  if (previousValue && (previousValue - 1e-9 > mvalue))
560  G4cout << "Error in CreateVertexList: previousValue " << previousValue
561  << " is smaller than mvalue " << mvalue << G4endl;
562  previousValue = mvalue;
563  }
564 #endif
565 }
566 
568 //
570 {
572  G4int with = AllocatedMemory();
573  G4double ratio = (G4double) with / without;
574  G4cout << "G4TessellatedSolid - Allocated memory without voxel overhead "
575  << without << "; with " << with << "; ratio: " << ratio << G4endl;
576 }
577 
579 //
581 {
582  if (t)
583  {
584 #ifdef G4SPECSDEBUG
585  G4cout << "Creating vertex list..." << G4endl;
586 #endif
588 
589 #ifdef G4SPECSDEBUG
590  G4cout << "Setting extreme facets..." << G4endl;
591 #endif
593 
594 #ifdef G4SPECSDEBUG
595  G4cout << "Voxelizing..." << G4endl;
596 #endif
597  Voxelize();
598 
599 #ifdef G4SPECSDEBUG
601 #endif
602 
603  }
604  fSolidClosed = t;
605 }
606 
608 //
609 // GetSolidClosed
610 //
611 // Used to determine whether the solid is closed to adding further fFacets.
612 //
614 {
615  return fSolidClosed;
616 }
617 
619 //
620 // operator+=
621 //
622 // This operator allows the user to add two tessellated solids together, so
623 // that the solid on the left then includes all of the facets in the solid
624 // on the right. Note that copies of the facets are generated, rather than
625 // using the original facet set of the solid on the right.
626 //
629 {
630  G4int size = right.GetNumberOfFacets();
631  for (G4int i = 0; i < size; ++i)
632  AddFacet(right.GetFacet(i)->GetClone());
633 
634  return *this;
635 }
636 
638 //
639 // GetNumberOfFacets
640 //
642 {
643  return fFacets.size();
644 }
645 
647 //
649 {
650  //
651  // First the simple test - check if we're outside of the X-Y-Z extremes
652  // of the tessellated solid.
653  //
655  return kOutside;
656 
657  vector<G4int> startingVoxel(3);
658  fVoxels.GetVoxel(startingVoxel, p);
659 
660  const G4double dirTolerance = 1.0E-14;
661 
662  const vector<G4int> &startingCandidates =
663  fVoxels.GetCandidates(startingVoxel);
664  G4int limit = startingCandidates.size();
665  if (limit == 0 && fInsides.GetNbits())
666  {
667  G4int index = fVoxels.GetPointIndex(p);
668  EInside location = fInsides[index] ? kInside : kOutside;
669  return location;
670  }
671 
672  G4double minDist = kInfinity;
673 
674  for(G4int i = 0; i < limit; ++i)
675  {
676  G4int candidate = startingCandidates[i];
677  G4VFacet &facet = *fFacets[candidate];
678  G4double dist = facet.Distance(p,minDist);
679  if (dist < minDist) minDist = dist;
680  if (dist <= kCarToleranceHalf)
681  return kSurface;
682  }
683 
684  // The following is something of an adaptation of the method implemented by
685  // Rickard Holmberg augmented with information from Schneider & Eberly,
686  // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence,
687  // we're trying to determine whether we're inside the volume by projecting
688  // a few rays and determining if the first surface crossed is has a normal
689  // vector between 0 to pi/2 (out-going) or pi/2 to pi (in-going).
690  // We should also avoid rays which are nearly within the plane of the
691  // tessellated surface, and therefore produce rays randomly.
692  // For the moment, this is a bit over-engineered (belt-braces-and-ducttape).
693  //
694  G4double distOut = kInfinity;
695  G4double distIn = kInfinity;
696  G4double distO = 0.0;
697  G4double distI = 0.0;
698  G4double distFromSurfaceO = 0.0;
699  G4double distFromSurfaceI = 0.0;
700  G4ThreeVector normalO, normalI;
701  G4bool crossingO = false;
702  G4bool crossingI = false;
703  EInside location = kOutside;
704  G4int sm = 0;
705 
706  G4bool nearParallel = false;
707  do
708  {
709  // We loop until we find direction where the vector is not nearly parallel
710  // to the surface of any facet since this causes ambiguities. The usual
711  // case is that the angles should be sufficiently different, but there
712  // are 20 random directions to select from - hopefully sufficient.
713  //
714  distOut = distIn = kInfinity;
715  const G4ThreeVector &v = fRandir[sm];
716  sm++;
717  //
718  // This code could be voxelized by the same algorithm, which is used for
719  // DistanceToOut(). We will traverse through fVoxels. we will call
720  // intersect only for those, which would be candidates and was not
721  // checked before.
722  //
723  G4ThreeVector currentPoint = p;
724  G4ThreeVector direction = v.unit();
725  // G4SurfBits exclusion(fVoxels.GetBitsPerSlice());
726  vector<G4int> curVoxel(3);
727  curVoxel = startingVoxel;
728  G4double shiftBonus = kCarTolerance;
729 
730  G4bool crossed = false;
731  G4bool started = true;
732 
733  do
734  {
735  const vector<G4int> &candidates =
736  started ? startingCandidates : fVoxels.GetCandidates(curVoxel);
737  started = false;
738  if (G4int candidatesCount = candidates.size())
739  {
740  for (G4int i = 0 ; i < candidatesCount; ++i)
741  {
742  G4int candidate = candidates[i];
743  // bits.SetBitNumber(candidate);
744  G4VFacet &facet = *fFacets[candidate];
745 
746  crossingO = facet.Intersect(p,v,true,distO,distFromSurfaceO,normalO);
747  crossingI = facet.Intersect(p,v,false,distI,distFromSurfaceI,normalI);
748 
749  if (crossingO || crossingI)
750  {
751  crossed = true;
752 
753  nearParallel = (crossingO
754  && std::fabs(normalO.dot(v))<dirTolerance)
755  || (crossingI && std::fabs(normalI.dot(v))<dirTolerance);
756  if (!nearParallel)
757  {
758  if (crossingO && distO > 0.0 && distO < distOut)
759  distOut = distO;
760  if (crossingI && distI > 0.0 && distI < distIn)
761  distIn = distI;
762  }
763  else break;
764  }
765  }
766  if (nearParallel) break;
767  }
768  else
769  {
770  if (!crossed)
771  {
772  G4int index = fVoxels.GetVoxelsIndex(curVoxel);
773  G4bool inside = fInsides[index];
774  location = inside ? kInside : kOutside;
775  return location;
776  }
777  }
778 
779  G4double shift=fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
780  if (shift == kInfinity) break;
781 
782  currentPoint += direction * (shift + shiftBonus);
783  }
784  while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
785 
786  }
787  while (nearParallel && sm!=fMaxTries);
788  //
789  // Here we loop through the facets to find out if there is an intersection
790  // between the ray and that facet. The test if performed separately whether
791  // the ray is entering the facet or exiting.
792  //
793 #ifdef G4VERBOSE
794  if (sm == fMaxTries)
795  {
796  //
797  // We've run out of random vector directions. If nTries is set sufficiently
798  // low (nTries <= 0.5*maxTries) then this would indicate that there is
799  // something wrong with geometry.
800  //
801  std::ostringstream message;
802  G4int oldprc = message.precision(16);
803  message << "Cannot determine whether point is inside or outside volume!"
804  << G4endl
805  << "Solid name = " << GetName() << G4endl
806  << "Geometry Type = " << fGeometryType << G4endl
807  << "Number of facets = " << fFacets.size() << G4endl
808  << "Position:" << G4endl << G4endl
809  << "p.x() = " << p.x()/mm << " mm" << G4endl
810  << "p.y() = " << p.y()/mm << " mm" << G4endl
811  << "p.z() = " << p.z()/mm << " mm";
812  message.precision(oldprc);
813  G4Exception("G4TessellatedSolid::Inside()",
814  "GeomSolids1002", JustWarning, message);
815  }
816 #endif
817 
818  // In the next if-then-elseif G4String the logic is as follows:
819  // (1) You don't hit anything so cannot be inside volume, provided volume
820  // constructed correctly!
821  // (2) Distance to inside (ie. nearest facet such that you enter facet) is
822  // shorter than distance to outside (nearest facet such that you exit
823  // facet) - on condition of safety distance - therefore we're outside.
824  // (3) Distance to outside is shorter than distance to inside therefore
825  // we're inside.
826  //
827  if (distIn == kInfinity && distOut == kInfinity)
828  location = kOutside;
829  else if (distIn <= distOut - kCarToleranceHalf)
830  location = kOutside;
831  else if (distOut <= distIn - kCarToleranceHalf)
832  location = kInside;
833 
834  return location;
835 }
836 
838 //
840 {
841  //
842  // First the simple test - check if we're outside of the X-Y-Z extremes
843  // of the tessellated solid.
844  //
846  return kOutside;
847 
848  const G4double dirTolerance = 1.0E-14;
849 
850  G4double minDist = kInfinity;
851  //
852  // Check if we are close to a surface
853  //
854  G4int size = fFacets.size();
855  for (G4int i = 0; i < size; ++i)
856  {
857  G4VFacet &facet = *fFacets[i];
858  G4double dist = facet.Distance(p,minDist);
859  if (dist < minDist) minDist = dist;
860  if (dist <= kCarToleranceHalf)
861  {
862  return kSurface;
863  }
864  }
865  //
866  // The following is something of an adaptation of the method implemented by
867  // Rickard Holmberg augmented with information from Schneider & Eberly,
868  // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence, we're
869  // trying to determine whether we're inside the volume by projecting a few
870  // rays and determining if the first surface crossed is has a normal vector
871  // between 0 to pi/2 (out-going) or pi/2 to pi (in-going). We should also
872  // avoid rays which are nearly within the plane of the tessellated surface,
873  // and therefore produce rays randomly. For the moment, this is a bit
874  // over-engineered (belt-braces-and-ducttape).
875  //
876 #if G4SPECSDEBUG
877  G4int nTry = 7;
878 #else
879  G4int nTry = 3;
880 #endif
881  G4double distOut = kInfinity;
882  G4double distIn = kInfinity;
883  G4double distO = 0.0;
884  G4double distI = 0.0;
885  G4double distFromSurfaceO = 0.0;
886  G4double distFromSurfaceI = 0.0;
887  G4ThreeVector normalO(0.0,0.0,0.0);
888  G4ThreeVector normalI(0.0,0.0,0.0);
889  G4bool crossingO = false;
890  G4bool crossingI = false;
891  EInside location = kOutside;
892  EInside locationprime = kOutside;
893  G4int sm = 0;
894 
895  for (G4int i=0; i<nTry; ++i)
896  {
897  G4bool nearParallel = false;
898  do
899  {
900  //
901  // We loop until we find direction where the vector is not nearly parallel
902  // to the surface of any facet since this causes ambiguities. The usual
903  // case is that the angles should be sufficiently different, but there
904  // are 20 random directions to select from - hopefully sufficient.
905  //
906  distOut = distIn = kInfinity;
907  G4ThreeVector v = fRandir[sm];
908  sm++;
909  vector<G4VFacet*>::const_iterator f = fFacets.begin();
910 
911  do
912  {
913  //
914  // Here we loop through the facets to find out if there is an
915  // intersection between the ray and that facet. The test if performed
916  // separately whether the ray is entering the facet or exiting.
917  //
918  crossingO = ((*f)->Intersect(p,v,true,distO,distFromSurfaceO,normalO));
919  crossingI = ((*f)->Intersect(p,v,false,distI,distFromSurfaceI,normalI));
920  if (crossingO || crossingI)
921  {
922  nearParallel = (crossingO && std::fabs(normalO.dot(v))<dirTolerance)
923  || (crossingI && std::fabs(normalI.dot(v))<dirTolerance);
924  if (!nearParallel)
925  {
926  if (crossingO && distO > 0.0 && distO < distOut) distOut = distO;
927  if (crossingI && distI > 0.0 && distI < distIn) distIn = distI;
928  }
929  }
930  } while (!nearParallel && ++f!=fFacets.end());
931  } while (nearParallel && sm!=fMaxTries);
932 
933 #ifdef G4VERBOSE
934  if (sm == fMaxTries)
935  {
936  //
937  // We've run out of random vector directions. If nTries is set
938  // sufficiently low (nTries <= 0.5*maxTries) then this would indicate
939  // that there is something wrong with geometry.
940  //
941  std::ostringstream message;
942  G4int oldprc = message.precision(16);
943  message << "Cannot determine whether point is inside or outside volume!"
944  << G4endl
945  << "Solid name = " << GetName() << G4endl
946  << "Geometry Type = " << fGeometryType << G4endl
947  << "Number of facets = " << fFacets.size() << G4endl
948  << "Position:" << G4endl << G4endl
949  << "p.x() = " << p.x()/mm << " mm" << G4endl
950  << "p.y() = " << p.y()/mm << " mm" << G4endl
951  << "p.z() = " << p.z()/mm << " mm";
952  message.precision(oldprc);
953  G4Exception("G4TessellatedSolid::Inside()",
954  "GeomSolids1002", JustWarning, message);
955  }
956 #endif
957  //
958  // In the next if-then-elseif G4String the logic is as follows:
959  // (1) You don't hit anything so cannot be inside volume, provided volume
960  // constructed correctly!
961  // (2) Distance to inside (ie. nearest facet such that you enter facet) is
962  // shorter than distance to outside (nearest facet such that you exit
963  // facet) - on condition of safety distance - therefore we're outside.
964  // (3) Distance to outside is shorter than distance to inside therefore
965  // we're inside.
966  //
967  if (distIn == kInfinity && distOut == kInfinity)
968  locationprime = kOutside;
969  else if (distIn <= distOut - kCarToleranceHalf)
970  locationprime = kOutside;
971  else if (distOut <= distIn - kCarToleranceHalf)
972  locationprime = kInside;
973 
974  if (i == 0) location = locationprime;
975  }
976 
977  return location;
978 }
979 
981 //
982 // Return the outwards pointing unit normal of the shape for the
983 // surface closest to the point at offset p.
984 //
986  G4ThreeVector &aNormal) const
987 {
988  G4double minDist;
989  G4VFacet *facet = 0;
990 
991  if (fVoxels.GetCountOfVoxels() > 1)
992  {
993  vector<G4int> curVoxel(3);
994  fVoxels.GetVoxel(curVoxel, p);
995  const vector<G4int> &candidates = fVoxels.GetCandidates(curVoxel);
996  // fVoxels.GetCandidatesVoxelArray(p, candidates, 0);
997 
998  if (G4int limit = candidates.size())
999  {
1000  minDist = kInfinity;
1001  for(G4int i = 0 ; i < limit ; ++i)
1002  {
1003  G4int candidate = candidates[i];
1004  G4VFacet &fct = *fFacets[candidate];
1005  G4double dist = fct.Distance(p,minDist);
1006  if (dist < minDist) minDist = dist;
1007  if (dist <= kCarToleranceHalf)
1008  {
1009  aNormal = fct.GetSurfaceNormal();
1010  return true;
1011  }
1012  }
1013  }
1014  minDist = MinDistanceFacet(p, true, facet);
1015  }
1016  else
1017  {
1018  minDist = kInfinity;
1019  G4int size = fFacets.size();
1020  for (G4int i = 0; i < size; ++i)
1021  {
1022  G4VFacet &f = *fFacets[i];
1023  G4double dist = f.Distance(p, minDist);
1024  if (dist < minDist)
1025  {
1026  minDist = dist;
1027  facet = &f;
1028  }
1029  }
1030  }
1031 
1032  if (minDist != kInfinity)
1033  {
1034  if (facet) { aNormal = facet->GetSurfaceNormal(); }
1035  return minDist <= kCarToleranceHalf;
1036  }
1037  else
1038  {
1039 #ifdef G4VERBOSE
1040  std::ostringstream message;
1041  message << "Point p is not on surface !?" << G4endl
1042  << " No facets found for point: " << p << " !" << G4endl
1043  << " Returning approximated value for normal.";
1044 
1045  G4Exception("G4TessellatedSolid::SurfaceNormal(p)",
1046  "GeomSolids1002", JustWarning, message );
1047 #endif
1048  aNormal = (p.z() > 0 ? G4ThreeVector(0,0,1) : G4ThreeVector(0,0,-1));
1049  return false;
1050  }
1051 }
1052 
1054 //
1055 // G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)
1056 //
1057 // Return the distance along the normalised vector v to the shape,
1058 // from the point at offset p. If there is no intersection, return
1059 // kInfinity. The first intersection resulting from 'leaving' a
1060 // surface/volume is discarded. Hence, this is tolerant of points on
1061 // surface of shape.
1062 //
1063 G4double
1065  const G4ThreeVector &v,
1066  G4double /*aPstep*/) const
1067 {
1068  G4double minDist = kInfinity;
1069  G4double dist = 0.0;
1070  G4double distFromSurface = 0.0;
1072 
1073 #if G4SPECSDEBUG
1074  if (Inside(p) == kInside )
1075  {
1076  std::ostringstream message;
1077  G4int oldprc = message.precision(16) ;
1078  message << "Point p is already inside!?" << G4endl
1079  << "Position:" << G4endl << G4endl
1080  << " p.x() = " << p.x()/mm << " mm" << G4endl
1081  << " p.y() = " << p.y()/mm << " mm" << G4endl
1082  << " p.z() = " << p.z()/mm << " mm" << G4endl
1083  << "DistanceToOut(p) == " << DistanceToOut(p);
1084  message.precision(oldprc) ;
1085  G4Exception("G4TriangularFacet::DistanceToIn(p,v)",
1086  "GeomSolids1002", JustWarning, message);
1087  }
1088 #endif
1089 
1090  G4int size = fFacets.size();
1091  for (G4int i = 0; i < size; ++i)
1092  {
1093  G4VFacet &facet = *fFacets[i];
1094  if (facet.Intersect(p,v,false,dist,distFromSurface,normal))
1095  {
1096  //
1097  // set minDist to the new distance to current facet if distFromSurface
1098  // is in positive direction and point is not at surface. If the point is
1099  // within 0.5*kCarTolerance of the surface, then force distance to be
1100  // zero and leave member function immediately (for efficiency), as
1101  // proposed by & credit to Akira Okumura.
1102  //
1103  if (distFromSurface > kCarToleranceHalf && dist >= 0.0 && dist < minDist)
1104  {
1105  minDist = dist;
1106  }
1107  else
1108  {
1109  if (-kCarToleranceHalf <= dist && dist <= kCarToleranceHalf)
1110  {
1111  return 0.0;
1112  }
1113  else
1114  {
1115  if (distFromSurface > -kCarToleranceHalf
1116  && distFromSurface < kCarToleranceHalf)
1117  {
1118  minDist = dist;
1119  }
1120  }
1121  }
1122  }
1123  }
1124  return minDist;
1125 }
1126 
1128 //
1129 G4double
1131  const G4ThreeVector &v,
1132  G4ThreeVector &aNormalVector,
1133  G4bool &aConvex,
1134  G4double /*aPstep*/) const
1135 {
1136  G4double minDist = kInfinity;
1137  G4double dist = 0.0;
1138  G4double distFromSurface = 0.0;
1139  G4ThreeVector normal, minNormal;
1140 
1141 #if G4SPECSDEBUG
1142  if ( Inside(p) == kOutside )
1143  {
1144  std::ostringstream message;
1145  G4int oldprc = message.precision(16) ;
1146  message << "Point p is already outside!?" << G4endl
1147  << "Position:" << G4endl << G4endl
1148  << " p.x() = " << p.x()/mm << " mm" << G4endl
1149  << " p.y() = " << p.y()/mm << " mm" << G4endl
1150  << " p.z() = " << p.z()/mm << " mm" << G4endl
1151  << "DistanceToIn(p) == " << DistanceToIn(p);
1152  message.precision(oldprc) ;
1153  G4Exception("G4TriangularFacet::DistanceToOut(p)",
1154  "GeomSolids1002", JustWarning, message);
1155  }
1156 #endif
1157 
1158  G4bool isExtreme = false;
1159  G4int size = fFacets.size();
1160  for (G4int i = 0; i < size; ++i)
1161  {
1162  G4VFacet &facet = *fFacets[i];
1163  if (facet.Intersect(p,v,true,dist,distFromSurface,normal))
1164  {
1165  if (distFromSurface > 0.0 && distFromSurface <= kCarToleranceHalf &&
1167  {
1168  // We are on a surface. Return zero.
1169  aConvex = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1170  // Normal(p, aNormalVector);
1171  // aNormalVector = facet.GetSurfaceNormal();
1172  aNormalVector = normal;
1173  return 0.0;
1174  }
1175  if (dist >= 0.0 && dist < minDist)
1176  {
1177  minDist = dist;
1178  minNormal = normal;
1179  isExtreme = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1180  }
1181  }
1182  }
1183  if (minDist < kInfinity)
1184  {
1185  aNormalVector = minNormal;
1186  aConvex = isExtreme;
1187  return minDist;
1188  }
1189  else
1190  {
1191  // No intersection found
1192  aConvex = false;
1193  Normal(p, aNormalVector);
1194  return 0.0;
1195  }
1196 }
1197 
1199 //
1201 DistanceToOutCandidates(const std::vector<G4int> &candidates,
1202  const G4ThreeVector &aPoint,
1203  const G4ThreeVector &direction,
1204  G4double &minDist, G4ThreeVector &minNormal,
1205  G4int &minCandidate ) const
1206 {
1207  G4int candidatesCount = candidates.size();
1208  G4double dist = 0.0;
1209  G4double distFromSurface = 0.0;
1211 
1212  for (G4int i = 0 ; i < candidatesCount; ++i)
1213  {
1214  G4int candidate = candidates[i];
1215  G4VFacet &facet = *fFacets[candidate];
1216  if (facet.Intersect(aPoint,direction,true,dist,distFromSurface,normal))
1217  {
1218  if (distFromSurface > 0.0 && distFromSurface <= kCarToleranceHalf
1219  && facet.Distance(aPoint,kCarTolerance) <= kCarToleranceHalf)
1220  {
1221  // We are on a surface
1222  //
1223  minDist = 0.0;
1224  minNormal = normal;
1225  minCandidate = candidate;
1226  break;
1227  }
1228  if (dist >= 0.0 && dist < minDist)
1229  {
1230  minDist = dist;
1231  minNormal = normal;
1232  minCandidate = candidate;
1233  }
1234  }
1235  }
1236 }
1237 
1239 //
1240 G4double
1242  const G4ThreeVector &aDirection,
1243  G4ThreeVector &aNormalVector,
1244  G4bool &aConvex,
1245  G4double aPstep) const
1246 {
1247  G4double minDistance;
1248 
1249  if (fVoxels.GetCountOfVoxels() > 1)
1250  {
1251  minDistance = kInfinity;
1252 
1253  G4ThreeVector currentPoint = aPoint;
1254  G4ThreeVector direction = aDirection.unit();
1255  G4double totalShift = 0;
1256  vector<G4int> curVoxel(3);
1257  if (!fVoxels.Contains(aPoint)) return 0;
1258 
1259  fVoxels.GetVoxel(curVoxel, currentPoint);
1260 
1261  G4double shiftBonus = kCarTolerance;
1262 
1263  const vector<G4int> *old = 0;
1264 
1265  G4int minCandidate = -1;
1266  do
1267  {
1268  const vector<G4int> &candidates = fVoxels.GetCandidates(curVoxel);
1269  if (old == &candidates)
1270  old++;
1271  if (old != &candidates && candidates.size())
1272  {
1273  DistanceToOutCandidates(candidates, aPoint, direction, minDistance,
1274  aNormalVector, minCandidate);
1275  if (minDistance <= totalShift) break;
1276  }
1277 
1278  G4double shift=fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
1279  if (shift == kInfinity) break;
1280 
1281  totalShift += shift;
1282  if (minDistance <= totalShift) break;
1283 
1284  currentPoint += direction * (shift + shiftBonus);
1285 
1286  old = &candidates;
1287  }
1288  while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
1289 
1290  if (minCandidate < 0)
1291  {
1292  // No intersection found
1293  minDistance = 0;
1294  aConvex = false;
1295  Normal(aPoint, aNormalVector);
1296  }
1297  else
1298  {
1299  aConvex = (fExtremeFacets.find(fFacets[minCandidate])
1300  != fExtremeFacets.end());
1301  }
1302  }
1303  else
1304  {
1305  minDistance = DistanceToOutNoVoxels(aPoint, aDirection, aNormalVector,
1306  aConvex, aPstep);
1307  }
1308  return minDistance;
1309 }
1310 
1312 //
1314 DistanceToInCandidates(const std::vector<G4int> &candidates,
1315  const G4ThreeVector &aPoint,
1316  const G4ThreeVector &direction) const
1317 {
1318  G4int candidatesCount = candidates.size();
1319  G4double dist = 0.0;
1320  G4double distFromSurface = 0.0;
1322 
1323  G4double minDistance = kInfinity;
1324  for (G4int i = 0 ; i < candidatesCount; ++i)
1325  {
1326  G4int candidate = candidates[i];
1327  G4VFacet &facet = *fFacets[candidate];
1328  if (facet.Intersect(aPoint,direction,false,dist,distFromSurface,normal))
1329  {
1330  //
1331  // Set minDist to the new distance to current facet if distFromSurface is
1332  // in positive direction and point is not at surface. If the point is
1333  // within 0.5*kCarTolerance of the surface, then force distance to be
1334  // zero and leave member function immediately (for efficiency), as
1335  // proposed by & credit to Akira Okumura.
1336  //
1337  if ( (distFromSurface > kCarToleranceHalf)
1338  && (dist >= 0.0) && (dist < minDistance))
1339  {
1340  minDistance = dist;
1341  }
1342  else
1343  {
1344  if (-kCarToleranceHalf <= dist && dist <= kCarToleranceHalf)
1345  {
1346  return 0.0;
1347  }
1348  else if (distFromSurface > -kCarToleranceHalf
1349  && distFromSurface < kCarToleranceHalf)
1350  {
1351  minDistance = dist;
1352  }
1353  }
1354  }
1355  }
1356  return minDistance;
1357 }
1358 
1360 //
1361 G4double
1363  const G4ThreeVector &aDirection,
1364  G4double aPstep) const
1365 {
1366  G4double minDistance;
1367 
1368  if (fVoxels.GetCountOfVoxels() > 1)
1369  {
1370  minDistance = kInfinity;
1371  G4ThreeVector currentPoint = aPoint;
1372  G4ThreeVector direction = aDirection.unit();
1373  G4double shift = fVoxels.DistanceToFirst(currentPoint, direction);
1374  if (shift == kInfinity) return shift;
1375  G4double shiftBonus = kCarTolerance;
1376  if (shift)
1377  currentPoint += direction * (shift + shiftBonus);
1378  // if (!fVoxels.Contains(currentPoint)) return minDistance;
1379  G4double totalShift = shift;
1380 
1381  // G4SurfBits exclusion; // (1/*fVoxels.GetBitsPerSlice()*/);
1382  vector<G4int> curVoxel(3);
1383 
1384  fVoxels.GetVoxel(curVoxel, currentPoint);
1385  do
1386  {
1387  const vector<G4int> &candidates = fVoxels.GetCandidates(curVoxel);
1388  if (candidates.size())
1389  {
1390  G4double distance=DistanceToInCandidates(candidates, aPoint, direction);
1391  if (minDistance > distance) minDistance = distance;
1392  if (distance < totalShift) break;
1393  }
1394 
1395  shift = fVoxels.DistanceToNext(currentPoint, direction, curVoxel);
1396  if (shift == kInfinity /*|| shift == 0*/) break;
1397 
1398  totalShift += shift;
1399  if (minDistance < totalShift) break;
1400 
1401  currentPoint += direction * (shift + shiftBonus);
1402  }
1403  while (fVoxels.UpdateCurrentVoxel(currentPoint, direction, curVoxel));
1404  }
1405  else
1406  {
1407  minDistance = DistanceToInNoVoxels(aPoint, aDirection, aPstep);
1408  }
1409 
1410  return minDistance;
1411 }
1412 
1414 //
1415 G4bool
1416 G4TessellatedSolid::CompareSortedVoxel(const std::pair<G4int, G4double> &l,
1417  const std::pair<G4int, G4double> &r)
1418 {
1419  return l.second < r.second;
1420 }
1421 
1423 //
1424 G4double
1426  G4bool simple,
1427  G4VFacet * &minFacet) const
1428 {
1429  G4double minDist = kInfinity;
1430 
1431  G4int size = fVoxels.GetVoxelBoxesSize();
1432  vector<pair<G4int, G4double> > voxelsSorted(size);
1433 
1434  pair<G4int, G4double> info;
1435 
1436  for (G4int i = 0; i < size; ++i)
1437  {
1438  const G4VoxelBox &voxelBox = fVoxels.GetVoxelBox(i);
1439 
1440  G4ThreeVector pointShifted = p - voxelBox.pos;
1441  G4double safety = fVoxels.MinDistanceToBox(pointShifted, voxelBox.hlen);
1442  info.first = i;
1443  info.second = safety;
1444  voxelsSorted[i] = info;
1445  }
1446 
1447  std::sort(voxelsSorted.begin(), voxelsSorted.end(),
1449 
1450  for (G4int i = 0; i < size; ++i)
1451  {
1452  const pair<G4int,G4double> &inf = voxelsSorted[i];
1453  G4double dist = inf.second;
1454  if (dist > minDist) break;
1455 
1456  const vector<G4int> &candidates = fVoxels.GetVoxelBoxCandidates(inf.first);
1457  G4int csize = candidates.size();
1458  for (G4int j = 0; j < csize; ++j)
1459  {
1460  G4int candidate = candidates[j];
1461  G4VFacet &facet = *fFacets[candidate];
1462  dist = simple ? facet.Distance(p,minDist)
1463  : facet.Distance(p,minDist,false);
1464  if (dist < minDist)
1465  {
1466  minDist = dist;
1467  minFacet = &facet;
1468  }
1469  }
1470  }
1471  return minDist;
1472 }
1473 
1475 //
1477  G4bool aAccurate) const
1478 {
1479 #if G4SPECSDEBUG
1480  if ( Inside(p) == kInside )
1481  {
1482  std::ostringstream message;
1483  G4int oldprc = message.precision(16) ;
1484  message << "Point p is already inside!?" << G4endl
1485  << "Position:" << G4endl << G4endl
1486  << "p.x() = " << p.x()/mm << " mm" << G4endl
1487  << "p.y() = " << p.y()/mm << " mm" << G4endl
1488  << "p.z() = " << p.z()/mm << " mm" << G4endl
1489  << "DistanceToOut(p) == " << DistanceToOut(p);
1490  message.precision(oldprc) ;
1491  G4Exception("G4TriangularFacet::DistanceToIn(p)",
1492  "GeomSolids1002", JustWarning, message);
1493  }
1494 #endif
1495 
1496  G4double minDist;
1497 
1498  if (fVoxels.GetCountOfVoxels() > 1)
1499  {
1500  if (!aAccurate)
1501  return fVoxels.DistanceToBoundingBox(p);
1502 
1503  if (!OutsideOfExtent(p, kCarTolerance))
1504  {
1505  vector<G4int> startingVoxel(3);
1506  fVoxels.GetVoxel(startingVoxel, p);
1507  const vector<G4int> &candidates = fVoxels.GetCandidates(startingVoxel);
1508  if (candidates.size() == 0 && fInsides.GetNbits())
1509  {
1510  G4int index = fVoxels.GetPointIndex(p);
1511  if (fInsides[index]) return 0.;
1512  }
1513  }
1514 
1515  G4VFacet *facet;
1516  minDist = MinDistanceFacet(p, true, facet);
1517  }
1518  else
1519  {
1520  minDist = kInfinity;
1521  G4int size = fFacets.size();
1522  for (G4int i = 0; i < size; ++i)
1523  {
1524  G4VFacet &facet = *fFacets[i];
1525  G4double dist = facet.Distance(p,minDist);
1526  if (dist < minDist) minDist = dist;
1527  }
1528  }
1529  return minDist;
1530 }
1531 
1533 //
1534 G4double
1536 {
1537 #if G4SPECSDEBUG
1538  if ( Inside(p) == kOutside )
1539  {
1540  std::ostringstream message;
1541  G4int oldprc = message.precision(16) ;
1542  message << "Point p is already outside!?" << G4endl
1543  << "Position:" << G4endl << G4endl
1544  << "p.x() = " << p.x()/mm << " mm" << G4endl
1545  << "p.y() = " << p.y()/mm << " mm" << G4endl
1546  << "p.z() = " << p.z()/mm << " mm" << G4endl
1547  << "DistanceToIn(p) == " << DistanceToIn(p);
1548  message.precision(oldprc) ;
1549  G4Exception("G4TriangularFacet::DistanceToOut(p)",
1550  "GeomSolids1002", JustWarning, message);
1551  }
1552 #endif
1553 
1554  G4double minDist;
1555 
1556  if (OutsideOfExtent(p, kCarTolerance)) return 0.0;
1557 
1558  if (fVoxels.GetCountOfVoxels() > 1)
1559  {
1560  G4VFacet *facet;
1561  minDist = MinDistanceFacet(p, true, facet);
1562  }
1563  else
1564  {
1565  minDist = kInfinity;
1566  G4double dist = 0.0;
1567  G4int size = fFacets.size();
1568  for (G4int i = 0; i < size; ++i)
1569  {
1570  G4VFacet &facet = *fFacets[i];
1571  dist = facet.Distance(p,minDist);
1572  if (dist < minDist) minDist = dist;
1573  }
1574  }
1575  return minDist;
1576 }
1577 
1579 //
1580 // G4GeometryType GetEntityType() const;
1581 //
1582 // Provide identification of the class of an object
1583 //
1585 {
1586  return fGeometryType;
1587 }
1588 
1590 //
1591 std::ostream &G4TessellatedSolid::StreamInfo(std::ostream &os) const
1592 {
1593  os << G4endl;
1594  os << "Geometry Type = " << fGeometryType << G4endl;
1595  os << "Number of facets = " << fFacets.size() << G4endl;
1596 
1597  G4int size = fFacets.size();
1598  for (G4int i = 0; i < size; ++i)
1599  {
1600  os << "FACET # = " << i + 1 << G4endl;
1601  G4VFacet &facet = *fFacets[i];
1602  facet.StreamInfo(os);
1603  }
1604  os << G4endl;
1605 
1606  return os;
1607 }
1608 
1610 //
1611 // Make a clone of the object
1612 //
1614 {
1615  return new G4TessellatedSolid(*this);
1616 }
1617 
1619 //
1620 // EInside G4TessellatedSolid::Inside (const G4ThreeVector &p) const
1621 //
1622 // This method must return:
1623 // * kOutside if the point at offset p is outside the shape
1624 // boundaries plus kCarTolerance/2,
1625 // * kSurface if the point is <= kCarTolerance/2 from a surface, or
1626 // * kInside otherwise.
1627 //
1629 {
1630  EInside location;
1631 
1632  if (fVoxels.GetCountOfVoxels() > 1)
1633  {
1634  location = InsideVoxels(aPoint);
1635  }
1636  else
1637  {
1638  location = InsideNoVoxels(aPoint);
1639  }
1640  return location;
1641 }
1642 
1644 //
1646 {
1647  G4ThreeVector n;
1648  Normal(p, n);
1649  return n;
1650 }
1651 
1653 //
1654 // G4double DistanceToIn(const G4ThreeVector& p)
1655 //
1656 // Calculate distance to nearest surface of shape from an outside point p. The
1657 // distance can be an underestimate.
1658 //
1660 {
1661  return SafetyFromOutside(p,false);
1662 }
1663 
1665 //
1667  const G4ThreeVector& v)const
1668 {
1669  return DistanceToInCore(p,v,kInfinity);
1670 }
1671 
1673 //
1674 // G4double DistanceToOut(const G4ThreeVector& p)
1675 //
1676 // Calculate distance to nearest surface of shape from an inside
1677 // point. The distance can be an underestimate.
1678 //
1680 {
1681  return SafetyFromInside(p,false);
1682 }
1683 
1685 //
1686 // G4double DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
1687 // const G4bool calcNorm=false,
1688 // G4bool *validNorm=0, G4ThreeVector *n=0);
1689 //
1690 // Return distance along the normalised vector v to the shape, from a
1691 // point at an offset p inside or on the surface of the
1692 // shape. Intersections with surfaces, when the point is not greater
1693 // than kCarTolerance/2 from a surface, must be ignored.
1694 // If calcNorm is true, then it must also set validNorm to either
1695 // * true, if the solid lies entirely behind or on the exiting
1696 // surface. Then it must set n to the outwards normal vector
1697 // (the Magnitude of the vector is not defined).
1698 // * false, if the solid does not lie entirely behind or on the
1699 // exiting surface.
1700 // If calcNorm is false, then validNorm and n are unused.
1701 //
1703  const G4ThreeVector& v,
1704  const G4bool calcNorm,
1705  G4bool *validNorm,
1706  G4ThreeVector *norm) const
1707 {
1708  G4ThreeVector n;
1709  G4bool valid;
1710 
1711  G4double dist = DistanceToOutCore(p, v, n, valid);
1712  if (calcNorm)
1713  {
1714  *norm = n;
1715  *validNorm = valid;
1716  }
1717  return dist;
1718 }
1719 
1721 //
1723 {
1724  scene.AddSolid (*this);
1725 }
1726 
1728 //
1730 {
1731  G4int nVertices = fVertexList.size();
1732  G4int nFacets = fFacets.size();
1733  G4PolyhedronArbitrary *polyhedron =
1734  new G4PolyhedronArbitrary (nVertices, nFacets);
1735  for (G4ThreeVectorList::const_iterator v= fVertexList.begin();
1736  v!=fVertexList.end(); ++v)
1737  {
1738  polyhedron->AddVertex(*v);
1739  }
1740 
1741  G4int size = fFacets.size();
1742  for (G4int i = 0; i < size; ++i)
1743  {
1744  G4VFacet &facet = *fFacets[i];
1745  G4int v[4];
1746  G4int n = facet.GetNumberOfVertices();
1747  if (n > 4) n = 4;
1748  else if (n == 3) v[3] = 0;
1749  for (G4int j=0; j<n; ++j)
1750  {
1751  G4int k = facet.GetVertexIndex(j);
1752  v[j] = k+1;
1753  }
1754  polyhedron->AddFacet(v[0],v[1],v[2],v[3]);
1755  }
1756  polyhedron->SetReferences();
1757 
1758  return (G4Polyhedron*) polyhedron;
1759 }
1760 
1762 //
1763 // GetPolyhedron
1764 //
1766 {
1767  if (!fpPolyhedron ||
1769  fpPolyhedron->GetNumberOfRotationSteps())
1770  {
1771  delete fpPolyhedron;
1773  }
1774  return fpPolyhedron;
1775 }
1776 
1778 //
1779 // CalculateExtent
1780 //
1781 // Based on correction provided by Stan Seibert, University of Texas.
1782 //
1783 G4bool
1785  const G4VoxelLimits& pVoxelLimit,
1786  const G4AffineTransform& pTransform,
1787  G4double& pMin, G4double& pMax) const
1788 {
1789  G4ThreeVectorList transVertexList(fVertexList);
1790  G4int size = fVertexList.size();
1791 
1792  // Put solid into transformed frame
1793  for (G4int i=0; i < size; ++i)
1794  {
1795  pTransform.ApplyPointTransform(transVertexList[i]);
1796  }
1797 
1798  // Find min and max extent in each dimension
1800  G4ThreeVector maxExtent(-kInfinity, -kInfinity, -kInfinity);
1801 
1802  size = transVertexList.size();
1803  for (G4int i=0; i< size; ++i)
1804  {
1805  for (G4int axis=G4ThreeVector::X; axis < G4ThreeVector::SIZE; ++axis)
1806  {
1807  G4double coordinate = transVertexList[i][axis];
1808  if (coordinate < minExtent[axis])
1809  { minExtent[axis] = coordinate; }
1810  if (coordinate > maxExtent[axis])
1811  { maxExtent[axis] = coordinate; }
1812  }
1813  }
1814 
1815  // Check for containment and clamp to voxel boundaries
1816  for (G4int axis=G4ThreeVector::X; axis < G4ThreeVector::SIZE; ++axis)
1817  {
1818  EAxis geomAxis = kXAxis; // U geom classes use different index type
1819  switch(axis)
1820  {
1821  case G4ThreeVector::X: geomAxis = kXAxis; break;
1822  case G4ThreeVector::Y: geomAxis = kYAxis; break;
1823  case G4ThreeVector::Z: geomAxis = kZAxis; break;
1824  }
1825  G4bool isLimited = pVoxelLimit.IsLimited(geomAxis);
1826  G4double voxelMinExtent = pVoxelLimit.GetMinExtent(geomAxis);
1827  G4double voxelMaxExtent = pVoxelLimit.GetMaxExtent(geomAxis);
1828 
1829  if (isLimited)
1830  {
1831  if ( minExtent[axis] > voxelMaxExtent+kCarTolerance ||
1832  maxExtent[axis] < voxelMinExtent-kCarTolerance )
1833  {
1834  return false ;
1835  }
1836  else
1837  {
1838  if (minExtent[axis] < voxelMinExtent)
1839  {
1840  minExtent[axis] = voxelMinExtent ;
1841  }
1842  if (maxExtent[axis] > voxelMaxExtent)
1843  {
1844  maxExtent[axis] = voxelMaxExtent;
1845  }
1846  }
1847  }
1848  }
1849 
1850  // Convert pAxis into G4ThreeVector index
1851  G4int vecAxis=0;
1852  switch(pAxis)
1853  {
1854  case kXAxis: vecAxis = G4ThreeVector::X; break;
1855  case kYAxis: vecAxis = G4ThreeVector::Y; break;
1856  case kZAxis: vecAxis = G4ThreeVector::Z; break;
1857  default: break;
1858  }
1859 
1860  pMin = minExtent[vecAxis] - kCarTolerance;
1861  pMax = maxExtent[vecAxis] + kCarTolerance;
1862 
1863  return true;
1864 }
1865 
1867 //
1869 {
1870  return fMinExtent.x();
1871 }
1872 
1874 //
1876 {
1877  return fMaxExtent.x();
1878 }
1879 
1881 //
1883 {
1884  return fMinExtent.y();
1885 }
1886 
1888 //
1890 {
1891  return fMaxExtent.y();
1892 }
1893 
1895 //
1897 {
1898  return fMinExtent.z();
1899 }
1900 
1902 //
1904 {
1905  return fMaxExtent.z();
1906 }
1907 
1909 //
1911 {
1912  return G4VisExtent (fMinExtent.x(), fMaxExtent.x(), fMinExtent.y(), fMaxExtent.y(), fMinExtent.z(), fMaxExtent.z());
1913 }
1914 
1916 //
1918 {
1919  if(fCubicVolume != 0.) {;}
1921  return fCubicVolume;
1922 }
1923 
1925 //
1927 {
1928  if (fSurfaceArea != 0.) return fSurfaceArea;
1929 
1930  G4int size = fFacets.size();
1931  for (G4int i = 0; i < size; ++i)
1932  {
1933  G4VFacet &facet = *fFacets[i];
1934  fSurfaceArea += facet.GetArea();
1935  }
1936  return fSurfaceArea;
1937 }
1938 
1940 //
1942 {
1943  // Select randomly a facet and return a random point on it
1944 
1945  G4int i = (G4int) G4RandFlat::shoot(0., fFacets.size());
1946  return fFacets[i]->GetPointOnFace();
1947 }
1948 
1950 //
1951 // SetRandomVectorSet
1952 //
1953 // This is a set of predefined random vectors (if that isn't a contradition
1954 // in terms!) used to generate rays from a user-defined point. The member
1955 // function Inside uses these to determine whether the point is inside or
1956 // outside of the tessellated solid. All vectors should be unit vectors.
1957 //
1959 {
1960  fRandir.resize(20);
1961  fRandir[0] =
1962  G4ThreeVector(-0.9577428892113370, 0.2732676269591740, 0.0897405271949221);
1963  fRandir[1] =
1964  G4ThreeVector(-0.8331264504940770,-0.5162067214954600,-0.1985722492445700);
1965  fRandir[2] =
1966  G4ThreeVector(-0.1516671651108820, 0.9666292616127460, 0.2064580868390110);
1967  fRandir[3] =
1968  G4ThreeVector( 0.6570250350323190,-0.6944539025883300, 0.2933460081893360);
1969  fRandir[4] =
1970  G4ThreeVector(-0.4820456281280320,-0.6331060000098690,-0.6056474264406270);
1971  fRandir[5] =
1972  G4ThreeVector( 0.7629032554236800 , 0.1016854697539910,-0.6384658864065180);
1973  fRandir[6] =
1974  G4ThreeVector( 0.7689540409061150, 0.5034929891988220, 0.3939600142169160);
1975  fRandir[7] =
1976  G4ThreeVector( 0.5765188359255740, 0.5997271636278330,-0.5549354566343150);
1977  fRandir[8] =
1978  G4ThreeVector( 0.6660632777862070,-0.6362809868288380, 0.3892379937580790);
1979  fRandir[9] =
1980  G4ThreeVector( 0.3824415020414780, 0.6541792713761380,-0.6525243125110690);
1981  fRandir[10] =
1982  G4ThreeVector(-0.5107726564526760, 0.6020905056811610, 0.6136760679616570);
1983  fRandir[11] =
1984  G4ThreeVector( 0.7459135439578050, 0.6618796061649330, 0.0743530220183488);
1985  fRandir[12] =
1986  G4ThreeVector( 0.1536405855311580, 0.8117477913978260,-0.5634359711967240);
1987  fRandir[13] =
1988  G4ThreeVector( 0.0744395301705579,-0.8707110101772920,-0.4861286795736560);
1989  fRandir[14] =
1990  G4ThreeVector(-0.1665874645185400, 0.6018553940549240,-0.7810369397872780);
1991  fRandir[15] =
1992  G4ThreeVector( 0.7766902003633100, 0.6014617505959970,-0.1870724331097450);
1993  fRandir[16] =
1994  G4ThreeVector(-0.8710128685847430,-0.1434320216603030,-0.4698551243971010);
1995  fRandir[17] =
1996  G4ThreeVector( 0.8901082092766820,-0.4388411398893870, 0.1229871120030100);
1997  fRandir[18] =
1998  G4ThreeVector(-0.6430417431544370,-0.3295938228697690, 0.6912779675984150);
1999  fRandir[19] =
2000  G4ThreeVector( 0.6331124368380410, 0.6306211461665000, 0.4488714875425340);
2001 
2002  fMaxTries = 20;
2003 }
2004 
2006 //
2008 {
2009  G4int base = sizeof(*this);
2010  base += fVertexList.capacity() * sizeof(G4ThreeVector);
2011  base += fRandir.capacity() * sizeof(G4ThreeVector);
2012 
2013  G4int limit = fFacets.size();
2014  for (G4int i = 0; i < limit; i++)
2015  {
2016  G4VFacet &facet = *fFacets[i];
2017  base += facet.AllocatedMemory();
2018  }
2019 
2020  std::set<G4VFacet *>::const_iterator beg, end, it;
2021  beg = fExtremeFacets.begin();
2022  end = fExtremeFacets.end();
2023  for (it = beg; it != end; it++)
2024  {
2025  G4VFacet &facet = *(*it);
2026  base += facet.AllocatedMemory();
2027  }
2028  return base;
2029 }
2030 
2032 //
2034 {
2036  G4int sizeInsides = fInsides.GetNbytes();
2037  G4int sizeVoxels = fVoxels.AllocatedMemory();
2038  size += sizeInsides + sizeVoxels;
2039  return size;
2040 }
G4bool Contains(const G4ThreeVector &point) const
void ResetBitNumber(unsigned int bitnumber)
Definition: G4SurfBits.hh:161
G4String GetName() const
unsigned int GetNbits() const
Definition: G4SurfBits.hh:101
ThreeVector shoot(const G4int Ap, const G4int Af)
void Clear()
Definition: G4SurfBits.cc:92
void SetSolidClosed(const G4bool t)
EInside InsideVoxels(const G4ThreeVector &aPoint) const
G4double DistanceToInCore(const G4ThreeVector &p, const G4ThreeVector &v, G4double aPstep=kInfinity) const
static const G4double kInfinity
Definition: geomdefs.hh:42
G4double DistanceToInNoVoxels(const G4ThreeVector &p, const G4ThreeVector &v, G4double aPstep=kInfinity) const
void Voxelize(std::vector< G4VFacet * > &facets)
virtual G4double GetArea()=0
CLHEP::Hep3Vector G4ThreeVector
void DistanceToOutCandidates(const std::vector< G4int > &candidates, const G4ThreeVector &aPoint, const G4ThreeVector &direction, G4double &minDist, G4ThreeVector &minNormal, G4int &minCandidate) const
virtual void DescribeYourselfTo(G4VGraphicsScene &scene) const
void CopyObjects(const G4TessellatedSolid &s)
std::vector< G4ThreeVector > fVertexList
G4int GetCandidates(std::vector< G4int > &curVoxel, std::vector< G4int > *&candidates, std::vector< G4int > &space) const
virtual G4bool Intersect(const G4ThreeVector &, const G4ThreeVector &, const G4bool, G4double &, G4double &, G4ThreeVector &)=0
virtual G4VisExtent GetExtent() const
G4String name
Definition: TRTMaterials.hh:40
G4double DistanceToFirst(const G4ThreeVector &point, const G4ThreeVector &direction) const
G4double DistanceToBoundingBox(const G4ThreeVector &point) const
virtual G4double GetCubicVolume()
Definition: G4VSolid.cc:188
G4double GetMaxXExtent() const
virtual G4int GetNumberOfVertices() const =0
virtual G4ThreeVector GetCircumcentre() const =0
virtual G4double GetCubicVolume()
virtual G4double Distance(const G4ThreeVector &, G4double)=0
G4int GetVoxelsIndex(G4int x, G4int y, G4int z) const
G4double GetMinXExtent() const
G4double a
Definition: TRTMaterials.hh:39
std::vector< G4ThreeVector > fRandir
virtual G4double GetSurfaceArea()
static G4double MinDistanceToBox(const G4ThreeVector &aPoint, const G4ThreeVector &f)
virtual void SetVertexIndex(G4int i, G4int j)=0
G4bool UpdateCurrentVoxel(const G4ThreeVector &point, const G4ThreeVector &direction, std::vector< G4int > &curVoxel) const
G4double GetMaxZExtent() const
static G4bool CompareSortedVoxel(const std::pair< G4int, G4double > &l, const std::pair< G4int, G4double > &r)
virtual void AddSolid(const G4Box &)=0
int G4int
Definition: G4Types.hh:78
G4int GetPointIndex(const G4ThreeVector &p) const
void SetBitNumber(unsigned int bitnumber, G4bool value=true)
Definition: G4SurfBits.hh:123
G4VFacet * GetFacet(G4int i) const
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
G4bool IsEmpty(G4int index) const
virtual G4ThreeVector GetSurfaceNormal() const =0
G4double DistanceToInCandidates(const std::vector< G4int > &candidates, const G4ThreeVector &aPoint, const G4ThreeVector &aDirection) const
G4double GetMinZExtent() const
G4GLOB_DLL std::ostream G4cout
G4bool IsLimited() const
virtual G4double DistanceToOut(const G4ThreeVector &p) const
virtual G4Polyhedron * CreatePolyhedron() const
void GetVoxel(std::vector< G4int > &curVoxel, const G4ThreeVector &point) const
virtual void SetVertices(std::vector< G4ThreeVector > *vertices)=0
G4int SetAllUsingStack(const std::vector< G4int > &voxel, const std::vector< G4int > &max, G4bool status, G4SurfBits &checked)
virtual EInside Inside(const G4ThreeVector &p) const
bool G4bool
Definition: G4Types.hh:79
G4bool OutsideOfExtent(const G4ThreeVector &p, G4double tolerance=0) const
G4bool AddFacet(G4VFacet *aFacet)
G4double DistanceToNext(const G4ThreeVector &point, const G4ThreeVector &direction, const std::vector< G4int > &curVoxel) const
std::vector< G4ThreeVector > G4ThreeVectorList
Definition: G4VSolid.hh:79
void SetMaxVoxels(G4int max)
EInside InsideNoVoxels(const G4ThreeVector &p) const
G4TessellatedSolid & operator+=(const G4TessellatedSolid &right)
G4SurfaceVoxelizer fVoxels
const G4int n
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
void AddVertex(const G4ThreeVector &v)
virtual G4VSolid * Clone() const
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
std::set< G4VertexInfo, G4VertexComparator > fFacetList
virtual G4Polyhedron * GetPolyhedron() const
G4int GetNumberOfFacets() const
G4bool IsInside(const G4ThreeVector &p) const
Definition: G4VFacet.cc:114
virtual std::ostream & StreamInfo(std::ostream &os) const
virtual G4int GetVertexIndex(G4int i) const =0
G4ThreeVector pos
T max(const T t1, const T t2)
brief Return the largest of the two arguments
EInside
Definition: geomdefs.hh:58
G4double MinDistanceFacet(const G4ThreeVector &p, G4bool simple, G4VFacet *&facet) const
EAxis
Definition: geomdefs.hh:54
G4Polyhedron * fpPolyhedron
G4double DistanceToOutNoVoxels(const G4ThreeVector &p, const G4ThreeVector &v, G4ThreeVector &aNormalVector, G4bool &aConvex, G4double aPstep=kInfinity) const
virtual G4double SafetyFromInside(const G4ThreeVector &p, G4bool aAccurate=false) const
std::ostream & StreamInfo(std::ostream &os) const
Definition: G4VFacet.cc:98
void AddFacet(const G4int iv1, const G4int iv2, const G4int iv3, const G4int iv4=0)
G4GeometryType fGeometryType
std::set< G4VFacet * > fExtremeFacets
std::vector< G4VFacet * > fFacets
long long GetCountOfVoxels() const
virtual G4GeometryType GetEntityType() const
const std::vector< G4double > & GetBoundary(G4int index) const
#define G4endl
Definition: G4ios.hh:61
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:110
G4double kCarTolerance
Definition: G4VSolid.hh:305
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
const G4SurfBits & Empty() const
G4int GetMaxVoxels(G4ThreeVector &ratioOfReduction)
const std::vector< G4int > & GetVoxelBoxCandidates(G4int i) const
double G4double
Definition: G4Types.hh:76
virtual G4VFacet * GetClone()=0
virtual G4bool Normal(const G4ThreeVector &p, G4ThreeVector &n) const
G4int GetVoxelBoxesSize() const
G4double GetMaxExtent(const EAxis pAxis) const
G4ThreeVector hlen
virtual G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
virtual G4ThreeVector GetVertex(G4int i) const =0
static const double mm
Definition: G4SIunits.hh:102
const G4VoxelBox & GetVoxelBox(G4int i) const
G4double GetMaxYExtent() const
virtual G4ThreeVector GetPointOnSurface() const
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
G4double DistanceToOutCore(const G4ThreeVector &p, const G4ThreeVector &v, G4ThreeVector &aNormalVector, G4bool &aConvex, G4double aPstep=kInfinity) const
static const G4double pos
G4double GetMinExtent(const EAxis pAxis) const
virtual G4int AllocatedMemory()=0
virtual G4double SafetyFromOutside(const G4ThreeVector &p, G4bool aAccurate=false) const
G4double GetMinYExtent() const
unsigned int GetNbytes() const
Definition: G4SurfBits.hh:102
G4TessellatedSolid & operator=(const G4TessellatedSolid &right)
G4bool GetSolidClosed() const
void ApplyPointTransform(G4ThreeVector &vec) const
virtual G4bool IsDefined() const =0