58 int nvert = nvertices;
61 if (vert[(i + 1) % nvert] == vert[i]) {
63 for (
int j = i + 2; j < nvert; ++j)
64 vert[j - 1] = vert[j];
79 bool neighbour =
false;
80 int line1[2], line2[2];
82 for (
int i = 0; i <
fNvert; ++i) {
85 for (
int j = 0; j < other.
GetNvert(); ++j) {
86 if (ivert == other[j]) {
91 bool order1 = line1[1] == line1[0] + 1;
92 bool order2 = line2[1] == (line2[0] + 1) % other.
GetNvert();
93 flip = (order1 == order2);
128 constexpr double tolerance = 1.e-10;
129 auto vertexHash = [&](
Vertex_t const &vertex) {
133 auto hash_combine = [](
long seed,
const long value) {
134 return seed ^ (std::hash<long>{}(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
136 for (
int i = 0; i < 3; i++) {
138 hash = hash_combine(hash, std::roundl(vertex[i] / tolerance));
143 auto hash = vertexHash(vert);
144 bool isAdded =
false;
148 for (
auto it = range.first; it != range.second; ++it) {
169 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
179 Error(
"AddFacet",
"Triangular facet at index %d degenerated. Not adding.",
GetNfacets());
183 for (
auto i = 0; i < 3; ++i)
186 fFacets.emplace_back(ind[0], ind[1], ind[2]);
197 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
201 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding",
GetName());
206 fFacets.emplace_back(i0, i1, i2);
216 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
226 Error(
"AddFacet",
"Quadrilateral facet at index %d degenerated. Not adding.",
GetNfacets());
231 for (
auto i = 0; i < nvert; ++i)
235 fFacets.emplace_back(ind[0], ind[1], ind[2]);
237 fFacets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
250 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
254 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding",
GetName());
259 fFacets.emplace_back(i0, i1, i2, i3);
269 constexpr double kTolerance = 1.e-20;
270 auto const &facet =
fFacets[ifacet];
271 int nvert = facet.GetNvert();
274 for (
int i = 0; i < nvert - 1; ++i) {
276 if (e1.
Mag2() < kTolerance)
278 for (
int j = i + 1; j < nvert; ++j) {
280 if (e2.
Mag2() < kTolerance)
284 if (normal.
Mag2() < kTolerance)
301 constexpr double kTolerance = 1.e-10;
302 auto const &facet =
fFacets[ifacet];
303 int nvert = facet.GetNvert();
304 bool degenerated =
true;
307 std::cout <<
"Facet: " << ifacet <<
" is degenerated\n";
312 double surfaceArea = 0.;
313 for (
int i = 1; i < nvert - 1; ++i) {
318 if (surfaceArea < kTolerance) {
319 std::cout <<
"Facet: " << ifacet <<
" has zero surface area\n";
346 std::cerr <<
"Inconsistency in normal container";
373 bool hasorphans =
false;
374 bool hasflipped =
false;
375 for (
int i = 0; i <
fNfacets; ++i) {
380 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
382 if (nn[icrt] >=
fFacets[icrt].GetNvert())
384 for (
int i = icrt + 1; i <
fNfacets; ++i) {
385 bool isneighbour =
fFacets[icrt].IsNeighbour(
fFacets[i], flipped[i]);
388 flipped[i] = !flipped[i];
393 if (nn[icrt] ==
fFacets[icrt].GetNvert())
397 if (nn[icrt] <
fFacets[icrt].GetNvert())
401 if (hasorphans && verbose) {
402 Error(
"Check",
"Tessellated solid %s has following not fully connected facets:",
GetName());
403 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
404 if (nn[icrt] <
fFacets[icrt].GetNvert())
405 std::cout << icrt <<
" (" <<
fFacets[icrt].GetNvert() <<
" edges, " << nn[icrt] <<
" neighbours)\n";
412 Warning(
"Check",
"Tessellated solid %s has following facets with flipped normals:",
GetName());
413 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
416 std::cout << icrt <<
"\n";
423 if (nfixed && verbose)
424 Info(
"Check",
"Automatically flipped %d facets to match first defined facet", nfixed);
438 double vmin[3] = {kBig, kBig, kBig};
439 double vmax[3] = {-kBig, -kBig, -kBig};
440 for (
const auto &facet :
fFacets) {
441 for (
int i = 0; i < facet.GetNvert(); ++i) {
442 for (
int j = 0; j < 3; ++j) {
448 fDX = 0.5 * (vmax[0] - vmin[0]);
449 fDY = 0.5 * (vmax[1] - vmin[1]);
450 fDZ = 0.5 * (vmax[2] - vmin[2]);
451 for (
int i = 0; i < 3; ++i)
452 fOrigin[i] = 0.5 * (vmax[i] + vmin[i]);
472 const int nsegs =
fNseg;
487 std::cout <<
"=== Tessellated shape " <<
GetName() <<
" having " <<
GetNvertices() <<
" vertices and "
498 int *pols = buff.
fPols;
503 for (
const auto &facet :
fFacets) {
504 auto nvert = facet.GetNvert();
506 pols[indpol++] = nvert;
507 for (
auto j = 0; j < nvert; ++j) {
508 int k = (j + 1) % nvert;
511 segs[indseg++] = facet[j];
512 segs[indseg++] = facet[k];
514 pols[indpol + nvert - j - 1] = sind++;
527 vertex.CopyTo(&
points[ind]);
539 points[ind++] = vertex.x();
540 points[ind++] = vertex.y();
541 points[ind++] = vertex.z();
553 Error(
"ResizeCenter",
"Not all faces are defined");
558 double scale = maxsize / maxedge;
559 constexpr double kTol = 1
e-12;
560 const bool modified = (std::abs(scale - 1.0) > kTol) || (std::abs(origin[0]) > kTol) ||
561 (std::abs(origin[1]) > kTol) || (std::abs(origin[2]) > kTol);
562 for (
size_t i = 0; i <
fVertices.size(); ++i) {
585 const int nsegs =
fNseg;
589 if (buffer.
SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) {
611 using std::vector, std::string, std::ifstream, std::stringstream, std::endl;
622 FacetInd_t(
int a,
int b,
int c)
629 FacetInd_t(
int a,
int b,
int c,
int d)
663 if (!file.is_open()) {
664 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unable to open %s", objfile);
668 while (getline(file,
line)) {
673 if (
line.rfind(
'v', 0) == 0 &&
line.rfind(
"vt", 0) != 0 &&
line.rfind(
"vn", 0) != 0 &&
line.rfind(
"vn", 0) != 0) {
675 double pos[4] = {0, 0, 0, 1};
676 ss >> tag >> pos[0] >> pos[1] >> pos[2] >> pos[3];
677 vertices.emplace_back(pos[0] * pos[3], pos[1] * pos[3], pos[2] * pos[3]);
680 else if (
line.rfind(
'f', 0) == 0) {
686 sfacets.push_back(word);
687 if (sfacets.size() > 4 || sfacets.size() < 3) {
688 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Detected face having unsupported %zu vertices",
693 for (
auto &sword : sfacets) {
696 getline(ssword, token,
'/');
699 ind[nvert++] = stoi(token) - 1;
700 if (ind[nvert - 1] < 0) {
701 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unsupported relative vertex index definition in %s",
707 facets.emplace_back(ind[0], ind[1], ind[2]);
709 facets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
713 int nvertices = (
int)vertices.size();
714 int nfacets = (
int)facets.size();
716 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Not enough faces detected in %s", objfile);
720 string sobjfile(objfile);
722 std::cout <<
"Read " << nvertices <<
" vertices and " << nfacets <<
" facets from " << sobjfile << endl;
724 auto tsl =
new TGeoTessellated(sobjfile.erase(sobjfile.find_last_of(
'.')).c_str(), vertices);
726 for (
int i = 0; i < nfacets; ++i) {
727 auto facet = facets[i];
728 if (facet.nvert == 3)
729 tsl->AddFacet(facet.i0, facet.i1, facet.i2);
731 tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3);
733 tsl->CloseShape(check,
true, verbose);
751 constexpr double EPS = 1
e-8;
752 const double INF = std::numeric_limits<double>::infinity();
756 auto det = e1.
Dot(p);
757 if (std::abs(det) <= EPS) {
762 auto invDet = 1.0 / det;
763 auto u = tvec.
Dot(p) * invDet;
764 if (u < 0.0 || u > 1.0) {
768 auto v = dir.
Dot(
q) * invDet;
772 auto t = e2.
Dot(
q) * invDet;
773 return (t > rayEPS) ? t : INF;
777 const std::vector<Vertex_t> &vertices,
double rayEPS = 1
e-8)
780 const auto &
v0 = vertices[facet[0]];
781 const auto &
v1 = vertices[facet[1]];
782 const auto &
v2 = vertices[facet[2]];
783 auto t = rayTriangle(orig, dir,
v0,
v1,
v2, rayEPS);
786 const auto &
v3 = vertices[facet[3]];
787 auto t2 = rayTriangle(orig, dir,
v0,
v2,
v3, rayEPS);
788 return std::min(t, t2);
792 const std::vector<Vertex_t> &vertices,
double rayEPS = 1
e-8)
795 return rayFacet(orig, dir, facet, vertices, rayEPS) != std::numeric_limits<double>::infinity();
798template <
typename T =
float>
801 Vec3f(T x_, T y_, T z_) : x(x_), y(y_), z(z_){};
805inline Vec3f<T>
operator-(
const Vec3f<T> &
a,
const Vec3f<T> &
b)
807 return {
a.x -
b.x,
a.y -
b.y,
a.z -
b.z};
811inline Vec3f<T>
cross(
const Vec3f<T> &
a,
const Vec3f<T> &
b)
813 return {
a.y *
b.z -
a.z *
b.y,
a.z *
b.x -
a.x *
b.z,
a.x *
b.y -
a.y *
b.x};
817inline T
dot(
const Vec3f<T> &
a,
const Vec3f<T> &
b)
819 return a.x *
b.x +
a.y *
b.y +
a.z *
b.z;
828template <
typename T =
float>
829T pointTriangleDistSq(
const Vec3f<T> &p,
const Vec3f<T> &
a,
const Vec3f<T> &
b,
const Vec3f<T> &
c)
836 auto d1 =
dot(ab, ap);
837 auto d2 =
dot(ac, ap);
838 if (d1 <= T(0.0) && d2 <= T(0.0)) {
843 auto d3 =
dot(ab, bp);
844 auto d4 =
dot(ac, bp);
845 if (d3 >= T(0.0) && d4 <= d3) {
849 T vc = d1 * d4 - d3 * d2;
850 if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
851 T
v = d1 / (d1 - d3);
852 Vec3f<T> proj = {
a.x +
v * ab.x,
a.y +
v * ab.y,
a.z +
v * ab.z};
853 Vec3f<T>
d = p - proj;
860 if (d6 >= T(0.0f) && d5 <= d6) {
864 T vb = d5 * d2 - d1 * d6;
865 if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
866 T w = d2 / (d2 - d6);
868 Vec3f<T>
d = p - proj;
872 T va = d3 * d6 - d5 * d4;
873 if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
874 T w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
875 Vec3f<T> proj = {
b.x + w * (
c.x -
b.x),
b.y + w * (
c.y -
b.y),
b.z + w * (
c.z - b.z)};
876 Vec3f<T>
d = p - proj;
881 T denom = T(1.0f) / (va + vb + vc);
885 Vec3f<T> proj = {
a.x + ab.x *
v + ac.x * w,
a.y + ab.y *
v + ac.y * w,
a.z + ab.z *
v + ac.z * w};
887 Vec3f<T>
d = p - proj;
891template <
typename T =
float>
892T pointFacetDistSq(
const Vec3f<T> &p,
const TGeoFacet &facet,
const std::vector<Vertex_t> &vertices)
895 const auto &
v0 = vertices[facet[0]];
896 const auto &
v1 = vertices[facet[1]];
897 const auto &
v2 = vertices[facet[2]];
898 auto d = pointTriangleDistSq(p, Vec3f<T>(
v0[0],
v0[1],
v0[2]), Vec3f<T>(
v1[0],
v1[1],
v1[2]),
899 Vec3f<T>(
v2[0],
v2[1],
v2[2]));
902 const auto &
v3 = vertices[facet[3]];
903 auto d2 = pointTriangleDistSq(p, Vec3f<T>(
v0[0],
v0[1],
v0[2]), Vec3f<T>(
v2[0],
v2[1],
v2[2]),
904 Vec3f<T>(
v3[0],
v3[1],
v3[2]));
905 return std::min(
d, d2);
917 double local_step =
Big();
919 using Scalar = float;
926 auto mybvh = (Bvh *)
fBVH;
932 auto truncate_roundup = [](
double orig) {
933 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
935 return static_cast<float>(orig + epsilon);
939 const auto topnode_bbox = mybvh->get_root().get_bbox();
940 if ((-point[0] + topnode_bbox.min[0]) > stepmax) {
943 if ((-point[1] + topnode_bbox.min[1]) > stepmax) {
946 if ((-point[2] + topnode_bbox.min[2]) > stepmax) {
949 if ((point[0] - topnode_bbox.max[0]) > stepmax) {
952 if ((point[1] - topnode_bbox.max[1]) > stepmax) {
955 if ((point[2] - topnode_bbox.max[2]) > stepmax) {
960 Ray ray(Vec3(point[0], point[1], point[2]),
961 Vec3(dir[0], dir[1], dir[2]),
963 truncate_roundup(local_step));
965 static constexpr bool use_robust_traversal =
true;
967 Vertex_t dir_v{dir[0], dir[1], dir[2]};
970 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index, stack, [&](
size_t begin,
size_t end) {
971 for (
size_t prim_id = begin; prim_id < end; ++prim_id) {
972 auto objectid = mybvh->prim_ids[prim_id];
973 const auto &facet =
fFacets[objectid];
977 if (
n.Dot(dir_v) > 0.) {
981 auto thisdist = rayFacet(
Vertex_t(point[0], point[1], point[2]), dir_v, facet,
fVertices, 0.);
983 if (thisdist < local_step) {
984 local_step = thisdist;
1000 double local_step =
Big();
1002 using Scalar = float;
1009 auto mybvh = (Bvh *)
fBVH;
1015 auto truncate_roundup = [](
double orig) {
1016 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
1018 return static_cast<float>(orig + epsilon);
1022 Ray ray(Vec3(point[0], point[1], point[2]),
1023 Vec3(dir[0], dir[1], dir[2]),
1025 truncate_roundup(local_step));
1027 static constexpr bool use_robust_traversal =
true;
1029 Vertex_t dir_v{dir[0], dir[1], dir[2]};
1032 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index, stack, [&](
size_t begin,
size_t end) {
1033 for (
size_t prim_id = begin; prim_id < end; ++prim_id) {
1034 auto objectid = mybvh->prim_ids[prim_id];
1035 auto facet =
fFacets[objectid];
1039 if (
n.Dot(dir_v) <= 0.) {
1043 const double t = rayFacet(
Vertex_t{point[0], point[1], point[2]}, dir_v, facet,
fVertices, 0.);
1044 if (t < local_step) {
1064 for (
size_t i = 0; i <
fFacets.size(); ++i) {
1070 a[0] * (
b[1] *
c[2] -
b[2] *
c[1]) +
b[0] * (
c[1] *
a[2] -
c[2] *
a[1]) +
c[0] * (
a[1] *
b[2] -
a[2] *
b[1]);
1080 using Scalar = float;
1087 auto GetBoundingBox = [
this](
TGeoFacet const &facet) {
1088 const auto nvertices = facet.GetNvert();
1089 if (nvertices != 3 && nvertices != 4)
1090 Fatal(
"BuildBVH",
"only facets with 3 or 4 vertices supported");
1094 const auto &
v4 = (nvertices == 4) ?
fVertices[facet[3]] :
v3;
1097 bbox.min[0] = std::min(std::min(std::min(
v1[0],
v2[0]),
v3[0]),
v4[0]) - 0.001f;
1098 bbox.min[1] = std::min(std::min(std::min(
v1[1],
v2[1]),
v3[1]),
v4[1]) - 0.001f;
1099 bbox.min[2] = std::min(std::min(std::min(
v1[2],
v2[2]),
v3[2]),
v4[2]) - 0.001f;
1100 bbox.max[0] = std::max(std::max(std::max(
v1[0],
v2[0]),
v3[0]),
v4[0]) + 0.001f;
1101 bbox.max[1] = std::max(std::max(std::max(
v1[1],
v2[1]),
v3[1]),
v4[1]) + 0.001f;
1102 bbox.max[2] = std::max(std::max(std::max(
v1[2],
v2[2]),
v3[2]),
v4[2]) + 0.001f;
1108 std::vector<BBox> bboxes;
1109 std::vector<Vec3> centers;
1113 centers.reserve(nd);
1115 for (
int i = 0; i < nd; ++i) {
1119 (bboxes).push_back(GetBoundingBox(facet));
1120 centers.emplace_back((bboxes).back().get_center());
1133 auto bvhptr =
new Bvh;
1134 *bvhptr = std::move(
bvh);
1135 fBVH = (
void *)(bvhptr);
1144 using Scalar = float;
1151 auto mybvh = (Bvh *)
fBVH;
1157 auto truncate_roundup = [](
double orig) {
1158 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
1160 return static_cast<float>(orig + epsilon);
1171 Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757};
1173 double local_step =
Big();
1175 Ray ray(Vec3(point[0], point[1], point[2]),
1176 Vec3(test_dir[0], test_dir[1], test_dir[2]),
1178 truncate_roundup(local_step));
1180 static constexpr bool use_robust_traversal =
true;
1184 size_t crossings = 0;
1185 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index, stack, [&](
size_t begin,
size_t end) {
1186 for (
size_t prim_id = begin; prim_id < end; ++prim_id) {
1187 auto objectid = mybvh->prim_ids[prim_id];
1188 auto &facet =
fFacets[objectid];
1191 if (rayFacetHit(
Vertex_t(point[0], point[1], point[2]), test_dir, facet,
fVertices, 0.)) {
1198 return crossings & 1;
1205struct BVHPrioElement {
1215template <
typename Comparator>
1216class BVHPrioQueue :
public std::priority_queue<BVHPrioElement, std::vector<BVHPrioElement>, Comparator> {
1218 using std::priority_queue<BVHPrioElement, std::vector<BVHPrioElement>,
1219 Comparator>::priority_queue;
1222 void clear() { this->
c.clear(); }
1228template <
bool returnFace>
1235 using Scalar = float;
1241 auto mybvh = (Bvh *)
fBVH;
1244 Vec3 testpoint(point[0], point[1], point[2]);
1246 auto currnode = mybvh->nodes[0];
1248 bool outside_top =
false;
1254 return std::sqrt(safety_sq_to_top);
1259 auto cmp = [](BVHPrioElement
a, BVHPrioElement
b) {
return a.value >
b.value; };
1260 static thread_local BVHPrioQueue<
decltype(cmp)> queue(cmp);
1264 float current_safety_to_node_sq = 0.f;
1267 *closest_facet_id = -1;
1271 if (currnode.is_leaf()) {
1273 const auto begin_prim_id = currnode.index.first_id();
1274 const auto end_prim_id = begin_prim_id + currnode.index.prim_count();
1276 for (
auto p_id = begin_prim_id; p_id < end_prim_id; p_id++) {
1277 const auto object_id = mybvh->prim_ids[p_id];
1279 const auto &facet =
fFacets[object_id];
1281 pointFacetDistSq(Vec3f<float>(point[0], point[1], point[2]), facet,
fVertices);
1283 if (thissafetySQ < smallest_safety_sq) {
1284 smallest_safety_sq = thissafetySQ;
1286 *closest_facet_id = object_id;
1293 const auto leftchild_id = currnode.index.first_id();
1294 const auto rightchild_id = leftchild_id + 1;
1296 for (
size_t childid : {leftchild_id, rightchild_id}) {
1297 if (childid >= mybvh->nodes.size()) {
1301 const auto &node = mybvh->nodes[childid];
1306 queue.push(BVHPrioElement{childid, -1.});
1309 if (safety_to_node_square <= smallest_safety_sq) {
1311 queue.push(BVHPrioElement{childid, safety_to_node_square});
1317 if (queue.size() > 0) {
1318 auto currElement = queue.top();
1319 currnode = mybvh->nodes[currElement.bvh_node_id];
1320 current_safety_to_node_sq = currElement.value;
1325 }
while (current_safety_to_node_sq <= smallest_safety_sq);
1327 return std::nextafter(std::sqrt(smallest_safety_sq), 0.0f);
1353 int closest_face_id = -1;
1356 if (closest_face_id < 0) {
1369 if (norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2] < 0) {
1383 if (
b.IsReading()) {
1398 for (
size_t i = 0; i <
fFacets.size(); ++i) {
1400 bool degenerated =
false;
int Int_t
Signed integer 4 bytes (int).
bool Bool_t
Boolean (0=false, 1=true) (bool).
double Double_t
Double 8 bytes.
float Float_t
Float 4 bytes (float).
const char Option_t
Option string (const char).
Tessellated::Vertex_t Vertex_t
TTime operator-(const TTime &t1, const TTime &t2)
Generic 3D primitive description class.
Bool_t SectionsValid(UInt_t mask) const
void SetSectionsValid(UInt_t mask)
Bool_t SetRawSizes(UInt_t reqPnts, UInt_t reqPntsCapacity, UInt_t reqSegs, UInt_t reqSegsCapacity, UInt_t reqPols, UInt_t reqPolsCapacity)
Set kRaw tessellation section of buffer with supplied sizes.
Buffer base class used for serializing objects.
void FillBuffer3D(TBuffer3D &buffer, Int_t reqSections, Bool_t localFrame) const override
Fill the supplied buffer, with sections in desired frame See TBuffer3D.h for explanation of sections,...
TGeoBBox(const TGeoBBox &)=delete
Bool_t Contains(const Double_t *point) const override
Tessellated::Vertex_t Vertex_t
bool IsNeighbour(const TGeoFacet &other, bool &flip) const
Check if a connected neighbour facet has compatible normal.
static int CompactFacet(Vertex_t *vert, int nvertices)
Compact consecutive equal vertices.
Int_t GetBasicColor() const
Get the basic color (0-7).
void TransformPoints(Double_t *points, UInt_t NbPoints) const
Tranform a set of points (LocalToMaster).
const char * GetName() const override
Get the shape name.
Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const override
Safety.
void ResizeCenter(double maxsize)
Resize and center the shape in a box of size maxsize.
int AddVertex(const Vertex_t &vert)
Add a vertex checking for duplicates, returning the vertex index.
bool Contains(const Double_t *point) const override
Contains.
void ComputeNormal(const Double_t *point, const Double_t *dir, Double_t *norm) const override
ComputeNormal interface.
bool FacetCheck(int ifacet) const
Check validity of facet.
void Streamer(TBuffer &) override
Custom streamer which performs Closing on read.
Double_t SafetyKernel(const Double_t *point, bool in, int *closest_facet_id=nullptr) const
a reusable safety kernel, which optionally returns the closest face
void Print(Option_t *option="") const override
Prints basic info.
Double_t Capacity() const override
Capacity.
Double_t DistFromInside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const override
DistFromOutside.
void * fBVH
to know if shape still needs closure/initialization
Double_t DistFromOutside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const override
DistFromOutside.
void SetSegsAndPols(TBuffer3D &buff) const override
Fills TBuffer3D structure for segments and polygons.
const TBuffer3D & GetBuffer3D(int reqSections, Bool_t localFrame) const override
Fills a static 3D buffer and returns a reference.
TGeoTessellated(const TGeoTessellated &)=delete
BVH acceleration structure for safety and navigation.
void SetPoints(double *points) const override
Fill tessellated points to an array.
bool CheckClosure(bool fixFlipped=true, bool verbose=true)
Check closure of the solid and check/fix flipped normals.
bool fDefined
! Shape fully defined
Vertex_t FacetComputeNormal(int ifacet, bool °enerated) const
Compute normal for a given facet.
void CloseShape(bool check=true, bool fixFlipped=true, bool verbose=true)
Close the shape: calculate bounding box and compact vertices.
Tessellated::Vertex_t Vertex_t
void GetMeshNumbers(int &nvert, int &nsegs, int &npols) const override
Returns numbers of vertices, segments and polygons composing the shape mesh.
std::vector< TGeoFacet > fFacets
static TGeoTessellated * ImportFromObjFormat(const char *objfile, bool check=false, bool verbose=false)
Reader from .obj format.
TBuffer3D * MakeBuffer3D() const override
Creates a TBuffer3D describing this shape.
void ComputeBBox() override
Compute bounding box.
std::multimap< long, int > fVerticesMap
! Temporary map used to deduplicate vertices
std::vector< Vertex_t > fOutwardNormals
bool AddFacet(const Vertex_t &pt0, const Vertex_t &pt1, const Vertex_t &pt2)
Adding a triangular facet from vertex positions in absolute coordinates.
void CalculateNormals()
Calculate the normals.
std::vector< Vertex_t > fVertices
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
static BVH_ALWAYS_INLINE Bvh< Node > build(ThreadPool &thread_pool, std::span< const BBox > bboxes, std::span< const Vec > centers, const Config &config={})
Build a BVH in parallel using the given thread pool.
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
ROOT::Geom::Vertex_t Vertex_t
BVH_ALWAYS_INLINE Vec< T, 3 > cross(const Vec< T, 3 > &a, const Vec< T, 3 > &b)
BVH_ALWAYS_INLINE T dot(const Vec< T, N > &a, const Vec< T, N > &b)
static Vertex_t Cross(Vertex_t const &left, Vertex_t const &right)
The cross (vector) product of two Vector3D<T> objects.
void Normalize()
Normalizes the vector by dividing each entry by the length.
static double Dot(Vertex_t const &left, Vertex_t const &right)
The dot product of two vector objects.
Quality quality
The quality of the BVH produced by the builder.
Growing stack that can be used for BVH traversal.
Binary BVH node, containing its bounds and an index into its children or the primitives it contains.