21#include "TGeoManager.h"
22#include "TGeoMatrix.h"
23#include "TGeoVolume.h"
24#include "TVirtualGeoPainter.h"
27#include "TBuffer3DTypes.h"
53int TGeoFacet::CompactFacet(
Vertex_t* vert,
int nvertices)
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];
75bool TGeoFacet::IsNeighbour(
const TGeoFacet&
other,
bool& flip)
const
79 bool neighbour =
false;
80 int line1[2], line2[2];
82 for (
int i = 0;
i < fNvert; ++
i) {
83 auto ivert = fIvert[
i];
85 for (
int j = 0;
j <
other.GetNvert(); ++
j) {
91 bool order1 = line1[1] == line1[0] + 1;
92 bool order2 = line2[1] == (line2[0] + 1) %
other.GetNvert();
93 flip = (order1 == order2);
110 fFacets.reserve(nfacets);
119 fVertices = vertices;
120 fNvert = fVertices.size();
128 fNfacets = tsl.GetNfacets();
129 fNvert = tsl.GetNvertices();
130 fNseg = tsl.GetNsegments();
133 fVertices.reserve(fNvert);
134 fFacets.reserve(fNfacets);
135 for (
int i = 0;
i < fNfacets; ++
i) {
136 fFacets.push_back(tsl.GetFacet(
i));
138 for (
int i = 0;
i < fNvert; ++
i) {
139 fVertices.push_back(tsl.GetVertex(
i));
150 constexpr double tolerance = 1.e-10;
155 auto hash_combine = [](
long seed,
const long value) {
156 return seed ^ (std::hash<long>{}(
value) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
158 for (
int i = 0;
i < 3;
i++) {
165 auto hash = vertexHash(vert);
166 bool isAdded =
false;
169 auto range = fVerticesMap.equal_range(
hash);
170 for (
auto it =
range.first; it !=
range.second; ++it) {
172 if (fVertices[ivert] == vert) {
178 ivert = fVertices.size();
179 fVertices.push_back(vert);
180 fVerticesMap.insert(std::make_pair(
hash, ivert));
191 Error(
"AddFacet",
"Shape %s already fully defined. Not adding", GetName());
199 int nvert = TGeoFacet::CompactFacet(vert, 3);
201 Error(
"AddFacet",
"Triangular facet at index %d degenerated. Not adding.",
GetNfacets());
205 for (
auto i = 0;
i < 3; ++
i)
208 fFacets.emplace_back(ind[0], ind[1], ind[2]);
219 Error(
"AddFacet",
"Shape %s already fully defined. Not adding", GetName());
222 if (fVertices.empty()) {
223 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding", GetName());
228 fFacets.emplace_back(i0, i1, i2);
238 Error(
"AddFacet",
"Shape %s already fully defined. Not adding", GetName());
246 int nvert = TGeoFacet::CompactFacet(vert, 4);
248 Error(
"AddFacet",
"Quadrilateral facet at index %d degenerated. Not adding.",
GetNfacets());
253 for (
auto i = 0;
i < nvert; ++
i)
257 fFacets.emplace_back(ind[0], ind[1], ind[2]);
259 fFacets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
272 Error(
"AddFacet",
"Shape %s already fully defined. Not adding", GetName());
275 if (fVertices.empty()) {
276 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding", GetName());
281 fFacets.emplace_back(i0, i1, i2, i3);
291 constexpr double kTolerance = 1.e-20;
292 auto const& facet = fFacets[ifacet];
293 int nvert = facet.GetNvert();
296 for (
int i = 0;
i < nvert - 1; ++
i) {
297 Vertex_t e1 = fVertices[facet[
i + 1]] - fVertices[facet[
i]];
298 if (e1.Mag2() < kTolerance)
300 for (
int j =
i + 1;
j < nvert; ++
j) {
301 Vertex_t e2 = fVertices[facet[(
j + 1) % nvert]] - fVertices[facet[
j]];
302 if (e2.Mag2() < kTolerance)
304 normal = Vertex_t::Cross(e1, e2);
306 if (normal.Mag2() < kTolerance)
323 constexpr double kTolerance = 1.e-10;
324 auto const& facet = fFacets[ifacet];
325 int nvert = facet.GetNvert();
326 bool degenerated =
true;
329 std::cout <<
"Facet: " << ifacet <<
" is degenerated\n";
334 double surfaceArea = 0.;
335 for (
int i = 1;
i < nvert - 1; ++
i) {
336 Vertex_t e1 = fVertices[facet[
i]] - fVertices[facet[0]];
337 Vertex_t e2 = fVertices[facet[
i + 1]] - fVertices[facet[0]];
338 surfaceArea += 0.5 * Vertex_t::Cross(e1, e2).Mag();
340 if (surfaceArea < kTolerance) {
341 std::cout <<
"Facet: " << ifacet <<
" has zero surface area\n";
353 if (fIsClosed && fBVH) {
358 fNvert = fVertices.size();
359 fNfacets = fFacets.size();
363 if (fOutwardNormals.size() == 0) {
367 if (fOutwardNormals.size() != fFacets.size()) {
368 std::cerr <<
"Inconsistency in normal container";
374 std::multimap<long, int>().swap(fVerticesMap);
376 if (fVertices.size() > 0) {
381 for (
auto i = 0;
i < fNfacets; ++
i)
393 int* nn =
new int[fNfacets];
394 bool* flipped =
new bool[fNfacets];
395 bool hasorphans =
false;
396 bool hasflipped =
false;
397 for (
int i = 0;
i < fNfacets; ++
i) {
402 for (
int icrt = 0; icrt < fNfacets; ++icrt) {
404 if (nn[icrt] >= fFacets[icrt].GetNvert())
406 for (
int i = icrt + 1;
i < fNfacets; ++
i) {
407 bool isneighbour = fFacets[icrt].IsNeighbour(fFacets[
i], flipped[
i]);
410 flipped[
i] = !flipped[
i];
415 if (nn[icrt] == fFacets[icrt].GetNvert())
419 if (nn[icrt] < fFacets[icrt].GetNvert())
423 if (hasorphans && verbose) {
424 Error(
"Check",
"Tessellated solid %s has following not fully connected facets:", GetName());
425 for (
int icrt = 0; icrt < fNfacets; ++icrt) {
426 if (nn[icrt] < fFacets[icrt].GetNvert())
427 std::cout << icrt <<
" (" << fFacets[icrt].GetNvert() <<
" edges, " << nn[icrt] <<
" neighbours)\n";
430 fClosedBody = !hasorphans;
434 Warning(
"Check",
"Tessellated solid %s has following facets with flipped normals:", GetName());
435 for (
int icrt = 0; icrt < fNfacets; ++icrt) {
438 std::cout << icrt <<
"\n";
440 fFacets[icrt].Flip();
445 if (nfixed && verbose)
446 Info(
"Check",
"Automatically flipped %d facets to match first defined facet", nfixed);
459 const double kBig = TGeoShape::Big();
460 double vmin[3] = {kBig, kBig, kBig};
461 double vmax[3] = {-kBig, -kBig, -kBig};
462 for (
const auto& facet : fFacets) {
463 for (
int i = 0;
i < facet.GetNvert(); ++
i) {
464 for (
int j = 0;
j < 3; ++
j) {
465 vmin[
j] = TMath::Min(vmin[
j], fVertices[facet[
i]].
operator[](
j));
466 vmax[
j] = TMath::Max(vmax[
j], fVertices[facet[
i]].
operator[](
j));
470 fDX = 0.5 * (vmax[0] - vmin[0]);
471 fDY = 0.5 * (vmax[1] - vmin[1]);
472 fDZ = 0.5 * (vmax[2] - vmin[2]);
473 for (
int i = 0;
i < 3; ++
i)
474 fOrigin[
i] = 0.5 * (vmax[
i] + vmin[
i]);
493 const int nvert = fNvert;
494 const int nsegs = fNseg;
496 auto buff =
new TBuffer3D(TBuffer3DTypes::kGeneric, nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols);
509 std::cout <<
"=== Tessellated shape " << GetName() <<
" having " <<
GetNvertices() <<
" vertices and "
518 const int c = GetBasicColor();
519 int* segs = buff.fSegs;
520 int* pols = buff.fPols;
525 for (
const auto& facet : fFacets) {
526 auto nvert = facet.GetNvert();
528 pols[indpol++] = nvert;
529 for (
auto j = 0;
j < nvert; ++
j) {
530 int k = (
j + 1) % nvert;
533 segs[indseg++] = facet[
j];
534 segs[indseg++] = facet[k];
536 pols[indpol + nvert -
j - 1] = sind++;
548 for (
const auto&
vertex : fVertices) {
549 vertex.CopyTo(&points[ind]);
560 for (
const auto&
vertex : fVertices) {
561 points[ind++] =
vertex.x();
562 points[ind++] =
vertex.y();
563 points[ind++] =
vertex.z();
575 Error(
"ResizeCenter",
"Not all faces are defined");
578 Vector3_t
origin(fOrigin[0], fOrigin[1], fOrigin[2]);
579 double maxedge = TMath::Max(TMath::Max(fDX, fDY), fDZ);
580 double scale = maxsize / maxedge;
581 for (
size_t i = 0;
i < fVertices.size(); ++
i) {
582 fVertices[
i] = scale * (fVertices[
i] -
origin);
584 fOrigin[0] = fOrigin[1] = fOrigin[2] = 0;
595 static TBuffer3D
buffer(TBuffer3DTypes::kGeneric);
597 FillBuffer3D(
buffer, reqSections, localFrame);
599 const int nvert = fNvert;
600 const int nsegs = fNseg;
603 if (reqSections & TBuffer3D::kRawSizes) {
604 if (
buffer.SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) {
605 buffer.SetSectionsValid(TBuffer3D::kRawSizes);
608 if ((reqSections & TBuffer3D::kRaw) &&
buffer.SectionsValid(TBuffer3D::kRawSizes)) {
610 if (!
buffer.fLocalFrame) {
615 buffer.SetSectionsValid(TBuffer3D::kRaw);
626 using std::vector, std::string, std::ifstream, std::stringstream, std::endl;
628 vector<Vertex_t> vertices;
629 vector<string> sfacets;
637 FacetInd_t(
int a,
int b,
int c)
644 FacetInd_t(
int a,
int b,
int c,
int d)
654 vector<FacetInd_t> facets;
677 ifstream
file(objfile);
678 if (!
file.is_open()) {
679 ::Error(
"O2Tessellated::ImportFromObjFormat",
"Unable to open %s", objfile);
683 while (getline(
file, line)) {
684 stringstream ss(line);
688 if (line.rfind(
'v', 0) == 0 && line.rfind(
"vt", 0) != 0 && line.rfind(
"vn", 0) != 0 && line.rfind(
"vn", 0) != 0) {
690 double pos[4] = {0, 0, 0, 1};
695 else if (line.rfind(
'f', 0) == 0) {
701 sfacets.push_back(word);
702 if (sfacets.size() > 4 || sfacets.size() < 3) {
703 ::Error(
"O2Tessellated::ImportFromObjFormat",
"Detected face having unsupported %zu vertices",
708 for (
auto& sword : sfacets) {
709 stringstream ssword(sword);
711 getline(ssword, token,
'/');
714 ind[nvert++] = stoi(token) - 1;
715 if (ind[nvert - 1] < 0) {
716 ::Error(
"O2Tessellated::ImportFromObjFormat",
"Unsupported relative vertex index definition in %s",
722 facets.emplace_back(ind[0], ind[1], ind[2]);
724 facets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
728 int nvertices = (
int)vertices.size();
729 int nfacets = (
int)facets.size();
731 ::Error(
"O2Tessellated::ImportFromObjFormat",
"Not enough faces detected in %s", objfile);
735 string sobjfile(objfile);
737 std::cout <<
"Read " << nvertices <<
" vertices and " << nfacets <<
" facets from " << sobjfile << endl;
739 auto tsl =
new O2Tessellated(sobjfile.erase(sobjfile.find_last_of(
'.')).c_str(), vertices);
741 for (
int i = 0;
i < nfacets; ++
i) {
742 auto facet = facets[
i];
743 if (facet.nvert == 3)
744 tsl->AddFacet(facet.i0, facet.i1, facet.i2);
746 tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3);
748 tsl->CloseShape(
check,
true, verbose);
757using Vertex_t = Tessellated::Vertex_t;
767 constexpr double EPS = 1e-8;
768 const double INF = std::numeric_limits<double>::infinity();
771 auto p = Vertex_t::Cross(dir, e2);
772 auto det = e1.Dot(p);
773 if (std::abs(det) <= EPS) {
778 auto invDet = 1.0 / det;
779 auto u = tvec.Dot(p) * invDet;
780 if (u < 0.0 || u > 1.0) {
783 auto q = Vertex_t::Cross(tvec, e1);
784 auto v = dir.Dot(q) * invDet;
785 if (v < 0.0 || u + v > 1.0) {
788 auto t = e2.Dot(q) * invDet;
789 return (t > rayEPS) ? t : INF;
792template <
typename T =
float>
798inline Vec3f<T>
operator-(
const Vec3f<T>&
a,
const Vec3f<T>&
b)
800 return {
a.x -
b.x,
a.y -
b.y,
a.z -
b.z};
804inline Vec3f<T> cross(
const Vec3f<T>&
a,
const Vec3f<T>&
b)
806 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};
810inline T dot(
const Vec3f<T>&
a,
const Vec3f<T>&
b)
812 return a.x *
b.x +
a.y *
b.y +
a.z *
b.z;
821template <
typename T =
float>
822T pointTriangleDistSq(
const Vec3f<T>& p,
const Vec3f<T>&
a,
const Vec3f<T>&
b,
const Vec3f<T>&
c)
829 auto d1 =
dot(ab, ap);
830 auto d2 =
dot(ac, ap);
831 if (d1 <=
T(0.0) && d2 <=
T(0.0)) {
836 auto d3 =
dot(ab, bp);
837 auto d4 =
dot(ac, bp);
838 if (d3 >=
T(0.0) && d4 <= d3) {
842 T vc = d1 * d4 - d3 *
d2;
843 if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
844 T v = d1 / (d1 - d3);
845 Vec3f<T> proj = {
a.x +
v * ab.x,
a.y +
v * ab.y,
a.z +
v * ab.z};
846 Vec3f<T> d =
p - proj;
853 if (d6 >=
T(0.0f) && d5 <= d6) {
857 T vb = d5 *
d2 - d1 * d6;
858 if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
860 Vec3f<T> proj = {
a.x +
w * ac.x,
a.y +
w * ac.y,
a.z +
w * ac.z};
861 Vec3f<T> d =
p - proj;
865 T va = d3 * d6 - d5 * d4;
866 if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
867 T w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
868 Vec3f<T> proj = {
b.x +
w * (
c.x -
b.x),
b.y +
w * (
c.y -
b.y),
b.z +
w * (
c.z -
b.z)};
869 Vec3f<T> d =
p - proj;
874 T denom =
T(1.0f) / (va + vb + vc);
878 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};
880 Vec3f<T> d =
p - proj;
885inline Vec3f<T> normalize(
const Vec3f<T>&
v)
888 if (len2 ==
T(0.0f)) {
889 std::cerr <<
"Degnerate triangle. Cannot determine normal";
892 T invLen =
T(1.0f) / std::sqrt(len2);
893 return {
v.x * invLen,
v.y * invLen,
v.z * invLen};
897inline Vec3f<T> triangleNormal(
const Vec3f<T>&
a,
const Vec3f<T>&
b,
const Vec3f<T>&
c)
899 const Vec3f<T> e1 =
b -
a;
900 const Vec3f<T> e2 =
c -
a;
901 return normalize(cross(e1, e2));
913 double local_step = Big();
915 using Scalar = float;
916 using Vec3 = bvh::v2::Vec<Scalar, 3>;
917 using Node = bvh::v2::Node<Scalar, 3>;
918 using Bvh = bvh::v2::Bvh<Node>;
919 using Ray = bvh::v2::Ray<Scalar, 3>;
922 auto mybvh = (Bvh*)fBVH;
928 auto truncate_roundup = [](
double orig) {
929 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
931 return static_cast<float>(orig + epsilon);
935 const auto topnode_bbox = mybvh->get_root().get_bbox();
936 if ((-point[0] + topnode_bbox.min[0]) > stepmax) {
939 if ((-point[1] + topnode_bbox.min[1]) > stepmax) {
942 if ((-point[2] + topnode_bbox.min[2]) > stepmax) {
945 if ((point[0] - topnode_bbox.max[0]) > stepmax) {
948 if ((point[1] - topnode_bbox.max[1]) > stepmax) {
951 if ((point[2] - topnode_bbox.max[2]) > stepmax) {
956 Ray ray(Vec3(point[0], point[1], point[2]),
957 Vec3(dir[0], dir[1], dir[2]),
959 truncate_roundup(local_step));
961 static constexpr bool use_robust_traversal =
true;
963 Vertex_t dir_v{dir[0], dir[1], dir[2]};
965 bvh::v2::GrowingStack<Bvh::Index>
stack;
966 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index,
stack, [&](
size_t begin,
size_t end) {
967 for (
size_t prim_id = begin; prim_id <
end; ++prim_id) {
968 auto objectid = mybvh->prim_ids[prim_id];
969 const auto& facet = fFacets[objectid];
970 const auto&
n = fOutwardNormals[objectid];
973 if (
n.Dot(dir_v) > 0.) {
977 auto thisdist = rayTriangle(
Vertex_t(point[0], point[1], point[2]), dir_v,
978 fVertices[facet[0]], fVertices[facet[1]], fVertices[facet[2]], 0.);
980 if (thisdist < local_step) {
981 local_step = thisdist;
997 double local_step = Big();
999 using Scalar = float;
1000 using Vec3 = bvh::v2::Vec<Scalar, 3>;
1001 using Node = bvh::v2::Node<Scalar, 3>;
1002 using Bvh = bvh::v2::Bvh<Node>;
1003 using Ray = bvh::v2::Ray<Scalar, 3>;
1006 auto mybvh = (Bvh*)fBVH;
1012 auto truncate_roundup = [](
double orig) {
1013 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
1015 return static_cast<float>(orig + epsilon);
1019 Ray ray(Vec3(point[0], point[1], point[2]),
1020 Vec3(dir[0], dir[1], dir[2]),
1022 truncate_roundup(local_step));
1024 static constexpr bool use_robust_traversal =
true;
1026 Vertex_t dir_v{dir[0], dir[1], dir[2]};
1028 bvh::v2::GrowingStack<Bvh::Index>
stack;
1029 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index,
stack, [&](
size_t begin,
size_t end) {
1030 for (
size_t prim_id = begin; prim_id <
end; ++prim_id) {
1031 auto objectid = mybvh->prim_ids[prim_id];
1032 auto facet = fFacets[objectid];
1033 const auto&
n = fOutwardNormals[objectid];
1036 if (
n.Dot(dir_v) <= 0.) {
1040 const auto&
v0 = fVertices[facet[0]];
1041 const auto&
v1 = fVertices[facet[1]];
1042 const auto&
v2 = fVertices[facet[2]];
1045 rayTriangle(
Vertex_t{point[0], point[1], point[2]}, dir_v,
v0,
v1,
v2, 0.);
1046 if (t < local_step) {
1066 for (
size_t i = 0;
i < fFacets.size(); ++
i) {
1067 auto& facet = fFacets[
i];
1068 auto a = fVertices[facet[0]];
1069 auto b = fVertices[facet[1]];
1070 auto c = fVertices[facet[2]];
1072 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]);
1080void O2Tessellated::BuildBVH()
1082 using Scalar = float;
1083 using BBox = bvh::v2::BBox<Scalar, 3>;
1084 using Vec3 = bvh::v2::Vec<Scalar, 3>;
1085 using Node = bvh::v2::Node<Scalar, 3>;
1086 using Bvh = bvh::v2::Bvh<Node>;
1089 auto GetBoundingBox = [
this](TGeoFacet
const& facet) {
1091 const auto nvertices = facet.GetNvert();
1092 assert(nvertices == 3);
1094 const auto&
v1 = fVertices[facet[0]];
1095 const auto&
v2 = fVertices[facet[1]];
1096 const auto&
v3 = fVertices[facet[2]];
1098 bbox.min[0] = std::min(std::min(
v1[0],
v2[0]),
v3[0]) - 0.001f;
1099 bbox.min[1] = std::min(std::min(
v1[1],
v2[1]),
v3[1]) - 0.001f;
1100 bbox.min[2] = std::min(std::min(
v1[2],
v2[2]),
v3[2]) - 0.001f;
1101 bbox.max[0] = std::max(std::max(
v1[0],
v2[0]),
v3[0]) + 0.001f;
1102 bbox.max[1] = std::max(std::max(
v1[1],
v2[1]),
v3[1]) + 0.001f;
1103 bbox.max[2] = std::max(std::max(
v1[2],
v2[2]),
v3[2]) + 0.001f;
1109 std::vector<BBox> bboxes;
1110 std::vector<Vec3> centers;
1113 int nd = fFacets.size();
1114 for (
int i = 0;
i < nd; ++
i) {
1115 auto& facet = fFacets[
i];
1118 (bboxes).push_back(GetBoundingBox(facet));
1119 centers.emplace_back((bboxes).back().get_center());
1129 typename bvh::v2::DefaultBuilder<Node>::Config config;
1130 config.quality = bvh::v2::DefaultBuilder<Node>::Quality::High;
1131 auto bvh = bvh::v2::DefaultBuilder<Node>::build(bboxes, centers, config);
1132 auto bvhptr =
new Bvh;
1133 *bvhptr = std::move(
bvh);
1134 fBVH = (
void*)(bvhptr);
1145 using Scalar = float;
1146 using Vec3 = bvh::v2::Vec<Scalar, 3>;
1147 using Node = bvh::v2::Node<Scalar, 3>;
1148 using Bvh = bvh::v2::Bvh<Node>;
1149 using Ray = bvh::v2::Ray<Scalar, 3>;
1152 auto mybvh = (Bvh*)fBVH;
1158 auto truncate_roundup = [](
double orig) {
1159 float epsilon = std::numeric_limits<float>::epsilon() * std::fabs(orig);
1161 return static_cast<float>(orig + epsilon);
1165 if (!TGeoBBox::Contains(point)) {
1172 Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757};
1174 double local_step = Big();
1176 Ray ray(Vec3(point[0], point[1], point[2]),
1177 Vec3(test_dir[0], test_dir[1], test_dir[2]),
1179 truncate_roundup(local_step));
1181 static constexpr bool use_robust_traversal =
true;
1184 bvh::v2::GrowingStack<Bvh::Index>
stack;
1185 size_t crossings = 0;
1186 mybvh->intersect<
false, use_robust_traversal>(ray, mybvh->get_root().index,
stack, [&](
size_t begin,
size_t end) {
1187 for (
size_t prim_id = begin; prim_id <
end; ++prim_id) {
1188 auto objectid = mybvh->prim_ids[prim_id];
1189 auto& facet = fFacets[objectid];
1192 const auto&
v0 = fVertices[facet[0]];
1193 const auto&
v1 = fVertices[facet[1]];
1194 const auto&
v2 = fVertices[facet[2]];
1196 const double t = rayTriangle(
Vertex_t(point[0], point[1], point[2]),
1197 test_dir,
v0,
v1,
v2, 0.);
1199 if (t != std::numeric_limits<double>::infinity()) {
1206 return crossings & 1;
1214struct BVHPrioElement {
1224template <
typename Comparator>
1225class BVHPrioQueue :
public std::priority_queue<BVHPrioElement, std::vector<BVHPrioElement>, Comparator>
1228 using std::priority_queue<BVHPrioElement, std::vector<BVHPrioElement>,
1232 void clear() { this->c.clear(); }
1238template <
bool returnFace>
1239inline Double_t O2Tessellated::SafetyKernel(
const Double_t* point,
bool in,
int* closest_facet_id)
const
1243 float smallest_safety_sq = TGeoShape::Big();
1245 using Scalar = float;
1246 using Vec3 = bvh::v2::Vec<Scalar, 3>;
1247 using Node = bvh::v2::Node<Scalar, 3>;
1248 using Bvh = bvh::v2::Bvh<Node>;
1251 auto mybvh = (Bvh*)fBVH;
1254 Vec3 testpoint(point[0], point[1], point[2]);
1256 auto currnode = mybvh->nodes[0];
1258 bool outside_top =
false;
1264 return std::sqrt(safety_sq_to_top);
1269 auto cmp = [](BVHPrioElement
a, BVHPrioElement
b) {
return a.value >
b.value; };
1270 static thread_local BVHPrioQueue<
decltype(
cmp)> queue(
cmp);
1274 float current_safety_to_node_sq = 0.f;
1277 *closest_facet_id = -1;
1281 if (currnode.is_leaf()) {
1283 const auto begin_prim_id = currnode.index.first_id();
1284 const auto end_prim_id = begin_prim_id + currnode.index.prim_count();
1286 for (
auto p_id = begin_prim_id; p_id < end_prim_id; p_id++) {
1287 const auto object_id = mybvh->prim_ids[p_id];
1289 const auto& facet = fFacets[object_id];
1290 const auto&
v1 = fVertices[facet[0]];
1291 const auto&
v2 = fVertices[facet[1]];
1292 const auto&
v3 = fVertices[facet[2]];
1294 auto thissafetySQ = pointTriangleDistSq(Vec3f{point[0], point[1], point[2]}, Vec3f{
v1[0],
v1[1],
v1[2]},
1295 Vec3f{
v2[0],
v2[1],
v2[2]}, Vec3f{
v3[0],
v3[1],
v3[2]});
1297 if (thissafetySQ < smallest_safety_sq) {
1298 smallest_safety_sq = thissafetySQ;
1300 *closest_facet_id = object_id;
1307 const auto leftchild_id = currnode.index.first_id();
1308 const auto rightchild_id = leftchild_id + 1;
1310 for (
size_t childid : {leftchild_id, rightchild_id}) {
1311 if (childid >= mybvh->nodes.size()) {
1315 const auto&
node = mybvh->nodes[childid];
1320 queue.push(BVHPrioElement{childid, -1.});
1323 if (safety_to_node_square <= smallest_safety_sq) {
1325 queue.push(BVHPrioElement{childid, safety_to_node_square});
1331 if (queue.size() > 0) {
1332 auto currElement = queue.top();
1333 currnode = mybvh->nodes[currElement.bvh_node_id];
1334 current_safety_to_node_sq = currElement.value;
1339 }
while (current_safety_to_node_sq <= smallest_safety_sq);
1341 return std::nextafter(std::sqrt(smallest_safety_sq), 0.0f);
1353 return SafetyKernel<false>(point, in);
1367 int closest_face_id = -1;
1368 SafetyKernel<true>(point,
true, &closest_face_id);
1370 if (closest_face_id < 0) {
1377 const auto&
n = fOutwardNormals[closest_face_id];
1383 if (norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2] < 0) {
1396 Vertex_t p(point[0], point[1], point[2]);
1397 Vertex_t d(dir[0], dir[1], dir[2]);
1399 double dist = Big();
1400 for (
size_t i = 0;
i < fFacets.size(); ++
i) {
1401 const auto& facet = fFacets[
i];
1402 const auto&
n = fOutwardNormals[
i];
1405 if (
n.Dot(d) <= 0.0) {
1409 const auto&
v0 = fVertices[facet[0]];
1410 const auto&
v1 = fVertices[facet[1]];
1411 const auto&
v2 = fVertices[facet[2]];
1413 const double t = rayTriangle(p, d,
v0,
v1,
v2, 0.);
1427 Vertex_t p(point[0], point[1], point[2]);
1428 Vertex_t d(dir[0], dir[1], dir[2]);
1430 double dist = Big();
1431 for (
size_t i = 0;
i < fFacets.size(); ++
i) {
1432 const auto& facet = fFacets[
i];
1433 const auto&
n = fOutwardNormals[
i];
1436 if (
n.Dot(d) > 0.0) {
1440 const auto&
v0 = fVertices[facet[0]];
1441 const auto&
v1 = fVertices[facet[1]];
1442 const auto&
v2 = fVertices[facet[2]];
1444 const double t = rayTriangle(p, d,
v0,
v1,
v2, 0.);
1459 const Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757};
1461 Vertex_t p(point[0], point[1], point[2]);
1464 for (
size_t i = 0;
i < fFacets.size(); ++
i) {
1465 const auto& facet = fFacets[
i];
1467 const auto&
v0 = fVertices[facet[0]];
1468 const auto&
v1 = fVertices[facet[1]];
1469 const auto&
v2 = fVertices[facet[2]];
1471 const double t = rayTriangle(p, test_dir,
v0,
v1,
v2, 0.);
1472 if (t != std::numeric_limits<double>::infinity()) {
1476 return (crossings & 1);
1483void O2Tessellated::Streamer(TBuffer&
b)
1485 if (
b.IsReading()) {
1486 b.ReadClassBuffer(O2Tessellated::Class(),
this);
1489 b.WriteClassBuffer(O2Tessellated::Class(),
this);
1496void O2Tessellated::CalculateNormals()
1498 fOutwardNormals.clear();
1499 for (
auto& facet : fFacets) {
1500 auto&
v1 = fVertices[facet[0]];
1501 auto&
v2 = fVertices[facet[1]];
1502 auto&
v3 = fVertices[facet[2]];
1503 using Vec3d = Vec3f<double>;
1504 auto norm = triangleNormal(Vec3d{
v1[0],
v1[1],
v1[2]}, Vec3d{
v2[0],
v2[1],
v2[2]}, Vec3d{
v3[0],
v3[1],
v3[2]});
1505 fOutwardNormals.emplace_back(
Vertex_t{norm.x, norm.y, norm.z});
header::DataOrigin origin
std::function< int(const o2::mch::mapping::CathodeSegmentation &, int, rapidjson::Value &)> Comparator
std::unique_ptr< expressions::Node > node
Tessellated::Vertex_t Vertex_t
void SetSegsAndPols(TBuffer3D &buff) const override
Fills TBuffer3D structure for segments and polygons.
Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const override
Safety.
bool Contains(const Double_t *point) const override
Contains.
void GetMeshNumbers(int &nvert, int &nsegs, int &npols) const override
Returns numbers of vertices, segments and polygons composing the shape mesh.
Double_t DistFromOutside_Loop(const Double_t *point, const Double_t *dir) const
trivial (non-BVH) DistFromOutside function
bool AddFacet(const Vertex_t &pt0, const Vertex_t &pt1, const Vertex_t &pt2)
Adding a triangular facet from vertex positions in absolute coordinates.
bool FacetCheck(int ifacet) const
Check validity of facet.
const TBuffer3D & GetBuffer3D(int reqSections, Bool_t localFrame) const override
Fills a static 3D buffer and returns a reference.
Double_t Capacity() const override
Capacity.
void ComputeBBox() override
Compute bounding box.
void CloseShape(bool check=true, bool fixFlipped=true, bool verbose=true)
Close the shape: calculate bounding box and compact vertices.
static O2Tessellated * ImportFromObjFormat(const char *objfile, bool check=false, bool verbose=false)
Reader from .obj format.
Double_t DistFromInside_Loop(const Double_t *point, const Double_t *dir) const
trivial (non-BVH) DistFromInside function
bool CheckClosure(bool fixFlipped=true, bool verbose=true)
Check closure of the solid and check/fix flipped normals.
void ComputeNormal(const Double_t *point, const Double_t *dir, Double_t *norm) const override
ComputeNormal interface.
void Print(Option_t *option="") const override
Prints basic info.
void ResizeCenter(double maxsize)
Resize and center the shape in a box of size maxsize.
TBuffer3D * MakeBuffer3D() const override
int AddVertex(const Vertex_t &vert)
Add a vertex checking for duplicates, returning the vertex index.
Vertex_t FacetComputeNormal(int ifacet, bool °enerated) const
Compute normal for a given facet.
bool Contains_Loop(const Double_t *point) const
trivial (non-BVH) Contains
Tessellated::Vertex_t Vertex_t
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 SetPoints(double *points) const override
Fill tessellated points to an array.
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.
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * value
GLfloat GLfloat GLfloat GLfloat v3
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLfloat GLfloat GLfloat v2
GLdouble GLdouble GLdouble z
std::variant< OriginValueMatcher, DescriptionValueMatcher, SubSpecificationTypeValueMatcher, std::unique_ptr< DataDescriptorMatcher >, ConstantValueMatcher, StartTimeValueMatcher > Node
void check(const std::vector< std::string > &arguments, const std::vector< ConfigParamSpec > &workflowOptions, const std::vector< DeviceSpec > &deviceSpecs, CheckMatrix &matrix)
Vertex< T > operator-(const Vertex< T > &a, const Vertex< T > &b)
auto dot(const Vertex< T > &a, const Vertex< T > &b) -> decltype(a.x *b.x)
VectorOfTObjectPtrs other
char const *restrict const cmp