40std::ostream &operator<<(std::ostream &os,
TGeoFacet const &facet)
43 for (
int i = 0; i < facet.GetNvert(); ++i) {
44 os << facet.GetVertex(i);
45 if (i != facet.GetNvert() - 1)
78 constexpr double kTolerance = 1.e-20;
81 for (
int i = 0; i <
fNvert - 1; ++i) {
83 if (e1.Mag2() < kTolerance)
85 for (
int j = i + 1; j <
fNvert; ++j) {
87 if (e2.Mag2() < kTolerance)
89 normal = Vertex_t::Cross(e1, e2);
91 if (normal.Mag2() < kTolerance)
105 constexpr double kTolerance = 1.e-10;
106 bool degenerated =
true;
109 std::cout <<
"Facet: " << *
this <<
" is degenerated\n";
114 double surfaceArea = 0.;
115 for (
int i = 1; i <
fNvert - 1; ++i) {
118 surfaceArea += 0.5 * Vertex_t::Cross(e1, e2).Mag();
120 if (surfaceArea < kTolerance) {
121 std::cout <<
"Facet: " << *
this <<
" has zero surface area\n";
140 int nvert = nvertices;
143 if (vert[(i + 1) % nvert] == vert[i]) {
145 for (
int j = i + 2; j < nvert; ++j)
146 vert[j - 1] = vert[j];
161 bool neighbour =
false;
162 int line1[2], line2[2];
164 for (
int i = 0; i <
fNvert; ++i) {
167 for (
int j = 0; j < other.
GetNvert(); ++j) {
171 if (++npoints == 2) {
173 bool order1 = line1[1] == line1[0] + 1;
174 bool order2 = line2[1] == (line2[0] + 1) % other.
GetNvert();
175 flip = (order1 == order2);
222 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
232 Error(
"AddFacet",
"Triangular facet at index %d degenerated. Not adding.",
GetNfacets());
237 fFacets.emplace_back(pt0, pt1, pt2);
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());
269 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
279 Error(
"AddFacet",
"Quadrilateral facet at index %d degenerated. Not adding.",
GetNfacets());
286 fFacets.emplace_back(vert[0], vert[1], vert[2]);
288 fFacets.emplace_back(vert[0], vert[1], vert[2], vert[3]);
301 Error(
"AddFacet",
"Shape %s already fully defined. Not adding",
GetName());
305 Error(
"AddFacet",
"Shape %s Cannot add facets by indices without vertices. Not adding",
GetName());
320 constexpr double tolerance = 1.e-10;
321 constexpr int ngrid = 100;
329 invExtent[0] = 0.5 / (
fDX + tolerance);
330 invExtent[1] = 0.5 / (
fDY + tolerance);
331 invExtent[2] = 0.5 / (
fDZ + tolerance);
349 for (
const auto ¤t_vert :
fVertices) {
350 if (current_vert ==
vertex)
362 for (
int i = 0; i < 3; ++i) {
363 int ind =
int(ngrid * (
vertex[i] - minExtent[i]) * invExtent[i]);
364 assert(ind < (
int)ngrid);
365 for (
int j = i + 1; j < 3; ++j)
373 int ind[4] = {-1, -1, -1, -1};
376 int nvert = facet.GetNvert();
377 for (
int i = 0; i < nvert; ++i) {
381 facet.SetVertices(&
fVertices, nvert, ind[0], ind[1], ind[2], ind[3]);
385 using CellVec_t = std::vector<int>;
386 auto grid =
new std::array<CellVec_t, ngrid * ngrid * ngrid>;
388 int nvert = facet.GetNvert();
389 for (
int i = 0; i < nvert; ++i) {
392 int hashind = GetHashIndex(
vertex);
393 bool isAdded =
false;
394 for (
auto ivert : grid->operator[](hashind)) {
404 grid->operator[](hashind).push_back(ind[i]);
407 facet.SetVertices(&
fVertices, nvert, ind[0], ind[1], ind[2], ind[3]);
432 bool hasorphans =
false;
433 bool hasflipped =
false;
434 for (
int i = 0; i <
fNfacets; ++i) {
439 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
441 if (nn[icrt] >=
fFacets[icrt].GetNvert())
443 for (
int i = icrt + 1; i <
fNfacets; ++i) {
444 bool isneighbour =
fFacets[icrt].IsNeighbour(
fFacets[i], flipped[i]);
447 flipped[i] = !flipped[i];
452 if (nn[icrt] ==
fFacets[icrt].GetNvert())
456 if (nn[icrt] <
fFacets[icrt].GetNvert())
460 if (hasorphans && verbose) {
461 Error(
"Check",
"Tessellated solid %s has following not fully connected facets:",
GetName());
462 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
463 if (nn[icrt] <
fFacets[icrt].GetNvert())
464 std::cout << icrt <<
" (" <<
fFacets[icrt].GetNvert() <<
" edges, " << nn[icrt] <<
" neighbours)\n";
471 Warning(
"Check",
"Tessellated solid %s has following facets with flipped normals:",
GetName());
472 for (
int icrt = 0; icrt <
fNfacets; ++icrt) {
475 std::cout << icrt <<
"\n";
482 if (nfixed && verbose)
483 Info(
"Check",
"Automatically flipped %d facets to match first defined facet", nfixed);
497 double vmin[3] = {kBig, kBig, kBig};
498 double vmax[3] = {-kBig, -kBig, -kBig};
499 for (
const auto &facet :
fFacets) {
500 for (
int i = 0; i < facet.GetNvert(); ++i) {
501 for (
int j = 0; j < 3; ++j) {
502 vmin[j] =
TMath::Min(vmin[j], facet.GetVertex(i).operator[](j));
503 vmax[j] =
TMath::Max(vmax[j], facet.GetVertex(i).operator[](j));
507 fDX = 0.5 * (vmax[0] - vmin[0]);
508 fDY = 0.5 * (vmax[1] - vmin[1]);
509 fDZ = 0.5 * (vmax[2] - vmin[2]);
510 for (
int i = 0; i < 3; ++i)
511 fOrigin[i] = 0.5 * (vmax[i] + vmin[i]);
531 const int nsegs =
fNseg;
546 std::cout <<
"=== Tessellated shape " <<
GetName() <<
" having " <<
GetNvertices() <<
" vertices and "
557 int *pols = buff.
fPols;
562 for (
const auto &facet :
fFacets) {
563 auto nvert = facet.GetNvert();
565 pols[indpol++] = nvert;
566 for (
auto j = 0; j < nvert; ++j) {
567 int k = (j + 1) % nvert;
570 segs[indseg++] = facet.GetVertexIndex(j);
571 segs[indseg++] = facet.GetVertexIndex(k);
573 pols[indpol + nvert - j - 1] = sind++;
612 Error(
"ResizeCenter",
"Not all faces are defined");
617 double scale = maxsize / maxedge;
618 for (
size_t i = 0; i <
fVertices.size(); ++i) {
637 const int nsegs =
fNseg;
641 if (buffer.
SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) {
665 vector<Vertex_t> vertices;
666 vector<string> sfacets;
674 FacetInd_t(
int a,
int b,
int c)
681 FacetInd_t(
int a,
int b,
int c,
int d)
691 vector<FacetInd_t> facets;
714 ifstream
file(objfile);
715 if (!
file.is_open()) {
716 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unable to open %s", objfile);
721 stringstream ss(
line);
725 if (
line.rfind(
"v", 0) == 0 &&
line.rfind(
"vt", 0) != 0 &&
line.rfind(
"vn", 0) != 0 &&
line.rfind(
"vn", 0) != 0) {
727 double pos[4] = {0, 0, 0, 1};
728 ss >> tag >> pos[0] >> pos[1] >> pos[2] >> pos[3];
729 vertices.emplace_back(pos[0] * pos[3], pos[1] * pos[3], pos[2] * pos[3]);
732 else if (
line.rfind(
"f", 0) == 0) {
738 sfacets.push_back(word);
739 if (sfacets.size() > 4 || sfacets.size() < 3) {
740 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Detected face having unsupported %zu vertices",
745 for (
auto &sword : sfacets) {
746 stringstream ssword(sword);
748 getline(ssword, token,
'/');
751 ind[nvert++] = stoi(token) - 1;
752 if (ind[nvert - 1] < 0) {
753 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Unsupported relative vertex index definition in %s",
759 facets.emplace_back(ind[0], ind[1], ind[2]);
761 facets.emplace_back(ind[0], ind[1], ind[2], ind[3]);
765 int nvertices = (
int)vertices.size();
766 int nfacets = (
int)facets.size();
768 ::Error(
"TGeoTessellated::ImportFromObjFormat",
"Not enough faces detected in %s", objfile);
772 string sobjfile(objfile);
774 std::cout <<
"Read " << nvertices <<
" vertices and " << nfacets <<
" facets from " << sobjfile << endl;
776 auto tsl =
new TGeoTessellated(sobjfile.erase(sobjfile.find_last_of(
'.')).c_str(), vertices);
778 for (
int i = 0; i < nfacets; ++i) {
779 auto facet = facets[i];
780 if (facet.nvert == 3)
781 tsl->AddFacet(facet.i0, facet.i1, facet.i2);
783 tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3);
785 tsl->CloseShape(check,
true, verbose);
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.
virtual void FillBuffer3D(TBuffer3D &buffer, Int_t reqSections, Bool_t localFrame) const
Fills the supplied buffer, with sections in desired frame See TBuffer3D.h for explanation of sections...
Tessellated::VertexVec_t VertexVec_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)
int GetVertexIndex(int ivert) const
Vertex_t & GetVertex(int ivert)
int fNvert
array of vertices
Vertex_t ComputeNormal(bool °enerated) const
const TGeoFacet & operator=(const TGeoFacet &other)
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)
virtual const char * GetName() const
Get the shape name.
void ResizeCenter(double maxsize)
Resize and center the shape in a box of size maxsize.
virtual void Print(Option_t *option="") const
Prints basic info.
virtual const TBuffer3D & GetBuffer3D(int reqSections, Bool_t localFrame) const
Fills a static 3D buffer and returns a reference.
virtual void SetSegsAndPols(TBuffer3D &buff) const
Fills TBuffer3D structure for segments and polygons.
bool CheckClosure(bool fixFlipped=true, bool verbose=true)
Check closure of the solid and check/fix flipped normals.
virtual void SetPoints(double *points) const
Fill tessellated points to an array.
virtual TBuffer3D * MakeBuffer3D() const
Creates a TBuffer3D describing this shape.
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
std::vector< TGeoFacet > fFacets
static TGeoTessellated * ImportFromObjFormat(const char *objfile, bool check=false, bool verbose=false)
Reader from .obj format.
void ComputeBBox()
Compute bounding box.
virtual void AfterStreamer()
Function to be called after reading tessellated volumes from the geometry file.
bool AddFacet(const Vertex_t &pt0, const Vertex_t &pt1, const Vertex_t &pt2)
Adding a triangular facet from vertex positions in absolute coordinates.
virtual void GetMeshNumbers(int &nvert, int &nsegs, int &npols) const
Returns numbers of vertices, segments and polygons composing the shape mesh.
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)
Short_t Min(Short_t a, Short_t b)
Typedefs used by the geometry group.
static int AddVertex(GLUtesselator *tess, GLdouble coords[3], void *data)
void flip(struct mesh *m, struct behavior *b, struct otri *flipedge)