Geant4  10.01.p01
UTessellatedSolid.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * This Software is part of the AIDA Unified Solids Library package *
4 // * See: https://aidasoft.web.cern.ch/USolids *
5 // ********************************************************************
6 //
7 // $Id:$
8 //
9 // --------------------------------------------------------------------
10 //
11 // UTessellatedSolid
12 //
13 // 11.07.12 Marek Gayer
14 // Created from original implementation in Geant4
15 // --------------------------------------------------------------------
16 
17 #include <iostream>
18 #include <stack>
19 #include <iostream>
20 #include <iomanip>
21 #include <fstream>
22 #include <algorithm>
23 #include <list>
24 
25 #include "UTessellatedSolid.hh"
26 
27 using namespace std;
28 
31 
33 //
34 // Standard contructor has blank name and defines no fFacets.
35 //
36 
38 {
39  fgToleranceHalf = 0.5 * fgTolerance;
40 
41  // I recommend keeping NULL here instead of 0. c++11 provides nullptr, than it could be easily replaced everywhere using simple case sensitive, whole words replacement in all files
42 
43  fCubicVolume = 0.;
44  fSurfaceArea = 0.;
45 
46  fGeometryType = "UTessellatedSolid";
47  fSolidClosed = false;
48 
49  fMinExtent.Set(UUtils::kInfinity);
50  fMaxExtent.Set(-UUtils::kInfinity);
51 
52  SetRandomVectors();
53 }
54 
56 {
57  Initialize();
58 }
59 
61 //
62 // Alternative constructor. Simple define name and geometry type - no fFacets
63 // to detine.
64 //
66  : VUSolid(name)
67 {
68  Initialize();
69 }
70 
72 //
73 // Fake default constructor - sets only member data and allocates memory
74 // for usage restricted to object persistency.
75 //
77 {
78  Initialize();
79 }
80 
83 {
84  DeleteObjects();
85 }
86 
88 //
89 // Define copy constructor.
90 //
92  : VUSolid(ss)
93 {
94  Initialize();
95 
96  CopyObjects(ss);
97 }
98 
100 //
101 // Define assignment operator.
102 //
104 {
105  if (&ss == this) return *this;
106 
107  // Copy base class data
108  VUSolid::operator=(ss);
109 
110  DeleteObjects();
111 
112  Initialize();
113 
114  CopyObjects(ss);
115 
116  return *this;
117 }
118 
120 //
122 {
123  int size = fFacets.size();
124  for (int i = 0; i < size; ++i)
125  delete fFacets[i];
126  fFacets.clear();
127 }
128 
130 //
132 {
133  UVector3 reductionRatio;
134  int fmaxVoxels = fVoxels.GetMaxVoxels(reductionRatio);
135  if (fmaxVoxels < 0)
136  fVoxels.SetMaxVoxels(reductionRatio);
137  else
138  fVoxels.SetMaxVoxels(fmaxVoxels);
139 
140  int n = ss.GetNumberOfFacets();
141  for (int i = 0; i < n; ++i)
142  {
143  VUFacet* facetClone = (ss.GetFacet(i))->GetClone();
144  AddFacet(facetClone);
145  }
146  if (ss.GetSolidClosed()) SetSolidClosed(true);
147 }
148 
149 
151 //
152 // Add a facet to the facet list. Note that you can add, but you cannot
153 // delete.
154 //
156 {
157  // Add the facet to the vector.
158  if (fSolidClosed)
159  {
160  UUtils::Exception("UTessellatedSolid::AddFacet()", "GeomSolids1002", Warning, 1, "Attempt to add facets when solid is closed.");
161  return false;
162  }
163  else if (aFacet->IsDefined())
164  {
165  set<UVertexInfo, UVertexComparator>::iterator begin = fFacetList.begin(), end = fFacetList.end(), pos, it;
166  UVector3 p = aFacet->GetCircumcentre();
167  UVertexInfo value;
168  value.id = fFacetList.size();
169  value.mag2 = p.x + p.y + p.z;
170 
171  bool found = false;
172  if (!OutsideOfExtent(p, fgTolerance))
173  {
174  double fgTolerance3 = 3 * fgTolerance;
175  pos = fFacetList.lower_bound(value);
176 
177  it = pos;
178  while (!found && it != end)
179  {
180  int id = (*it).id;
181  VUFacet* facet = fFacets[id];
182  UVector3 q = facet->GetCircumcentre();
183  found = (facet == aFacet);
184  if (found) break;
185  double dif = q.x + q.y + q.z - value.mag2;
186  if (dif > fgTolerance3) break;
187  it++;
188  }
189 
190  if (fFacets.size() > 1)
191  {
192  it = pos;
193  while (!found && it != begin)
194  {
195  --it;
196  int id = (*it).id;
197  VUFacet* facet = fFacets[id];
198  UVector3 q = facet->GetCircumcentre();
199  found = (facet == aFacet);
200  if (found) break;
201  double dif = q.x + q.y + q.z - q.Mag2();
202  if (dif > fgTolerance3) break;
203  }
204  }
205  }
206 
207  if (!found)
208  {
209  fFacets.push_back(aFacet);
210  fFacetList.insert(value);
211  }
212  return true;
213  }
214  else
215  {
216  UUtils::Exception("UTessellatedSolid::AddFacet()", "GeomSolids1002", Warning, 1, "Attempt to add facet not properly defined.");
217  aFacet->StreamInfo(cout);
218  return false;
219  }
220 }
221 
223 //
224 int UTessellatedSolid::SetAllUsingStack(const vector<int>& voxel, const vector<int>& max, bool status, UBits& checked)
225 {
226  vector<int> xyz = voxel;
227  stack<vector<int> > pos;
228  pos.push(xyz);
229  int filled = 0;
230  int cc = 0, nz = 0;
231 
232  vector<int> candidates;
233 
234  while (!pos.empty())
235  {
236  xyz = pos.top();
237  pos.pop();
238  int index = fVoxels.GetVoxelsIndex(xyz);
239  if (!checked[index])
240  {
241  checked.SetBitNumber(index, true);
242  cc++;
243 
244  if (fVoxels.IsEmpty(index))
245  {
246  filled++;
247 
248  fInsides.SetBitNumber(index, status);
249 
250  for (int i = 0; i <= 2; ++i)
251  {
252  if (xyz[i] < max[i] - 1)
253  {
254  xyz[i]++;
255  pos.push(xyz);
256  xyz[i]--;
257  }
258 
259  if (xyz[i] > 0)
260  {
261  xyz[i]--;
262  pos.push(xyz);
263  xyz[i]++;
264  }
265  }
266  }
267  else
268  {
269  nz++;
270  }
271  }
272  }
273  return filled;
274 }
275 
277 //
279 {
280  vector<int> voxel(3), maxVoxels(3);
281  for (int i = 0; i <= 2; ++i) maxVoxels[i] = fVoxels.GetBoundary(i).size();
282  int size = maxVoxels[0] * maxVoxels[1] * maxVoxels[2];
283 
284  UBits checked(size - 1);
285  fInsides.Clear();
286  fInsides.ResetBitNumber(size - 1);
287 
288  UVector3 point;
289  for (voxel[2] = 0; voxel[2] < maxVoxels[2] - 1; ++voxel[2])
290  {
291  for (voxel[1] = 0; voxel[1] < maxVoxels[1] - 1; ++voxel[1])
292  {
293  for (voxel[0] = 0; voxel[0] < maxVoxels[0] - 1; ++voxel[0])
294  {
295  int index = fVoxels.GetVoxelsIndex(voxel);
296  if (!checked[index] && fVoxels.IsEmpty(index))
297  {
298  for (int i = 0; i <= 2; ++i) point[i] = fVoxels.GetBoundary(i)[voxel[i]];
299  bool inside = (bool)(InsideNoVoxels(point) == eInside);
300  SetAllUsingStack(voxel, maxVoxels, inside, checked);
301  }
302  else checked.SetBitNumber(index);
303  }
304  }
305  }
306 }
307 
309 //
311 {
312 #ifdef USPECSDEBUG
313  cout << "Voxelizing...\n";
314 #endif
316 
317  if (fVoxels.Empty().GetNbits())
318  {
319 #ifdef USPECSDEBUG
320  cout << "Precalculating Insides...\n";
321 #endif
323  }
325 }
326 
328 //
330 {
331  //
332  // Compute extremeFacets, i.e. find those facets that have surface
333  // planes that bound the volume.
334  // Note that this is going to reject concaved surfaces as being extreme. Also
335  // note that if the vertex is on the facet, displacement is zero, so IsInside
336  // returns true. So will this work?? Need non-equality
337  // "bool inside = displacement < 0.0;"
338  // or
339  // "bool inside = displacement <= -0.5*fgTolerance"
340  // (Notes from PT 13/08/2007).
341  //
342  int size = fFacets.size();
343  int vsize = fVertexList.size();
344 
345  for (int j = 0; j < size; ++j)
346  {
347  VUFacet& facet = *fFacets[j];
348 
349  bool isExtreme = true;
350  for (int i = 0; i < vsize; ++i)
351  {
352  if (!facet.IsInside(fVertexList[i]))
353  {
354  isExtreme = false;
355  break;
356  }
357  }
358  if (isExtreme) fExtremeFacets.insert(&facet);
359  }
360 }
361 
363 //
365 {
366  // the algorithm will be:
367  // we will have additional vertexListSorted, where all the items will be sorted by magnitude of vertice vector
368  // new candidate for fVertexList - we will determine the position fo first item which would be within it'ss magnitude - 0.5*fgTolerance. we will go trough until we will reach > +0.5 fgTolerance. comparison (q-p).Mag() < 0.5*fgTolerance will be made
369  // they can be just stored in std::vector, with custom insertion based on binary search
370 
371  set<UVertexInfo, UVertexComparator> vertexListSorted;
372  set<UVertexInfo, UVertexComparator>::iterator begin = vertexListSorted.begin(), end = vertexListSorted.end(), pos, it;
373  UVector3 p;
374  UVertexInfo value;
375 
376  fVertexList.clear();
377  int size = fFacets.size();
378  vector<int> newIndex(100);
379 
380  double fgTolerance24 = fgTolerance * fgTolerance / 4.0;
381  double fgTolerance3 = 3 * fgTolerance;
382  for (int k = 0; k < size; ++k)
383  {
384  VUFacet& facet = *fFacets[k];
385  int max = facet.GetNumberOfVertices();
386 
387  for (int i = 0; i < max; ++i)
388  {
389  p = facet.GetVertex(i);
390  value.id = fVertexList.size();
391  value.mag2 = p.x + p.y + p.z;
392 
393  bool found = false;
394  int id = 0;
395  if (!OutsideOfExtent(p, fgTolerance))
396  {
397  pos = vertexListSorted.lower_bound(value);
398 
399  it = pos;
400  while (it != end)
401  {
402  id = (*it).id;
403  UVector3 q = fVertexList[id];
404  double dif = (q - p).Mag2();
405  found = (dif < fgTolerance24);
406  if (found) break;
407  dif = q.x + q.y + q.z - value.mag2;
408  if (dif > fgTolerance3) break;
409  it++;
410  }
411 
412  if (!found && fVertexList.size() > 1)
413  {
414  it = pos;
415  while (it != begin)
416  {
417  --it;
418  id = (*it).id;
419  UVector3 q = fVertexList[id];
420  double dif = (q - p).Mag2();
421  found = (dif < fgTolerance24);
422  if (found) break;
423  dif = value.mag2 - (q.x + q.y + q.z);
424  if (dif > fgTolerance) break;
425  }
426  }
427  }
428 
429  // cout << "Total checked: " << checked << " from " << fVertexList.size() << endl;
430 
431  if (!found)
432  {
433 #ifdef USPECSDEBUG
434  cout << p.x() << ":" << p.y() << ":" << p.z() << endl;
435  cout << "Adding new vertex #" << i << " of facet " << k << " id " << value.id << endl;
436  cout << "===" << endl;
437 #endif
438  fVertexList.push_back(p);
439  vertexListSorted.insert(value);
440  begin = vertexListSorted.begin();
441  end = vertexListSorted.end();
442  newIndex[i] = value.id;
443 
444  //
445  // Now update the maximum x, y and z limits of the volume.
446  //
447  if (value.id == 0) fMinExtent = fMaxExtent = p;
448  else
449  {
450  if (p.x > fMaxExtent.x) fMaxExtent.x = p.x;
451  else if (p.x < fMinExtent.x) fMinExtent.x = p.x;
452  if (p.y > fMaxExtent.y) fMaxExtent.y = p.y;
453  else if (p.y < fMinExtent.y) fMinExtent.y = p.y;
454  if (p.z > fMaxExtent.z) fMaxExtent.z = p.z;
455  else if (p.z < fMinExtent.z) fMinExtent.z = p.z;
456  }
457  }
458  else
459  {
460 #ifdef USPECSDEBUG
461  cout << p.x() << ":" << p.y() << ":" << p.z() << endl;
462  cout << "Vertex #" << i << " of facet " << k << " found, redirecting to " << id << endl;
463  cout << "===" << endl;
464 #endif
465  newIndex[i] = id;
466  }
467  }
468  // only now it is possible to change vertices pointer
469  facet.SetVertices(&fVertexList);
470  for (int i = 0; i < max; i++)
471  facet.SetVertexIndex(i, newIndex[i]);
472 
473  }
474  vector<UVector3>(fVertexList).swap(fVertexList);
475 
476 #ifdef DEBUG
477  double previousValue = 0;
478  for (res = vertexListSorted.begin(); res != vertexListSorted.end(); ++res)
479  {
480  int id = (*res).id;
481  UVector3 vec = fVertexList[id];
482  double value = abs(vec.Mag());
483  if (previousValue > value)
484  cout << "Error!" << "\n";
485  previousValue = value;
486  }
487 #endif
488 }
489 
491 //
493 {
494  int without = AllocatedMemoryWithoutVoxels();
495  int with = AllocatedMemory();
496  double ratio = (double) with / without;
497  cout << "Allocated memory without voxel overhead " << without << "; with " << with << "; ratio: " << ratio << endl;
498 }
499 
501 //
503 {
504  if (t)
505  {
507 
509 
510  Voxelize();
511 
512 #ifdef USPECSDEBUG
514 #endif
515 
516  }
517  fSolidClosed = t;
518 }
519 
521 //
522 // GetSolidClosed
523 //
524 // Used to determine whether the solid is closed to adding further fFacets.
525 //
527 {
528  return fSolidClosed;
529 }
530 
532 //
533 // operator+=
534 //
535 // This operator allows the user to add two tessellated solids together, so
536 // that the solid on the left then includes all of the facets in the solid
537 // on the right. Note that copies of the facets are generated, rather than
538 // using the original facet set of the solid on the right.
539 //
540 UTessellatedSolid& UTessellatedSolid::operator+=
542 {
543  int size = right.GetNumberOfFacets();
544  for (int i = 0; i < size; ++i)
545  AddFacet(right.GetFacet(i)->GetClone());
546 
547  return *this;
548 }
549 
550 
552 //
553 // GetNumberOfFacets
554 //
556 {
557  return fFacets.size();
558 }
559 
561 //
563 {
564  //
565  // First the simple test - check if we're outside of the X-Y-Z extremes
566  // of the tessellated solid.
567  //
569  return eOutside;
570 
571  vector<int> startingVoxel(3);
572  fVoxels.GetVoxel(startingVoxel, p);
573 
574  const vector<int>& startingCandidates = fVoxels.GetCandidates(startingVoxel);
575  int limit = startingCandidates.size();
576 // int limit = fVoxels.GetCandidatesVoxelArray(p, candidates, NULL);
577  if (limit == 0 && fInsides.GetNbits())
578  {
579 // int index = fVoxels.GetPointIndex(p);
580  int index = fVoxels.GetVoxelsIndex(startingVoxel);
581  EnumInside location = fInsides[index] ? eInside : eOutside;
582  return location;
583  }
584 
585  double minDist = UUtils::kInfinity;
586 
587  for (int i = 0; i < limit; ++i)
588  {
589  int candidate = startingCandidates[i];
590  VUFacet& facet = *fFacets[candidate];
591  double dist = facet.Distance(p, minDist);
592  if (dist < minDist) minDist = dist;
593  if (dist <= fgToleranceHalf)
594  return eSurface;
595  }
596  //
597  //
598  // The following is something of an adaptation of the method implemented by
599  // Rickard Holmberg augmented with information from Schneider & Eberly,
600  // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence, we're
601  // trying to determine whether we're inside the volume by projecting a few rays
602  // and determining if the first surface crossed is has a normal vector between
603  // 0 to pi/2 (out-going) or pi/2 to pi (in-going). We should also avoid rays
604  // which are nearly within the plane of the tessellated surface, and therefore
605  // produce rays randomly. For the moment, this is a bit over-engineered
606  // (belt-braces-and-ducttape).
607  //
608  double distOut = UUtils::kInfinity;
609  double distIn = UUtils::kInfinity;
610  double distO = 0.0;
611  double distI = 0.0;
612  double distFromSurfaceO = 0.0;
613  double distFromSurfaceI = 0.0;
614  UVector3 normalO, normalI;
615  bool crossingO = false;
616  bool crossingI = false;
618 // VUSolid::EnumInside locationprime = VUSolid::eOutside;
619  int sm = 0;
620  double shift;
621 
622  // for (int i=0; i<nTry; ++i)
623  // {
624  bool nearParallel = false;
625  do
626  {
627  //
628  //
629  // We loop until we find direction where the vector is not nearly parallel
630  // to the surface of any facet since this causes ambiguities. The usual
631  // case is that the angles should be sufficiently different, but there are 20
632  // random directions to select from - hopefully sufficient.
633  //
634  distOut = distIn = UUtils::kInfinity;
635  const UVector3& v = fRandir[sm];
636  sm++;
637 
638  // This code could be voxelized by same algorithm, which is used for DistanceToOut.
639  // we will traverse through fVoxels. we will call intersect only for those, which would be candidates
640  // and was not checked before.
641 
642  // double minDistance = UUtils::kInfinity;
643 // UVector3 currentPoint = p;
644  UVector3 direction = v.Unit();
645 // UBits exclusion(fVoxels.GetBitsPerSlice());
646  vector<int> curVoxel(3);
647  curVoxel = startingVoxel;
648 // double shiftBonus = VUSolid::Tolerance();
649 
650  bool crossed = false;
651  bool started = true;
652 // set<int> already;
653 
654  do
655  {
656  const vector<int>& candidates = started ? startingCandidates : fVoxels.GetCandidates(curVoxel);
657  started = false;
658  if (int candidatesCount = candidates.size())
659  {
660 // int candidatesCount = candidates.size();
661  for (int i = 0 ; i < candidatesCount; ++i)
662  {
663  // bits.SetBitNumber(candidate);
664  int candidate = candidates[i];
665  VUFacet& facet = *fFacets[candidate];
666 
667  crossingO = facet.Intersect(p, v, true, distO, distFromSurfaceO, normalO);
668  crossingI = facet.Intersect(p, v, false, distI, distFromSurfaceI, normalI);
669 
670  if (crossingO || crossingI)
671  {
672  crossed = true;
673 
674 // double dot = std::fabs(normalO.Dot(v));
675  nearParallel = (crossingO && std::fabs(normalO.Dot(v)) < dirTolerance) ||
676  (crossingI && std::fabs(normalI.Dot(v)) < dirTolerance);
677  if (!nearParallel)
678  {
679  if (crossingO && distO > 0.0 && distO < distOut)
680  distOut = distO;
681  if (crossingI && distI > 0.0 && distI < distIn)
682  distIn = distI;
683  }
684  else break;
685  }
686  }
687  if (nearParallel) break;
688  }
689  else
690  {
691  if (!crossed)
692  {
693  int index = fVoxels.GetVoxelsIndex(curVoxel);
694  bool inside = fInsides[index];
695  location = inside ? eInside : eOutside;
696  // cout << (inside ? "I" : "O");
697  return location;
698  }
699  }
700  shift = fVoxels.DistanceToNext(p, direction, curVoxel);
701  }
702  while (shift != UUtils::kInfinity);
703 
704  }
705  while (nearParallel && sm != fMaxTries);
706 
707  //
708  //
709  // Here we loop through the facets to find out if there is an intersection
710  // between the ray and that facet. The test if performed separately whether
711  // the ray is entering the facet or exiting.
712  //
713 
714 #ifdef UVERBOSE
715  if (sm == fMaxTries)
716  {
717  //
718  // We've run out of random vector directions. If nTries is set sufficiently
719  // low (nTries <= 0.5*maxTries) then this would indicate that there is
720  // something wrong with geometry.
721  //
722  std::ostringstream message;
723  int oldprc = message.precision(16);
724  message << "Cannot determine whether point is inside or outside volume!"
725  << endl
726  << "Solid name = " << GetName() << endl
727  << "Geometry Type = " << fGeometryType << endl
728  << "Number of facets = " << fFacets.size() << endl
729  << "Position:" << endl << endl
730  << "p.x() = " << p.x() / mm << " mm" << endl
731  << "p.y() = " << p.y() / mm << " mm" << endl
732  << "p.z() = " << p.z() / mm << " mm";
733  message.precision(oldprc);
734  UUtils::Exception("UTessellatedSolid::Inside()",
735  "GeomSolids1002", Warning, 1, message.str().c_str());
736  }
737 #endif
738  //
739  //
740  // In the next if-then-elseif string the logic is as follows:
741  // (1) You don't hit anything so cannot be inside volume, provided volume
742  // constructed correctly!
743  // (2) Distance to inside (ie. nearest facet such that you enter facet) is
744  // shorter than distance to outside (nearest facet such that you exit
745  // facet) - on condition of safety distance - therefore we're outside.
746  // (3) Distance to outside is shorter than distance to inside therefore we're
747  // inside.
748  //
749  if (distIn == UUtils::kInfinity && distOut == UUtils::kInfinity)
750  location = eOutside;
751  else if (distIn <= distOut - fgToleranceHalf)
752  location = eOutside;
753  else if (distOut <= distIn - fgToleranceHalf)
754  location = eInside;
755  // }
756 
757  // cout << " => " << (location == eInside ? "I" : "O") << endl;
758 
759  return location;
760 }
761 
763 //
764 // VUSolid::EnumInside UTessellatedSolid::Inside (const UVector3 &p) const
765 //
766 // This method must return:
767 // * kOutside if the point at offset p is outside the shape
768 // boundaries plus fgTolerance/2,
769 // * kSurface if the point is <= fgTolerance/2 from a surface, or
770 // * kInside otherwise.
771 //
773 {
774  VUSolid::EnumInside location;
775 
776  if (fVoxels.GetCountOfVoxels() > 1)
777  {
778  location = InsideVoxels(aPoint);
779  }
780  else
781  {
782  location = InsideNoVoxels(aPoint);
783  }
784 #ifdef DEBUG
785  if (location != insideNoVoxels)
786  location = insideNoVoxels; // you can place a breakpoint here
787 #endif
788  return location;
789 }
790 
792 //
794 {
795  //
796  // First the simple test - check if we're outside of the X-Y-Z extremes
797  // of the tessellated solid.
798  //
800  return eOutside;
801 
802  double minDist = UUtils::kInfinity;
803  //
804  //
805  // Check if we are close to a surface
806  //
807  int size = fFacets.size();
808  for (int i = 0; i < size; ++i)
809  {
810  VUFacet& facet = *fFacets[i];
811  double dist = facet.Distance(p, minDist);
812  if (dist < minDist) minDist = dist;
813  if (dist <= fgToleranceHalf)
814  {
815  return eSurface;
816  }
817  }
818  //
819  //
820  // The following is something of an adaptation of the method implemented by
821  // Rickard Holmberg augmented with information from Schneider & Eberly,
822  // "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence, we're
823  // trying to determine whether we're inside the volume by projecting a few rays
824  // and determining if the first surface crossed is has a normal vector between
825  // 0 to pi/2 (out-going) or pi/2 to pi (in-going). We should also avoid rays
826  // which are nearly within the plane of the tessellated surface, and therefore
827  // produce rays randomly. For the moment, this is a bit over-engineered
828  // (belt-braces-and-ducttape).
829  //
830 #if USPECSDEBUG
831  int nTry = 7;
832 #else
833  int nTry = 3;
834 #endif
835  double distOut = UUtils::kInfinity;
836  double distIn = UUtils::kInfinity;
837  double distO = 0.0;
838  double distI = 0.0;
839  double distFromSurfaceO = 0.0;
840  double distFromSurfaceI = 0.0;
841  UVector3 normalO(0.0, 0.0, 0.0);
842  UVector3 normalI(0.0, 0.0, 0.0);
843  bool crossingO = false;
844  bool crossingI = false;
846  VUSolid::EnumInside locationprime = VUSolid::eOutside;
847  int sm = 0;
848 
849  for (int i = 0; i < nTry; ++i)
850  {
851  bool nearParallel = false;
852  do
853  {
854  //
855  //
856  // We loop until we find direction where the vector is not nearly parallel
857  // to the surface of any facet since this causes ambiguities. The usual
858  // case is that the angles should be sufficiently different, but there are 20
859  // random directions to select from - hopefully sufficient.
860  //
861  distOut = distIn = UUtils::kInfinity;
862  UVector3 v = fRandir[sm];
863  sm++;
864  vector<VUFacet*>::const_iterator f = fFacets.begin();
865 
866  do
867  {
868  //
869  //
870  // Here we loop through the facets to find out if there is an intersection
871  // between the ray and that facet. The test if performed separately whether
872  // the ray is entering the facet or exiting.
873  //
874  crossingO = ((*f)->Intersect(p, v, true, distO, distFromSurfaceO, normalO));
875  crossingI = ((*f)->Intersect(p, v, false, distI, distFromSurfaceI, normalI));
876  if (crossingO || crossingI)
877  {
878  nearParallel = (crossingO && std::fabs(normalO.Dot(v)) < dirTolerance) ||
879  (crossingI && std::fabs(normalI.Dot(v)) < dirTolerance);
880  if (!nearParallel)
881  {
882  if (crossingO && distO > 0.0 && distO < distOut) distOut = distO;
883  if (crossingI && distI > 0.0 && distI < distIn) distIn = distI;
884  }
885  }
886  }
887  while (!nearParallel && ++f != fFacets.end());
888  }
889  while (nearParallel && sm != fMaxTries);
890 
891 #ifdef UVERBOSE
892  if (sm == fMaxTries)
893  {
894  //
895  //
896  // We've run out of random vector directions. If nTries is set sufficiently
897  // low (nTries <= 0.5*maxTries) then this would indicate that there is
898  // something wrong with geometry.
899  //
900  std::ostringstream message;
901  int oldprc = message.precision(16);
902  message << "Cannot determine whether point is inside or outside volume!"
903  << endl
904  << "Solid name = " << GetName() << endl
905  << "Geometry Type = " << fGeometryType << endl
906  << "Number of facets = " << fFacets.size() << endl
907  << "Position:" << endl << endl
908  << "p.x() = " << p.x() / mm << " mm" << endl
909  << "p.y() = " << p.y() / mm << " mm" << endl
910  << "p.z() = " << p.z() / mm << " mm";
911  message.precision(oldprc);
912  UUtils::Exception("UTessellatedSolid::Inside()",
913  "GeomSolids1002", Warning, 1, message.str().c_str());
914  }
915 #endif
916  //
917  //
918  // In the next if-then-elseif string the logic is as follows:
919  // (1) You don't hit anything so cannot be inside volume, provided volume
920  // constructed correctly!
921  // (2) Distance to inside (ie. nearest facet such that you enter facet) is
922  // shorter than distance to outside (nearest facet such that you exit
923  // facet) - on condition of safety distance - therefore we're outside.
924  // (3) Distance to outside is shorter than distance to inside therefore we're
925  // inside.
926  //
927  if (distIn == UUtils::kInfinity && distOut == UUtils::kInfinity)
928  locationprime = eOutside;
929  else if (distIn <= distOut - fgToleranceHalf)
930  locationprime = eOutside;
931  else if (distOut <= distIn - fgToleranceHalf)
932  locationprime = eInside;
933 
934  if (i == 0) location = locationprime;
935  }
936 
937  return location;
938 }
939 
941 //
942 // Return the outwards pointing unit normal of the shape for the
943 // surface closest to the point at offset p.
944 //
945 bool UTessellatedSolid::Normal(const UVector3& p, UVector3& aNormal) const
946 {
947  double minDist;
948  VUFacet* facet = NULL;
949 
950  if (fVoxels.GetCountOfVoxels() > 1)
951  {
952  vector<int> curVoxel(3);
953  fVoxels.GetVoxel(curVoxel, p);
954  const vector<int>& candidates = fVoxels.GetCandidates(curVoxel);
955 // fVoxels.GetCandidatesVoxelArray(p, candidates, NULL);
956 
957  if (int limit = candidates.size())
958  {
959  minDist = UUtils::kInfinity;
960  for (int i = 0 ; i < limit ; ++i)
961  {
962  int candidate = candidates[i];
963  VUFacet& f = *fFacets[candidate];
964  double dist = f.Distance(p, minDist);
965  if (dist < minDist) minDist = dist;
966  if (dist <= fgToleranceHalf)
967  {
968  aNormal = f.GetSurfaceNormal();
969  return true;
970  }
971  }
972  }
973  minDist = MinDistanceFacet(p, true, facet);
974  }
975  else
976  {
977  minDist = UUtils::kInfinity;
978  int size = fFacets.size();
979  for (int i = 0; i < size; ++i)
980  {
981  VUFacet& f = *fFacets[i];
982  double dist = f.Distance(p, minDist);
983  if (dist < minDist)
984  {
985  minDist = dist;
986  facet = &f;
987  }
988  }
989  }
990 
991  if (minDist != UUtils::kInfinity)
992  {
993  if (facet) aNormal = facet->GetSurfaceNormal();
994  return minDist <= fgToleranceHalf;
995  }
996  else
997  {
998 #ifdef UVERBOSE
999  std::ostringstream message;
1000  message << "Point p is not on surface !?" << endl
1001  << " No facets found for point: " << p << " !" << endl
1002  << " Returning approximated value for normal.";
1003 
1004  UUtils::Exception("UTessellatedSolid::SurfaceNormal(p)", "GeomSolids1002",
1005  Warning, 1, message.str().c_str());
1006 #endif
1007  aNormal = (p.z > 0 ? UVector3(0, 0, 1) : UVector3(0, 0, -1));
1008  return false;
1009  }
1010 }
1011 
1013 //
1014 // double DistanceToIn(const UVector3& p, const UVector3& v)
1015 //
1016 // Return the distance along the normalised vector v to the shape,
1017 // from the point at offset p. If there is no intersection, return
1018 // UUtils::kInfinity. The first intersection resulting from ‘leaving’ a
1019 // surface/volume is discarded. Hence, this is tolerant of points on
1020 // surface of shape.
1021 //
1023  const UVector3& v, double /*aPstep*/) const
1024 {
1025  double minDist = UUtils::kInfinity;
1026  double dist = 0.0;
1027  double distFromSurface = 0.0;
1028  UVector3 normal;
1029 
1030 #if USPECSDEBUG
1031  if (Inside(p) == kInside)
1032  {
1033  std::ostringstream message;
1034  int oldprc = message.precision(16) ;
1035  message << "Point p is already inside!?" << endl
1036  << "Position:" << endl << endl
1037  << " p.x() = " << p.x() / mm << " mm" << endl
1038  << " p.y() = " << p.y() / mm << " mm" << endl
1039  << " p.z() = " << p.z() / mm << " mm" << endl
1040  << "DistanceToOut(p) == " << DistanceToOut(p);
1041  message.precision(oldprc) ;
1042  UUtils::Exception("UTriangularFacet::DistanceToIn(p,v)", "GeomSolids1002",
1043  Warning, 1, message.str().c_str());
1044  }
1045 #endif
1046 
1047  int size = fFacets.size();
1048  for (int i = 0; i < size; ++i)
1049  {
1050  VUFacet& facet = *fFacets[i];
1051  if (facet.Intersect(p, v, false, dist, distFromSurface, normal))
1052  {
1053  //
1054  // Set minDist to the new distance to current facet if distFromSurface is in
1055  // positive direction and point is not at surface. If the point is within
1056  // 0.5*fgTolerance of the surface, then force distance to be zero and
1057  // leave member function immediately (for efficiency), as proposed by & credit
1058  // to Akira Okumura.
1059  //
1060  if (distFromSurface > fgToleranceHalf && dist >= 0.0 && dist < minDist)
1061  {
1062  minDist = dist;
1063  }
1064  if (-fgToleranceHalf <= dist && dist <= fgToleranceHalf)
1065  {
1066  return 0.0;
1067  }
1068  else if (distFromSurface > - fgToleranceHalf && distFromSurface < fgToleranceHalf) minDist = dist;
1069 
1070  }
1071 
1072  }
1073  return minDist;
1074 }
1075 
1077 //
1078 double UTessellatedSolid::DistanceToOutNoVoxels(const UVector3& p, const UVector3& v, UVector3& aNormalVector, bool& aConvex, double /*aPstep*/) const
1079 {
1080  double minDist = UUtils::kInfinity;
1081  double dist = 0.0;
1082  double distFromSurface = 0.0;
1083  UVector3 normal, minNormal;
1084 
1085 #if USPECSDEBUG
1086  if (Inside(p) == kOutside)
1087  {
1088  std::ostringstream message;
1089  int oldprc = message.precision(16) ;
1090  message << "Point p is already outside!?" << endl
1091  << "Position:" << endl << endl
1092  << " p.x() = " << p.x() / mm << " mm" << endl
1093  << " p.y() = " << p.y() / mm << " mm" << endl
1094  << " p.z() = " << p.z() / mm << " mm" << endl
1095  << "DistanceToIn(p) == " << DistanceToIn(p);
1096  message.precision(oldprc) ;
1097  UUtils::Exception("UTriangularFacet::DistanceToOut(p)", "GeomSolids1002",
1098  Warning, 1, message.str().c_str());
1099  }
1100 #endif
1101 
1102  bool isExtreme = false;
1103  int size = fFacets.size();
1104  for (int i = 0; i < size; ++i)
1105  {
1106  VUFacet& facet = *fFacets[i];
1107  if (facet.Intersect(p, v, true, dist, distFromSurface, normal))
1108  {
1109  if (distFromSurface > 0.0 && distFromSurface <= fgToleranceHalf &&
1110  facet.Distance(p, fgTolerance) <= fgToleranceHalf)
1111  {
1112  // We are on a surface. Return zero.
1113  aConvex = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1114 // Normal(p, aNormalVector);
1115 // aNormalVector = facet.GetSurfaceNormal();
1116  aNormalVector = normal;
1117  return 0.0;
1118  }
1119  if (dist >= 0.0 && dist < minDist)
1120  {
1121  minDist = dist;
1122  minNormal = normal;
1123  isExtreme = (fExtremeFacets.find(&facet) != fExtremeFacets.end());
1124  /*
1125  // FASTER IT IS NOT ...
1126  bool isExtreme = binary_search (fExtremeFacets2.begin(), fExtremeFacets2.end(), i);
1127  */
1128  }
1129  }
1130  }
1131  if (minDist < UUtils::kInfinity)
1132  {
1133  aNormalVector = minNormal;
1134  aConvex = isExtreme;
1135  return minDist;
1136  }
1137  else
1138  {
1139  // No intersection found
1140  aConvex = false;
1141  Normal(p, aNormalVector);
1142  return 0.0;
1143  }
1144 }
1145 
1147 //
1148 void UTessellatedSolid::DistanceToOutCandidates(const vector<int>& candidates, const UVector3& aPoint,
1149  const UVector3& direction, double& minDist, UVector3& minNormal, int& minCandidate /*double aPstep,*/ /* UBits & bits*/) const
1150 {
1151  int candidatesCount = candidates.size();
1152  double dist = 0.0;
1153  double distFromSurface = 0.0;
1154  UVector3 normal;
1155 
1156  for (int i = 0 ; i < candidatesCount; ++i)
1157  {
1158  int candidate = candidates[i];
1159 
1160  VUFacet& facet = *fFacets[candidate];
1161  if (facet.Intersect(aPoint, direction, true, dist, distFromSurface, normal))
1162  {
1163  if (distFromSurface > 0.0 && distFromSurface <= fgToleranceHalf &&
1164  facet.Distance(aPoint, fgTolerance) <= fgToleranceHalf)
1165  {
1166  // We are on a surface
1167  minDist = 0.0;
1168  minNormal = normal;
1169  minCandidate = candidate;
1170  break;
1171  }
1172  if (dist >= 0.0 && dist < minDist)
1173  {
1174  minDist = dist;
1175  minNormal = normal;
1176  minCandidate = candidate;
1177  }
1178  }
1179  }
1180 }
1181 
1183 //
1184 double UTessellatedSolid::DistanceToOutCore(const UVector3& aPoint, const UVector3& aDirection, UVector3& aNormalVector, bool& aConvex, double aPstep) const
1185 {
1186  double minDistance;
1187  if (fVoxels.GetCountOfVoxels() > 1)
1188  {
1189  minDistance = UUtils::kInfinity;
1190 
1191  UVector3 direction = aDirection.Unit();
1192  double shift = 0;
1193  vector<int> curVoxel(3);
1194  if (!fVoxels.Contains(aPoint)) return 0;
1195 
1196  fVoxels.GetVoxel(curVoxel, aPoint);
1197 
1198 // const vector<int> *old = NULL;
1199 
1200 // UBits exclusion (1+0*fVoxels.GetBitsPerSlice());
1201 
1202  int minCandidate = -1;
1203  do
1204  {
1205  const vector<int>& candidates = fVoxels.GetCandidates(curVoxel);
1206 // if (old == &candidates)
1207 // old++;
1208 
1209  if (/*old != &candidates &&*/ candidates.size())
1210  {
1211  DistanceToOutCandidates(candidates, aPoint, direction, minDistance, aNormalVector, minCandidate);
1212  if (minDistance <= shift) break;
1213  }
1214 
1215  shift = fVoxels.DistanceToNext(aPoint, direction, curVoxel);
1216  if (shift == UUtils::kInfinity) break;
1217 
1218 // old = &candidates;
1219  }
1220  while (minDistance > shift);
1221 
1222  if (minCandidate < 0)
1223  {
1224  // No intersection found
1225  minDistance = 0;
1226  aConvex = false;
1227  Normal(aPoint, aNormalVector);
1228  }
1229  else aConvex = (fExtremeFacets.find(fFacets[minCandidate]) != fExtremeFacets.end());
1230  }
1231  else
1232  {
1233  minDistance = DistanceToOutNoVoxels(aPoint, aDirection, aNormalVector, aConvex, aPstep);
1234  }
1235  return minDistance;
1236 }
1237 
1239 //
1240 double UTessellatedSolid::DistanceToInCandidates(const std::vector<int>& candidates, const UVector3& aPoint, const UVector3& direction /*, double aPstep, UBits & bits*/) const
1241 {
1242  int candidatesCount = candidates.size();
1243  double dist = 0.0;
1244  double distFromSurface = 0.0;
1245  UVector3 normal;
1246 
1247  double minDistance = UUtils::kInfinity;
1248  for (int i = 0 ; i < candidatesCount; ++i)
1249  {
1250  int candidate = candidates[i];
1251 // bits.SetBitNumber(candidate);
1252  VUFacet& facet = *fFacets[candidate];
1253  if (facet.Intersect(aPoint, direction, false, dist, distFromSurface, normal))
1254  {
1255  //
1256  // Set minDist to the new distance to current facet if distFromSurface is in
1257  // positive direction and point is not at surface. If the point is within
1258  // 0.5*fgTolerance of the surface, then force distance to be zero and
1259  // leave member function immediately (for efficiency), as proposed by & credit
1260  // to Akira Okumura.
1261  //
1262  if (distFromSurface > fgToleranceHalf && dist >= 0.0 && dist < minDistance)
1263  {
1264  minDistance = dist;
1265  }
1266  if (-fgToleranceHalf <= dist && dist <= fgToleranceHalf)
1267  {
1268  return 0.0;
1269  }
1270  else
1271  {
1272  if (distFromSurface > - fgToleranceHalf && distFromSurface < fgToleranceHalf) minDistance = dist;
1273 
1274  }
1275 
1276  }
1277  }
1278  return minDistance;
1279 }
1280 
1282 //
1283 double UTessellatedSolid::DistanceToInCore(const UVector3& aPoint, const UVector3& aDirection, double aPstep) const
1284 {
1285  double minDistance, distance;
1286 
1287  if (fVoxels.GetCountOfVoxels() > 1)
1288  {
1289  minDistance = UUtils::kInfinity;
1290  UVector3 currentPoint = aPoint;
1291  UVector3 direction = aDirection.Unit();
1292  double shift = fVoxels.DistanceToFirst(currentPoint, direction);
1293  if (shift == UUtils::kInfinity) return shift;
1294  if (shift) currentPoint += direction * shift;
1295  // if (!fVoxels.Contains(currentPoint))
1296  // return minDistance;
1297 
1298 // UBits exclusion; // (1/*fVoxels.GetBitsPerSlice()*/);
1299  vector<int> curVoxel(3);
1300 
1301  fVoxels.GetVoxel(curVoxel, currentPoint);
1302  do
1303  {
1304  const vector<int>& candidates = fVoxels.GetCandidates(curVoxel);
1305  if (candidates.size())
1306  {
1307  distance = DistanceToInCandidates(candidates, aPoint, direction);
1308  if (minDistance > distance) minDistance = distance;
1309  if (distance < shift) break;
1310  }
1311  shift = fVoxels.DistanceToNext(aPoint, direction, curVoxel);
1312  }
1313  while (minDistance > shift);
1314 
1315 #ifdef DEBUG
1316  if (fabs(minDistance - distanceToInNoVoxels) > VUSolid::Tolerance())
1317  {
1318  VUSolid::EnumInside location = Inside(aPoint);
1319  minDistance = distanceToInNoVoxels; // you can place a breakpoint here
1320  }
1321 #endif
1322 // if (minDistance != UUtils::kInfinity) minDistance += shift;
1323  }
1324  else
1325  {
1326  minDistance = DistanceToInNoVoxels(aPoint, aDirection, aPstep);
1327  }
1328 
1329  return minDistance;
1330 }
1331 
1333 //
1334 bool UTessellatedSolid::CompareSortedVoxel(const std::pair<int, double>& l,
1335  const std::pair<int, double>& r)
1336 {
1337  return l.second < r.second;
1338 }
1339 
1341 //
1342 // double DistanceToIn(const UVector3& p)
1343 //
1344 // Calculate distance to nearest surface of shape from an outside point p. The
1345 // distance can be an underestimate.
1346 //
1347 double UTessellatedSolid::MinDistanceFacet(const UVector3& p, bool simple, VUFacet*& minFacet) const
1348 {
1349  double minDist = UUtils::kInfinity;
1350 
1351  int size = fVoxels.GetVoxelBoxesSize();
1352  vector<pair<int, double> > voxelsSorted(size);
1353 
1354  pair<int, double> info;
1355 
1356  for (int i = 0; i < size; ++i)
1357  {
1358  const UVoxelBox& voxelBox = fVoxels.GetVoxelBox(i);
1359 
1360  UVector3 pointShifted = p - voxelBox.pos;
1361  double safety = fVoxels.MinDistanceToBox(pointShifted, voxelBox.hlen);
1362  info.first = i;
1363  info.second = safety;
1364  voxelsSorted[i] = info;
1365  }
1366 
1367  std::sort(voxelsSorted.begin(), voxelsSorted.end(), &UTessellatedSolid::CompareSortedVoxel);
1368 
1369  for (int i = 0; i < size; ++i)
1370  {
1371  const pair<int, double>& inf = voxelsSorted[i];
1372 // const UVoxelBox &voxelBox = fVoxels.fVoxelBoxes[inf.first];
1373  double dist = inf.second;
1374  if (dist > minDist) break;
1375 
1376  const vector<int>& candidates = fVoxels.GetVoxelBoxCandidates(inf.first);
1377  int csize = candidates.size();
1378  for (int j = 0; j < csize; ++j)
1379  {
1380  int candidate = candidates[j];
1381  VUFacet& facet = *fFacets[candidate];
1382  dist = simple ? facet.Distance(p, minDist) : facet.Distance(p, minDist, false);
1383  if (dist < minDist)
1384  {
1385  minDist = dist;
1386  minFacet = &facet;
1387  }
1388  }
1389  }
1390  return minDist;
1391 }
1392 
1394 //
1395 double UTessellatedSolid::SafetyFromOutside(const UVector3& p, bool aAccurate) const
1396 {
1397 #if UDEBUG
1398  if (Inside(p) == kInside)
1399  {
1400  std::ostringstream message;
1401  int oldprc = message.precision(16) ;
1402  message << "Point p is already inside!?" << endl
1403  << "Position:" << endl << endl
1404  << "p.x() = " << p.x() / mm << " mm" << endl
1405  << "p.y() = " << p.y() / mm << " mm" << endl
1406  << "p.z() = " << p.z() / mm << " mm" << endl
1407  << "DistanceToOut(p) == " << DistanceToOut(p);
1408  message.precision(oldprc) ;
1409  UUtils::Exception("UTriangularFacet::DistanceToIn(p)", "GeomSolids1002",
1410  Warning, 1, message.str().c_str());
1411  }
1412 #endif
1413 
1414  double minDist;
1415 
1416  if (!aAccurate) return fVoxels.SafetyToBoundingBox(p);
1417 
1418  if (fVoxels.GetCountOfVoxels() > 1)
1419  {
1420  if (!OutsideOfExtent(p, fgTolerance))
1421  {
1422  vector<int> startingVoxel(3);
1423  fVoxels.GetVoxel(startingVoxel, p);
1424  const vector<int>& candidates = fVoxels.GetCandidates(startingVoxel);
1425 // int limit = fVoxels.GetCandidatesVoxelArray(p, candidates, NULL);
1426  if (candidates.size() == 0 && fInsides.GetNbits())
1427  {
1428 // int index = fVoxels.GetPointIndex(p);
1429  int index = fVoxels.GetVoxelsIndex(startingVoxel);
1430  if (fInsides[index]) return 0.;
1431  }
1432  }
1433 
1434  VUFacet* facet;
1435  minDist = MinDistanceFacet(p, true, facet);
1436  }
1437  else
1438  {
1439  minDist = UUtils::kInfinity;
1440  int size = fFacets.size();
1441  for (int i = 0; i < size; ++i)
1442  {
1443  VUFacet& facet = *fFacets[i];
1444  double dist = facet.Distance(p, minDist);
1445  if (dist < minDist) minDist = dist;
1446  }
1447  }
1448  return minDist;
1449 }
1450 
1452 //
1453 // double SafetyFrominside(const UVector3& p)
1454 //
1455 // Calculate distance to nearest surface of shape from an inside
1456 // point. The distance can be an underestimate.
1457 //
1458 double UTessellatedSolid::SafetyFromInside(const UVector3& p, bool) const
1459 {
1460 #if UDEBUG
1461  if (Inside(p) == kOutside)
1462  {
1463  std::ostringstream message;
1464  int oldprc = message.precision(16) ;
1465  message << "Point p is already outside!?" << endl
1466  << "Position:" << endl << endl
1467  << "p.x() = " << p.x() / mm << " mm" << endl
1468  << "p.y() = " << p.y() / mm << " mm" << endl
1469  << "p.z() = " << p.z() / mm << " mm" << endl
1470  << "DistanceToIn(p) == " << DistanceToIn(p);
1471  message.precision(oldprc) ;
1472  UUtils::Exception("UTriangularFacet::DistanceToOut(p)", "GeomSolids1002",
1473  Warning, 1, message.str().c_str());
1474  }
1475 #endif
1476 
1477  double minDist;
1478 
1479  if (OutsideOfExtent(p, fgTolerance)) return 0.0;
1480 
1481  if (fVoxels.GetCountOfVoxels() > 1)
1482  {
1483  VUFacet* facet;
1484  minDist = MinDistanceFacet(p, true, facet);
1485  }
1486  else
1487  {
1488  minDist = UUtils::kInfinity;
1489  double dist = 0.0;
1490  int size = fFacets.size();
1491  for (int i = 0; i < size; ++i)
1492  {
1493  VUFacet& facet = *fFacets[i];
1494  dist = facet.Distance(p, minDist);
1495  if (dist < minDist) minDist = dist;
1496  }
1497  }
1498  return minDist;
1499 }
1500 
1502 //
1503 // UGeometryType GetEntityType() const;
1504 //
1505 // Provide identification of the class of an object (required for
1506 // persistency and STEP interface).
1507 //
1509 {
1510  return fGeometryType;
1511 }
1512 
1514 //
1515 std::ostream& UTessellatedSolid::StreamInfo(std::ostream& os) const
1516 {
1517  os << endl;
1518  os << "Geometry Type = " << fGeometryType << endl;
1519  os << "Number of facets = " << fFacets.size() << endl;
1520 
1521  int size = fFacets.size();
1522  for (int i = 0; i < size; ++i)
1523  {
1524  os << "FACET # = " << i + 1 << endl;
1525  VUFacet& facet = *fFacets[i];
1526  facet.StreamInfo(os);
1527  }
1528  os << endl;
1529 
1530  return os;
1531 }
1532 
1534 //
1535 // Make a clone of the object
1536 //
1538 {
1539  return new UTessellatedSolid(*this);
1540 }
1541 
1543 //
1545 {
1546  aMin = fMinExtent;
1547  aMax = fMaxExtent;
1548 }
1549 
1551 //
1553 {
1554  return fMinExtent.x;
1555 }
1556 
1558 //
1560 {
1561  return fMaxExtent.x;
1562 }
1563 
1565 //
1567 {
1568  return fMinExtent.y;
1569 }
1570 
1572 //
1574 {
1575  return fMaxExtent.y;
1576 }
1577 
1579 //
1581 {
1582  return fMinExtent.z;
1583 }
1584 
1586 //
1588 {
1589  return fMaxExtent.z;
1590 }
1591 
1593 //
1595 {
1596  if (fSurfaceArea != 0.) return fSurfaceArea;
1597 
1598  int size = fFacets.size();
1599  for (int i = 0; i < size; ++i)
1600  {
1601  VUFacet& facet = *fFacets[i];
1602  fSurfaceArea += facet.GetArea();
1603  }
1604  return fSurfaceArea;
1605 }
1606 
1608 //
1610 {
1611  // Select randomly a facet and return a random point on it
1612 
1613  int i = (int) UUtils::Random(0., fFacets.size());
1614  return fFacets[i]->GetPointOnFace();
1615 }
1616 
1618 //
1619 // SetRandomVectorSet
1620 //
1621 // This is a set of predefined random vectors (if that isn't a contradition
1622 // in terms!) used to generate rays from a user-defined point. The member
1623 // function Inside uses these to determine whether the point is inside or
1624 // outside of the tessellated solid. All vectors should be unit vectors.
1625 //
1627 {
1628  fRandir.resize(20);
1629  fRandir[0] = UVector3(-0.9577428892113370, 0.2732676269591740, 0.0897405271949221);
1630  fRandir[1] = UVector3(-0.8331264504940770, -0.5162067214954600, -0.1985722492445700);
1631  fRandir[2] = UVector3(-0.1516671651108820, 0.9666292616127460, 0.2064580868390110);
1632  fRandir[3] = UVector3(0.6570250350323190, -0.6944539025883300, 0.2933460081893360);
1633  fRandir[4] = UVector3(-0.4820456281280320, -0.6331060000098690, -0.6056474264406270);
1634  fRandir[5] = UVector3(0.7629032554236800 , 0.1016854697539910, -0.6384658864065180);
1635  fRandir[6] = UVector3(0.7689540409061150, 0.5034929891988220, 0.3939600142169160);
1636  fRandir[7] = UVector3(0.5765188359255740, 0.5997271636278330, -0.5549354566343150);
1637  fRandir[8] = UVector3(0.6660632777862070, -0.6362809868288380, 0.3892379937580790);
1638  fRandir[9] = UVector3(0.3824415020414780, 0.6541792713761380, -0.6525243125110690);
1639  fRandir[10] = UVector3(-0.5107726564526760, 0.6020905056811610, 0.6136760679616570);
1640  fRandir[11] = UVector3(0.7459135439578050, 0.6618796061649330, 0.0743530220183488);
1641  fRandir[12] = UVector3(0.1536405855311580, 0.8117477913978260, -0.5634359711967240);
1642  fRandir[13] = UVector3(0.0744395301705579, -0.8707110101772920, -0.4861286795736560);
1643  fRandir[14] = UVector3(-0.1665874645185400, 0.6018553940549240, -0.7810369397872780);
1644  fRandir[15] = UVector3(0.7766902003633100, 0.6014617505959970, -0.1870724331097450);
1645  fRandir[16] = UVector3(-0.8710128685847430, -0.1434320216603030, -0.4698551243971010);
1646  fRandir[17] = UVector3(0.8901082092766820, -0.4388411398893870, 0.1229871120030100);
1647  fRandir[18] = UVector3(-0.6430417431544370, -0.3295938228697690, 0.6912779675984150);
1648  fRandir[19] = UVector3(0.6331124368380410, 0.6306211461665000, 0.4488714875425340);
1649 
1650  fMaxTries = 20;
1651 }
1652 
1653 double const UTessellatedSolid::dirTolerance = 1.0E-14;
1654 
1656 //
1658 {
1659  int base = sizeof(*this);
1660  base += fVertexList.capacity() * sizeof(UVector3);
1661  base += fRandir.capacity() * sizeof(UVector3);
1662 
1663  int limit = fFacets.size();
1664  for (int i = 0; i < limit; ++i)
1665  {
1666  VUFacet& facet = *fFacets[i];
1667  base += facet.AllocatedMemory() + sizeof(VUFacet*);
1668  }
1669 
1670  std::set<VUFacet*>::const_iterator beg, end, it;
1671  beg = fExtremeFacets.begin();
1672  end = fExtremeFacets.end();
1673  for (it = beg; it != end; it++)
1674  {
1675  VUFacet& facet = *(*it);
1676  base += facet.AllocatedMemory();
1677  }
1678  return base;
1679 }
1680 
1682 //
1684 {
1685  int size = AllocatedMemoryWithoutVoxels();
1686  int sizeInsides = fInsides.GetNbytes();
1687  int sizeVoxels = fVoxels.AllocatedMemory();
1688  size += sizeInsides + sizeVoxels;
1689  return size;
1690 }
double Mag2() const
Definition: UVector3.hh:267
double GetMaxZExtent() const
virtual UGeometryType GetEntityType() const
double GetMinYExtent() const
virtual bool Intersect(const UVector3 &, const UVector3 &, const bool, double &, double &, UVector3 &)=0
UVector3 hlen
Definition: UVoxelizer.hh:38
static const double dirTolerance
virtual UVector3 GetPointOnSurface() const
const std::vector< double > & GetBoundary(int index) const
Definition: UVoxelizer.hh:94
int GetVoxelsIndex(int x, int y, int z) const
Definition: UVoxelizer.hh:126
double DistanceToNext(const UVector3 &point, const UVector3 &direction, std::vector< int > &curVoxel) const
Definition: UVoxelizer.cc:1057
UTessellatedSolid & operator=(const UTessellatedSolid &s)
virtual ~UTessellatedSolid()
double GetMinXExtent() const
virtual bool Normal(const UVector3 &p, UVector3 &aNormal) const
virtual std::ostream & StreamInfo(std::ostream &os) const
std::vector< UVector3 > fRandir
double GetMaxYExtent() const
unsigned int GetNbytes() const
Definition: UBits.hh:124
bool OutsideOfExtent(const UVector3 &p, double tolerance=0) const
std::set< VUFacet * > fExtremeFacets
const std::string & GetName() const
Definition: VUSolid.hh:103
virtual int GetNumberOfVertices() const =0
static double fgTolerance
Definition: VUSolid.hh:30
G4String name
Definition: TRTMaterials.hh:40
double MinDistanceFacet(const UVector3 &p, bool simple, VUFacet *&facet) const
void Voxelize(std::vector< VUSolid * > &solids, std::vector< UTransform3D > &transforms)
virtual double SafetyFromOutside(const UVector3 &p, bool aAccurate=false) const
unsigned int GetNbits() const
Definition: UBits.hh:120
void SetMaxVoxels(int max)
Definition: UVoxelizer.cc:1125
bool AddFacet(VUFacet *aFacet)
virtual VUSolid * Clone() const
std::ostream & StreamInfo(std::ostream &os) const
Definition: VUFacet.cc:79
int GetNumberOfFacets() const
void DistanceToOutCandidates(const std::vector< int > &candidates, const UVector3 &aPoint, const UVector3 &direction, double &minDist, UVector3 &minNormal, int &minCandidate) const
virtual UVector3 GetVertex(int i) const =0
virtual double DistanceToIn(const UVector3 &p, const UVector3 &v, double aPstep=UUtils::kInfinity) const
void GetVoxel(std::vector< int > &curVoxel, const UVector3 &point) const
Definition: UVoxelizer.hh:101
static double Tolerance()
Definition: VUSolid.hh:127
bool Contains(const UVector3 &point) const
Definition: UVoxelizer.cc:998
double x
Definition: UVector3.hh:136
double GetMaxXExtent() const
long long GetCountOfVoxels() const
Definition: UVoxelizer.hh:184
std::vector< VUFacet * > fFacets
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
int GetMaxVoxels(UVector3 &ratioOfReduction)
Definition: UVoxelizer.hh:176
double DistanceToFirst(const UVector3 &point, const UVector3 &direction) const
Definition: UVoxelizer.cc:1008
static const double kInfinity
Definition: UUtils.hh:53
static bool CompareSortedVoxel(const std::pair< int, double > &l, const std::pair< int, double > &r)
int GetVoxelBoxesSize() const
Definition: UVoxelizer.hh:207
VUSolid::EnumInside InsideNoVoxels(const UVector3 &p) const
double DistanceToOutNoVoxels(const UVector3 &p, const UVector3 &v, UVector3 &aNormalVector, bool &aConvex, double aPstep=UUtils::kInfinity) const
double DistanceToInNoVoxels(const UVector3 &p, const UVector3 &v, double aPstep=UUtils::kInfinity) const
static double MinDistanceToBox(const UVector3 &aPoint, const UVector3 &f)
Definition: UVoxelizer.cc:1022
void Clear()
Definition: UBits.cc:72
void Initialize()
TODO: make a benchmark for automatic selection of number of voxels. random voxels will be selected...
void BuildBoundingBox()
Definition: UVoxelizer.cc:424
virtual UVector3 GetSurfaceNormal() const =0
virtual UVector3 GetCircumcentre() const =0
UVector3 pos
Definition: UVoxelizer.hh:39
double DistanceToInCandidates(const std::vector< int > &candidates, const UVector3 &aPoint, const UVector3 &aDirection) const
double DistanceToInCore(const UVector3 &p, const UVector3 &v, double aPstep=UUtils::kInfinity) const
virtual VUSolid::EnumInside Inside(const UVector3 &p) const
EnumInside
Definition: VUSolid.hh:23
const G4int n
double Dot(const UVector3 &) const
Definition: UVector3.hh:257
bool IsInside(const UVector3 &p) const
Definition: VUFacet.cc:100
virtual int AllocatedMemory()=0
void Extent(UVector3 &aMin, UVector3 &aMax) const
double Mag() const
Definition: UVector3.cc:48
const UVoxelBox & GetVoxelBox(int i) const
Definition: UVoxelizer.hh:212
UGeometryType fGeometryType
void SetBitNumber(unsigned int bitnumber, bool value=true)
Definition: UBits.hh:172
double GetMinZExtent() const
void Exception(const char *originOfException, const char *exceptionCode, UExceptionSeverity severity, int level, const char *description)
Definition: UUtils.cc:122
std::vector< UVector3 > fVertexList
virtual double GetArea()=0
virtual double SafetyFromInside(const UVector3 &p, bool aAccurate=false) const
const std::vector< int > & GetCandidates(std::vector< int > &curVoxel) const
Definition: UVoxelizer.hh:197
virtual bool IsDefined() const =0
T max(const T t1, const T t2)
brief Return the largest of the two arguments
VUSolid::EnumInside InsideVoxels(const UVector3 &aPoint) const
const std::vector< int > & GetVoxelBoxCandidates(int i) const
Definition: UVoxelizer.hh:217
UVector3 Unit() const
Definition: UVector3.cc:80
virtual void SetVertices(std::vector< UVector3 > *vertices)=0
std::set< UVertexInfo, UVertexComparator > fFacetList
double DistanceToOutCore(const UVector3 &p, const UVector3 &v, UVector3 &aNormalVector, bool &aConvex, double aPstep=UUtils::kInfinity) const
bool GetSolidClosed() const
void CopyObjects(const UTessellatedSolid &s)
std::string UGeometryType
Definition: UTypes.hh:39
void SetSolidClosed(const bool t)
double z
Definition: UVector3.hh:138
double SafetyToBoundingBox(const UVector3 &point) const
Definition: UVoxelizer.cc:1015
int AllocatedMemory()
Definition: UVoxelizer.cc:1137
void ResetBitNumber(unsigned int bitnumber)
Definition: UBits.hh:212
virtual double GetSurfaceArea()
const UBits & Empty() const
Definition: UVoxelizer.hh:162
double Random(double min=0.0, double max=1.0)
Definition: UUtils.cc:69
static const double mm
Definition: G4SIunits.hh:102
virtual double DistanceToOut(const UVector3 &p, const UVector3 &v, UVector3 &aNormalVector, bool &aConvex, double aPstep=UUtils::kInfinity) const
double y
Definition: UVector3.hh:137
static const G4double pos
Definition: UBits.hh:38
VUFacet * GetFacet(int i) const
bool IsEmpty(int index) const
Definition: UVoxelizer.hh:167
virtual void SetVertexIndex(const int i, const int j)=0
int SetAllUsingStack(const std::vector< int > &voxel, const std::vector< int > &max, bool status, UBits &checked)
virtual double Distance(const UVector3 &, const double)=0