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