48 int nvert = nvertices;
51 if (vert[(i + 1) % nvert] == vert[i]) {
53 for (
int j = i + 2; j < nvert; ++j)
54 vert[j - 1] = vert[j];
69 bool neighbour =
false;
70 int line1[2], line2[2];
72 for (
int i = 0; i <
fNvert; ++i) {
75 for (
int j = 0; j < other.
GetNvert(); ++j) {
76 if (ivert == other[j]) {
81 bool order1 = line1[1] == line1[0] + 1;
82 bool order2 = line2[1] == (line2[0] + 1) % other.
GetNvert();
83 flip = (order1 == order2);
118 constexpr double tolerance = 1.e-10;
119 auto vertexHash = [&](
Vertex_t const &vertex) {
123 auto hash_combine = [](
long seed,
const long value) {
124 return seed ^ (std::hash<long>{}(
value) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
126 for (
int i = 0; i < 3; i++) {
128 hash = hash_combine(hash, std::roundl(vertex[i] / tolerance));
133 auto hash = vertexHash(vert);
134 bool isAdded =
false;
138 for (
auto it = range.first; it != range.second; ++it) {
159 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
169 Error(
"AddFacet",
"Triangular facet at index %d degenerated. Not adding.",
GetNfacets());
173 for (
auto i = 0; i < 3; ++i)
176 fFacets.emplace_back(ind[0], ind[1], ind[2]);
189 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
193 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding",
GetName());
198 fFacets.emplace_back(i0, i1, i2);
208 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
218 Error(
"AddFacet",
"Quadrilateral facet at index %d degenerated. Not adding.",
GetNfacets());
223 for (
auto i = 0; i < nvert; ++i)
227 fFacets.emplace_back(ind[0], ind[1], ind[2]);
229 fFacets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
242 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
246 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding",
GetName());
251 fFacets.emplace_back(i0, i1, i2, i3);
261 constexpr double kTolerance = 1.e-20;
262 auto const &facet =
fFacets[ifacet];
263 int nvert = facet.GetNvert();
266 for (
int i = 0; i < nvert - 1; ++i) {
268 if (e1.
Mag2() < kTolerance)
270 for (
int j = i + 1; j < nvert; ++j) {
272 if (e2.
Mag2() < kTolerance)
276 if (normal.
Mag2() < kTolerance)
293 constexpr double kTolerance = 1.e-10;
294 auto const &facet =
fFacets[ifacet];
295 int nvert = facet.GetNvert();
296 bool degenerated =
true;
299 std::cout <<
"Facet: " << ifacet <<
" is degenerated\n";
304 double surfaceArea = 0.;
305 for (
int i = 1; i < nvert - 1; ++i) {
310 if (surfaceArea < kTolerance) {
311 std::cout <<
"Facet: " << ifacet <<
" has zero surface area\n";
350 bool hasorphans =
false;
351 bool hasflipped =
false;
352 for (
int i = 0; i <
fNfacets; ++i) {
357 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
359 if (nn[icrt] >=
fFacets[icrt].GetNvert())
361 for (
int i = icrt + 1; i <
fNfacets; ++i) {
362 bool isneighbour =
fFacets[icrt].IsNeighbour(
fFacets[i], flipped[i]);
365 flipped[i] = !flipped[i];
370 if (nn[icrt] ==
fFacets[icrt].GetNvert())
374 if (nn[icrt] <
fFacets[icrt].GetNvert())
378 if (hasorphans && verbose) {
379 Error(
"Check",
"Tessellated solid %s has following not fully connected facets:",
GetName());
380 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
381 if (nn[icrt] <
fFacets[icrt].GetNvert())
382 std::cout << icrt <<
" (" <<
fFacets[icrt].GetNvert() <<
" edges, " << nn[icrt] <<
" neighbours)\n";
389 Warning(
"Check",
"Tessellated solid %s has following facets with flipped normals:",
GetName());
390 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
393 std::cout << icrt <<
"\n";
400 if (nfixed && verbose)
401 Info(
"Check",
"Automatically flipped %d facets to match first defined facet", nfixed);
415 double vmin[3] = {kBig, kBig, kBig};
416 double vmax[3] = {-kBig, -kBig, -kBig};
417 for (
const auto &facet :
fFacets) {
418 for (
int i = 0; i < facet.GetNvert(); ++i) {
419 for (
int j = 0; j < 3; ++j) {
425 fDX = 0.5 * (vmax[0] - vmin[0]);
426 fDY = 0.5 * (vmax[1] - vmin[1]);
427 fDZ = 0.5 * (vmax[2] - vmin[2]);
428 for (
int i = 0; i < 3; ++i)
429 fOrigin[i] = 0.5 * (vmax[i] + vmin[i]);
449 const int nsegs =
fNseg;
464 std::cout <<
"=== Tessellated shape " <<
GetName() <<
" having " <<
GetNvertices() <<
" vertices and "
475 int *pols = buff.
fPols;
480 for (
const auto &facet :
fFacets) {
481 auto nvert = facet.GetNvert();
483 pols[indpol++] = nvert;
484 for (
auto j = 0; j < nvert; ++j) {
485 int k = (j + 1) % nvert;
488 segs[indseg++] = facet[j];
489 segs[indseg++] = facet[k];
491 pols[indpol + nvert - j - 1] = sind++;
504 vertex.CopyTo(&
points[ind]);
516 points[ind++] = vertex.x();
517 points[ind++] = vertex.y();
518 points[ind++] = vertex.z();
530 Error(
"ResizeCenter",
"Not all faces are defined");
535 double scale = maxsize / maxedge;
536 for (
size_t i = 0; i <
fVertices.size(); ++i) {
555 const int nsegs =
fNseg;
559 if (buffer.
SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) {
581 using std::vector, std::string, std::ifstream, std::stringstream, std::endl;
583 vector<Vertex_t> vertices;
584 vector<string> sfacets;
592 FacetInd_t(
int a,
int b,
int c)
599 FacetInd_t(
int a,
int b,
int c,
int d)
609 vector<FacetInd_t> facets;
632 ifstream file(objfile);
633 if (!file.is_open()) {
634 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unable to open %s", objfile);
638 while (getline(file,
line)) {
639 stringstream ss(
line);
643 if (
line.rfind(
'v', 0) == 0 &&
line.rfind(
"vt", 0) != 0 &&
line.rfind(
"vn", 0) != 0 &&
line.rfind(
"vn", 0) != 0) {
645 double pos[4] = {0, 0, 0, 1};
646 ss >> tag >> pos[0] >> pos[1] >> pos[2] >> pos[3];
647 vertices.emplace_back(pos[0] * pos[3], pos[1] * pos[3], pos[2] * pos[3]);
650 else if (
line.rfind(
'f', 0) == 0) {
656 sfacets.push_back(word);
657 if (sfacets.size() > 4 || sfacets.size() < 3) {
658 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Detected face having unsupported %zu vertices",
663 for (
auto &sword : sfacets) {
664 stringstream ssword(sword);
666 getline(ssword, token,
'/');
669 ind[nvert++] = stoi(token) - 1;
670 if (ind[nvert - 1] < 0) {
671 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unsupported relative vertex index definition in %s",
677 facets.emplace_back(ind[0], ind[1], ind[2]);
679 facets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
683 int nvertices = (
int)vertices.size();
684 int nfacets = (
int)facets.size();
686 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Not enough faces detected in %s", objfile);
690 string sobjfile(objfile);
692 std::cout <<
"Read " << nvertices <<
" vertices and " << nfacets <<
" facets from " << sobjfile << endl;
694 auto tsl =
new TGeoTessellated(sobjfile.erase(sobjfile.find_last_of(
'.')).c_str(), vertices);
696 for (
int i = 0; i < nfacets; ++i) {
697 auto facet = facets[i];
698 if (facet.nvert == 3)
699 tsl->AddFacet(facet.i0, facet.i1, facet.i2);
701 tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3);
703 tsl->CloseShape(check,
true, verbose);
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t points
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.
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,...
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.
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 FacetCheck(int ifacet) const
Check validity of facet.
void Print(Option_t *option="") const override
Prints basic info.
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.
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.
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
bool AddFacet(const Vertex_t &pt0, const Vertex_t &pt1, const Vertex_t &pt2)
Adding a triangular facet from vertex positions in absolute coordinates.
std::vector< Vertex_t > fVertices
bool fClosedBody
Shape fully defined.
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 Info(const char *method, const char *msgfmt,...) const
Issue info message.
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
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.