diff --git a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronGeneric.h b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronGeneric.h index f367de4e8bf2bdb5e1df85dedb828c1cf8b0abfa..8bc1bf7536ddef46bbddf03ff0715cabca2cabcb 100644 --- a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronGeneric.h +++ b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronGeneric.h @@ -21,7 +21,7 @@ class GeoPolyhedronGeneric : public GeoShape { GeoPolyhedronGeneric(){}; // Constructor - GeoPolyhedronGeneric(const GeoShape*); + GeoPolyhedronGeneric(const GeoShape*, const GeoTrf::Transform3D& trf = GeoTrf::Transform3D::Identity(), int polyhedrize = 0); // Copy constructor GeoPolyhedronGeneric(const GeoPolyhedronGeneric& gpg); @@ -84,6 +84,9 @@ class GeoPolyhedronGeneric : public GeoShape { // check of the hermeticity of the polyhedron (all edge need to be mirrored), plus at least four faces required, false otherwise bool isValid ( bool debugMode = false) const; + void setStatus( int status) { m_status = status;} + int getStatus() const { return m_status; } + // Returns coordinates of the specified vertex GeoTrf::Vector3D getVertex(unsigned int i) const { return m_Vertices.at(i); @@ -114,7 +117,6 @@ class GeoPolyhedronGeneric : public GeoShape { virtual bool isPolyhedron () const { return true; } - virtual ~GeoPolyhedronGeneric() = default; protected: @@ -122,6 +124,7 @@ protected: private: static const std::string s_classType; static const ShapeType s_classTypeID; + GeoTrf::Transform3D m_transform{GeoTrf::Transform3D::Identity()}; std::vector<GeoTrf::Vector3D> m_Vertices{}; std::vector< std::vector<size_t> > m_Faces{}; @@ -140,7 +143,10 @@ protected: double getRefSpan(int face = -1) const; // for debugging purposes - int m_origin{0}; + int m_origin{-1}; + + // status : -1 unchecked, 0 valid (may be empty), 1 non-polyhedrizable component, 2 failure to construct + int m_status{-1}; }; diff --git a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronManipulator.h b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronManipulator.h index c0b1fe90fcf5c84fd07f86e5f1e1361421fa3332..f0252d310d1896cf1f6a62805f7dd7dfa6ef6b55 100644 --- a/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronManipulator.h +++ b/GeoModelCore/GeoModelKernel/GeoModelKernel/GeoPolyhedronManipulator.h @@ -12,8 +12,8 @@ * */ -#include "GeoModelKernel/GeoShape.h" #include <GeoModelKernel/GeoDefinitions.h> +#include "GeoModelKernel/GeoShape.h" #include "GeoModelKernel/GeoShapeShift.h" #include "GeoModelKernel/GeoPolyhedronGeneric.h" #include <string> @@ -21,13 +21,13 @@ class GeoShapeIntersection; class GeoShapeUnion; class GeoShapeSubtraction; -class GeoPolyhedronGeneric; struct ShiftedGeoShape { const GeoShape* shape{nullptr}; const GeoPolyhedronGeneric* phed{nullptr}; GeoTrf::Transform3D transform; double volume{-1}; // -1 not calculated/not analytical + int polyhedrize{16}; // >0 polyhedrize // constructor ShiftedGeoShape(const GeoShape* inputShape) { shape = inputShape; @@ -38,14 +38,15 @@ struct ShiftedGeoShape { transform = shift->getX()*transform; shape = shift->getOp(); } - if (!(shape->type()=="Union" || shape->type()=="Subtraction" || shape->type()=="Intersection") ) { + if ( !(shape->type()=="Union" || shape->type()=="Subtraction" || shape->type()=="Intersection") ) { volume = shape->volume(); - phed = new GeoPolyhedronGeneric(shape); + phed = new GeoPolyhedronGeneric(shape,GeoTrf::Transform3D::Identity(),polyhedrize); if (!phed->isValid()) phed=nullptr; // temporary / to deal with non-polyhedrized shapes } } }; + struct NPL_vertex{ int index; bool shared{false}; int overlapping_face{-1}; bool used{false}; int onEdge{-1}; bool onEdgeDummy{false}; int shared_adjacent{-1}; bool oriented{false}; // int alternative_face; @@ -72,7 +73,7 @@ struct NPL_edge{ struct NPL_ordered{ std::vector<size_t> vtx; std::vector<int> edges; - int top_overlap{-1}; bool shared{false}; bool oriented{false}; + int top_overlap{-1}; bool shared{false}; bool oriented{false}; bool guess_orientation{false}; void reorder(size_t a) { while ( vtx.front()!= a) { vtx.push_back(vtx.front()); @@ -81,6 +82,17 @@ struct NPL_ordered{ edges.erase(edges.begin()); } } + void reverse(std::vector<NPL_edge> plane_edges) { + std::vector<size_t> vtx_tmp; + std::vector<int> edges_tmp; + for (auto iv : vtx) vtx_tmp.insert(vtx_tmp.begin(),iv); + for (auto ie : edges) { + edges_tmp.insert(edges_tmp.begin(),plane_edges[ie].symmetrized); + } + edges_tmp.push_back(edges_tmp.front()); edges_tmp.erase(edges_tmp.begin()); // reorder to match vtx + vtx = vtx_tmp; + edges = edges_tmp; + } }; struct NPH_plane{ @@ -94,6 +106,7 @@ struct NPH_plane{ //std::vector<NPL_ordered> shared_subface; std::vector<NPL_ordered> subfaces; std::vector<NPL_edge> plane_edges; + std::vector<NPL_edge> edge_loop_origin; GeoTrf::Vector3D normal; std::vector<int> overlapping; NPH_plane(int index) { index_ph = index;} @@ -103,7 +116,7 @@ struct NPH_vertex{ int index{-1}; int index_ph{-1}; bool shared{false}; - int onDoublEdge{-1}; int hitDoublEdge{-1}; + //int onDoublEdge{-1}; //int hitDoublEdge{-1}; std::pair<int,int> hit_edge_edge; std::vector<std::pair<int,int> > edges; NPH_vertex() {hit_edge_edge = std::pair<int,int>(-1,-1);} @@ -146,10 +159,18 @@ class GeoPolyhedronManipulator { public: + // steering routine for volume calculation with pre-defined precision + double volumeBoolean( const GeoShape* shape, double tolerance, int mode) const; + + // resolve into generic polyhedron shape if possible, or deploy polyhedrization + GeoPolyhedronGeneric resolve( const GeoShape*, GeoTrf::Transform3D& trf, int polyhedrize = 0, int level = 0, bool debugMode = false ); + GeoPolyhedronGeneric* intersection( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode); GeoPolyhedronGeneric* subtraction( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode); GeoPolyhedronGeneric* uni( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode); - GeoPolyhedronGeneric* resolveBoolean(const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, int modeBoolean, bool debugMode); + GeoPolyhedronGeneric resolveBoolean(const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, int modeBoolean, bool debugMode); + + void collectFaceNumber(const GeoShape*, int& nFaces); private: @@ -170,7 +191,7 @@ class GeoPolyhedronManipulator void collectLines( std::vector<NPH_plane>& planes, std::vector<GeoTrf::Vector3D>& vtx, std::vector<NPH_vertex>& vlog, std::vector<NPH_edge>& edges, bool debugMode ) const; - std::vector<NPL_edge> evaluateVertexLogic(int plane_index, std::vector<NPH_vertex>& vlog, std::vector<NPH_edge> edges, + std::vector<NPL_edge> evaluateVertexLogic(int plane_index, std::vector<NPH_vertex> vlog, std::vector<NPH_edge> edges, std::vector<NPH_plane>& planes, std::vector<GeoTrf::Vector3D> vtx) const; bool insideFace(unsigned int plane_index, GeoTrf::Vector3D point, double precision = 1.e-5, bool debugMode = false) const { @@ -206,6 +227,11 @@ class GeoPolyhedronManipulator GeoTrf::Vector3D areaVec( std::vector<size_t> loop, std::vector< GeoTrf::Vector3D > vtx) const; + int nextOri(int input, std::vector<NPL_edge> plane_edges, std::vector<NPL_edge> edge_loop_origin, std::vector<int> availableEdges, bool previous = false) const; + + // for debugging purpose only + std::vector<std::pair<int,int> > missing_edges( const GeoPolyhedronGeneric gpg) const; + }; #endif diff --git a/GeoModelCore/GeoModelKernel/src/GeoPolyhedronGeneric.cxx b/GeoModelCore/GeoModelKernel/src/GeoPolyhedronGeneric.cxx index 28e9b1825ca4e8bf3b5ed0dd510b8c1d460d0141..fb03ed4c47a3ea05dc2879ada3d9c97353e3e51d 100755 --- a/GeoModelCore/GeoModelKernel/src/GeoPolyhedronGeneric.cxx +++ b/GeoModelCore/GeoModelKernel/src/GeoPolyhedronGeneric.cxx @@ -7,7 +7,10 @@ #include "GeoModelKernel/GeoBox.h" #include "GeoModelKernel/GeoTrd.h" #include "GeoModelKernel/GeoTube.h" +#include "GeoModelKernel/GeoTubs.h" +#include "GeoModelKernel/GeoPcon.h" #include "GeoModelKernel/GeoSimplePolygonBrep.h" +#include "GeoModelKernel/GeoShapeShift.h" #include <cmath> #include <stdexcept> #include <iostream> @@ -17,9 +20,10 @@ const std::string GeoPolyhedronGeneric::s_classType = "PolyhedronGeneric"; const ShapeType GeoPolyhedronGeneric::s_classTypeID = 0x25; -GeoPolyhedronGeneric::GeoPolyhedronGeneric(const GeoShape* shape) { +GeoPolyhedronGeneric::GeoPolyhedronGeneric(const GeoShape* shape, const GeoTrf::Transform3D& transform, int polyhedrize) { std::vector<GeoTrf::Vector3D> vtx; + m_transform = transform; if (shape->type() == "Box") { const GeoBox* box = dynamic_cast<const GeoBox*> (shape); @@ -78,9 +82,11 @@ GeoPolyhedronGeneric::GeoPolyhedronGeneric(const GeoShape* shape) { for (unsigned int i=0; i<getNFaces(); i++) m_Normals.push_back( ((m_Vertices[m_Faces[i][0]]-m_Vertices[m_Faces[i][1]]).cross(m_Vertices[m_Faces[i][2]]-m_Vertices[m_Faces[i][1]])).normalized() ); - } - if (shape->type() == "SimplePolygonBrep") { + m_status = isValid() ? 0 : 2; + //if (!isValid() ) std::cout << " GeoPolyhedronGeneric constructor from Box/Trd not valid" << std::endl; + + } else if (shape->type() == "SimplePolygonBrep") { const GeoSimplePolygonBrep* spb = dynamic_cast<const GeoSimplePolygonBrep*> (shape); double hz = spb->getDZ(); @@ -133,81 +139,184 @@ GeoPolyhedronGeneric::GeoPolyhedronGeneric(const GeoShape* shape) { } } } - - if (!isValid() ) std::cout << " GeoPolyhedronGeneric constructor from SimplePolygonBrep not valid" << std::endl; + m_status = isValid() ? 0 : 2; + //if (!isValid() ) std::cout << " GeoPolyhedronGeneric constructor from SimplePolygonBrep not valid" << std::endl; + m_origin = 3; } + else if ( (shape->type() == "Tube" || shape->type() == "Tubs") ) { - if (shape->type() == "Tube") { // polyhedrize : TODO : make the precision tunable - - const GeoTube* tube = dynamic_cast<const GeoTube*> (shape); - double hz = tube->getZHalfLength(); - double rmin = tube->getRMin(); - double rmax = tube->getRMax(); + m_origin = 4; - int nsplit = 16; + if (polyhedrize == 0) { + m_status = 1; return; + } + const GeoTube* tube = (shape->type() == "Tube") ? dynamic_cast<const GeoTube*> (shape) : nullptr; + const GeoTubs* tubs = (shape->type() == "Tubs") ? dynamic_cast<const GeoTubs*> (shape) : nullptr; + + double hz = tube ? tube->getZHalfLength() : tubs->getZHalfLength(); + double rmin = tube ? tube->getRMin() : tubs->getRMin(); + double rmax = tube ? tube->getRMax() : tubs->getRMax(); + double sPhi = tubs ? tubs->getSPhi() : 0.; + double dPhi = tubs ? tubs->getDPhi() : 2*acos(-1.); + bool sector = dPhi < 2*acos(-1.); + + int nsplit = dPhi>acos(-1.) ? polyhedrize : int(0.5*polyhedrize); + if ( nsplit < 2 ) nsplit = 2; + // build outer shell - double ff = acos(-1.)/nsplit; + double ff = 0.5*dPhi/nsplit; double rx = rmax * sqrt( ff / sin(ff) / cos(ff) ); - for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rx*cos(-i*2*ff),rx*sin(-i*2*ff),hz)); - for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rx*cos(-i*2*ff),rx*sin(-i*2*ff),-hz)); - - std::vector<size_t> f0; std::vector<size_t> f1; + for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rx*cos(sPhi+dPhi-i*2*ff),rx*sin(sPhi+dPhi-i*2*ff),hz)); + std::vector<size_t> f0; for (unsigned int i=0; i < nsplit; i++) f0.push_back(i); - for (unsigned int i=2*nsplit-1; i >= nsplit; i--) f1.push_back(i); - - if (rmin>0) { - - f0.push_back(0); f1.push_back(2*nsplit-1); // needed for combined loop - + + // sector needs the closing vertex,too + if ( sector ) { + f0.push_back(vtx.size()); vtx.push_back(GeoTrf::Vector3D(rx*cos(sPhi),rx*sin(sPhi),hz)); + if (!(rmin>0) ) { // need the central point + f0.push_back(vtx.size()); vtx.push_back(GeoTrf::Vector3D(0.,0.,hz)); + } + } else if (rmin>0) f0.push_back(0); // needed for combined loop + + int nv = vtx.size(); // outer ring vertex count + if (rmin>0) { // inner ring mirrored double rn = rmin * sqrt( ff / sin(ff) / cos(ff) ); - for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rn*cos(-i*2*ff),rn*sin(-i*2*ff),-hz)); - for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rn*cos(-i*2*ff),rn*sin(-i*2*ff),hz)); - - for (unsigned int i=2*nsplit; i < 3*nsplit; i++) f1.push_back(i); - for (unsigned int i=4*nsplit-1; i >= 3*nsplit; i--) f0.push_back(i); - - f0.push_back(4*nsplit-1); f1.push_back(2*nsplit); // needed for combined loop + for (int i = nv-1; i >= 0; i--) { + vtx.push_back(GeoTrf::Vector3D(rn/rx*vtx[i].x(),rn/rx*vtx[i].y(),hz)); + } + f0.push_back(2*nv-1); + for (unsigned int i = nv; i< 2*nv; i++) f0.push_back(i); } - addFace(f0); addNormal(GeoTrf::Vector3D(0.,0.,1.)); + + int mv = vtx.size(); + + // mirror the face + int ntop = f0.size(); + for (unsigned int i=0; i<mv; i++) { + vtx.push_back(GeoTrf::Vector3D(vtx[i].x(),vtx[i].y(),-hz)); + } + std::vector<size_t> f1; + for (int i=ntop-1; i>=0; i--) f1.push_back(f0[i]+mv); addFace(f1); addNormal(GeoTrf::Vector3D(0.,0.,-1.)); addVertices(vtx); - for (unsigned int i=0; i<nsplit; i++) { + for (unsigned int i=0; i<ntop; i++) { + if (rmin>0 && !sector && (i==nsplit || i==ntop-1) ) continue; // dummy lateral faces std::vector<size_t> f; f.clear(); - f.push_back( i == nsplit-1 ? 0 : i+1); f.push_back(i); f.push_back(nsplit+i); f.push_back( i == nsplit-1 ? nsplit : nsplit+i+1); - addFace(f); addNormal( (m_Vertices[f[0]]-m_Vertices[f[1]]).cross(m_Vertices[f[2]]-m_Vertices[f[1]]).normalized() ); + f.push_back( i == ntop-1 ? f0[0] : f0[i+1]); f.push_back(f0[i]); f.push_back(f0[i]+mv); f.push_back( i == ntop-1 ? f0[0]+mv : f0[i+1]+mv); + addFace(f); addNormal( (m_Vertices[f[0]]-m_Vertices[f[1]]).cross(m_Vertices[f[2]]-m_Vertices[f[1]]).normalized() ); } - if (rmin>0) { - std::vector<size_t> f; f.clear(); - f.push_back(3*nsplit); f.push_back(0); f.push_back(nsplit); f.push_back(2*nsplit); - addFace(f); addNormal( (m_Vertices[f[0]]-m_Vertices[f[1]]).cross(m_Vertices[f[2]]-m_Vertices[f[1]]).normalized() ); + fillSpans(); - for (unsigned int i=0; i<nsplit; i++) { + m_status = isValid() ? 0 : 2; + //if (!isValid() ) std::cout << " GeoPolyhedronGeneric constructor from Tube/Tubs not valid" << std::endl; + + } + else if ( shape->type() == "Pcon") { + + m_origin = 5; + + if ( polyhedrize == 0 ) { + m_status = 1; return; + } + + const GeoPcon* pcon = dynamic_cast<const GeoPcon*> (shape); + + double sPhi = pcon->getSPhi(); + double dPhi = pcon->getDPhi(); + bool sector = dPhi < 2*acos(-1.); + unsigned int nplanes = pcon->getNPlanes(); + double pord = ( pcon->getZPlane(0) < pcon->getZPlane(nplanes-1) ) ? 1. : -1.; + + int nsplit = dPhi>acos(-1.) ? polyhedrize : int(0.5*polyhedrize); + if ( nsplit < 2 ) nsplit = 2; + + double ff = 0.5*dPhi/nsplit; + + std::vector<size_t> f; int nv = 0; int ntop = 0; int mv = 0; + + for ( unsigned int iz = 0; iz < nplanes; iz++) { + + double z = pcon->getZPlane(iz); + double rmin = pcon->getRMinPlane(iz); + double rmax = pcon->getRMaxPlane(iz); + + // build outer shell + double rx = rmax * sqrt( ff / sin(ff) / cos(ff) ); + for (unsigned int i=0; i < nsplit; i++) vtx.push_back(GeoTrf::Vector3D(rx*cos(sPhi+dPhi-i*2*ff),rx*sin(sPhi+dPhi-i*2*ff),z)); + + if (sector) { + vtx.push_back(GeoTrf::Vector3D(rx*cos(sPhi),rx*sin(sPhi),z)); // sector needs the closing vertex,too + if (!(rmin>0) ) vtx.push_back(GeoTrf::Vector3D(0.,0.,z)); // the central point needed + } + + if (iz==0 || iz == nplanes-1 ) { f.clear(); - f.push_back( i == 3*nsplit-1 ? 2*nsplit : 2*nsplit+i+1); f.push_back(2*nsplit+i); f.push_back(3*nsplit+i); f.push_back( i == 3*nsplit-1 ? 3*nsplit : 3*nsplit+i+1); - addFace(f); addNormal( (m_Vertices[f[0]]-m_Vertices[f[1]]).cross(m_Vertices[f[2]]-m_Vertices[f[1]]).normalized() ); + for (unsigned int i=0; i < nsplit; i++) f.push_back(vtx.size()-nsplit+i); + if ( sector ) { + f.push_back(vtx.size()); + if (!(rmin>0) ) f.push_back(vtx.size()); + } else if (rmin>0) f.push_back(vtx.size()-nsplit); // needed for combined loop + if (iz==0) nv = vtx.size(); // outer ring vertex count + } + + // inner ring mirrored + if (rmin>0) { + double rn = rmin * sqrt( ff / sin(ff) / cos(ff) ); + for (int i = vtx.size()-1; i >= vtx.size()-nv; i--) { + vtx.push_back(GeoTrf::Vector3D(rn/rx*vtx[i].x(),rn/rx*vtx[i].y(),z)); + } + + if (iz==0 || iz == nplanes-1) { + f.push_back(vtx.size()-1); + for (unsigned int i = vtx.size()-nv; i< vtx.size(); i++) f.push_back(i); + } + } + + if (iz==0) { + ntop = f.size(); + mv = vtx.size(); } - f.clear(); - f.push_back(2*nsplit); f.push_back(nsplit); f.push_back(0); f.push_back(3*nsplit); - addFace(f); addNormal( (m_Vertices[f[0]]-m_Vertices[f[1]]).cross(m_Vertices[f[2]]-m_Vertices[f[1]]).normalized() ); + if (iz==0 || iz == nplanes-1) { + if ( (pord>0 && iz==nplanes-1) || (pord<0 && iz==0) ) { + addFace(f); addNormal(GeoTrf::Vector3D(0.,0.,+1.)); + } else { + std::vector<size_t> fi; + for (int i=ntop-1; i>=0; i--) fi.push_back(f[i]); + addFace(fi); addNormal(GeoTrf::Vector3D(0.,0.,-1.)); + } + } + + if ( iz>0 ) { + + int nvx = vtx.size(); + for (unsigned int i=0; i<ntop; i++) { + if (rmin>0 && !sector && (i==nsplit || i==ntop-1) ) continue; // dummy lateral faces + f.clear(); + f.push_back( i == ntop-1 ? nvx-ntop : nvx-ntop+i+1); f.push_back(nvx-ntop+i); + f.push_back(nvx-2*ntop+i); f.push_back( i == ntop-1 ? nvx-2*ntop : nvx-2*ntop+i+1); + addFace(f); addNormal( (vtx[f[0]]-vtx[f[1]]).cross(vtx[f[2]]-vtx[f[1]]).normalized() ); + } + } } + + addVertices(vtx); fillSpans(); - std::cout << "tube->polyhedron:rmin,rmax,hz:"<<rmin <<","<<rmax<<","<<hz<<":valid:" << this->isValid() <<":volume:" << this->volume() << std::endl; - - m_origin = 4; - - } + m_status = isValid() ? 0 : 2; + //if (!isValid() ) std::cout << " GeoPolyhedronGeneric constructor from Pcon not valid" << std::endl; + } else m_status = 1; + if (m_face_span.size()<m_Faces.size()) fillSpans(); } @@ -218,6 +327,7 @@ GeoPolyhedronGeneric::GeoPolyhedronGeneric(const GeoPolyhedronGeneric& gpg) { m_Faces = gpg.m_Faces; m_Normals = gpg.m_Normals; m_origin = gpg.m_origin; // only used for debugging of initial conversion from GeoShape + m_status = gpg.m_status; if (isValid()) fillSpans(); @@ -345,6 +455,15 @@ bool GeoPolyhedronGeneric::contains ( GeoTrf::Vector3D point, double precision, void GeoPolyhedronGeneric::addVertices(std::vector<GeoTrf::Vector3D> vertices) { m_Vertices = vertices; + + bool isIdentity = true; + if (m_transform.translation().norm() > std::numeric_limits<float>::epsilon() ) isIdentity = false; + if (isIdentity) { + const GeoTrf::RotationMatrix3D& rot = m_transform.linear(); + for (int i=0; i<3; i++) if ( std::abs(GeoTrf::Vector3D::Unit(i).dot(rot*GeoTrf::Vector3D::Unit(i)) - 1 ) > std::numeric_limits<float>::epsilon() ) isIdentity = false; + } + + if (!isIdentity) for ( int i = 0; i < m_Vertices.size(); i++) m_Vertices[i] = m_transform * m_Vertices[i]; } void GeoPolyhedronGeneric::addFace(std::vector<size_t> faceVtx) @@ -530,7 +649,8 @@ std::vector< std::pair< double, std::pair<size_t,size_t> > > GeoPolyhedronGeneri bool GeoPolyhedronGeneric::isValid( bool debugMode ) const { - if (getNFaces()<4) return false; + // if (getNFaces()<4) return false; + if ( m_status > 0 ) return false; // loop over edges, check that each appears with its mirrored version ( attached faces ) for ( unsigned int ic=0; ic < getNFaces(); ic++) { @@ -643,6 +763,8 @@ void GeoPolyhedronGeneric::cleanAfterBooleanOperation() { bool GeoPolyhedronGeneric::construct(bool debugMode) { fillSpans(); + m_origin = 0; + m_status = isValid(debugMode) ? 0 : 2; return isValid(debugMode); } diff --git a/GeoModelCore/GeoModelKernel/src/GeoPolyhedronManipulator.cxx b/GeoModelCore/GeoModelKernel/src/GeoPolyhedronManipulator.cxx index b1632ff9d48df1bb948d1a2579db2b30203a5792..3f0eb2b423af090bf505f297e60cb8b11fdbfa1e 100644 --- a/GeoModelCore/GeoModelKernel/src/GeoPolyhedronManipulator.cxx +++ b/GeoModelCore/GeoModelKernel/src/GeoPolyhedronManipulator.cxx @@ -4,25 +4,29 @@ #include "GeoModelKernel/GeoPolyhedronManipulator.h" #include "GeoModelKernel/GeoShape.h" -#include "GeoModelKernel/GeoShapeIntersection.h" +#include "GeoModelKernel/GeoShapeShift.h" #include "GeoModelKernel/GeoShapeUnion.h" #include "GeoModelKernel/GeoShapeSubtraction.h" -#include "GeoModelKernel/GeoBox.h" +#include "GeoModelKernel/GeoShapeIntersection.h" +#include "GeoModelKernel/GeoSimplePolygonBrep.h" +#include "GeoModelKernel/GeoTube.h" +#include "GeoModelKernel/GeoTubs.h" +#include "GeoModelKernel/GeoPcon.h" #include <cmath> #include <cstdint> #include <iostream> #include <utility> GeoPolyhedronGeneric* GeoPolyhedronManipulator::intersection( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode) -{ return resolveBoolean( phA, phB, 0, debugMode); } +{ return new GeoPolyhedronGeneric(resolveBoolean( phA, phB, 0, debugMode)); } GeoPolyhedronGeneric* GeoPolyhedronManipulator::subtraction( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode) -{ return resolveBoolean( phA, phB, 1, debugMode); } +{ return new GeoPolyhedronGeneric(resolveBoolean( phA, phB, 1, debugMode)); } GeoPolyhedronGeneric* GeoPolyhedronManipulator::uni( const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, bool debugMode) -{ return resolveBoolean( phA, phB, 2, debugMode); } +{ return new GeoPolyhedronGeneric(resolveBoolean( phA, phB, 2, debugMode)); } -GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, int modeBoolean, bool debugMode) { +GeoPolyhedronGeneric GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhedronGeneric* phA, const GeoPolyhedronGeneric* phB, int modeBoolean, bool debugMode) { // modeBoolean : 0 intersection (A and B): shared(A,B) non-overlapping + shared A overlapping // 1 subtraction (A and not B): non-shared(A) + inverted shared (B) // 2 union (A or B) : non-shared(A,B) + shared A overlapping @@ -39,12 +43,16 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed for (unsigned int iv=0; iv < nVA; iv++) { vtx.push_back( phA->getVertex(iv) ); NPH_vertex phv; phv.index=vlog.size(); phv.index_ph=0; phv.shared = phB->contains( vtx.back(), 1.e-3 ); vlog.push_back( phv ); + } for (unsigned int ip=0; ip < phA->getNFaces(); ip++) { planes.push_back(NPH_plane(0)); planes.back().vertices = phA->getFace(ip); planes.back().normal = phA->faceNormal(ip); - if (debugMode) std::cout <<"phA:face:" << ip <<":vtx:"; for ( auto jv : planes.back().vertices ) std::cout << jv<<","; std::cout <<"" << std::endl; + if (debugMode) { + std::cout <<"phA:face:" << ip <<":vtx:"; + for ( auto jv : planes.back().vertices ) std::cout << jv<<","; std::cout <<"" << std::endl; + } } // phB + overlapping vertices + overlapping planes std::vector<std::pair<int,int>> overlapping_vertices; @@ -63,7 +71,10 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed planes.back().vertices.push_back( overlap>=0 ? overlap : vh+nVA); } planes.back().normal = phB->faceNormal(ip); - if (debugMode) std::cout <<"phB:face:" << ip <<":vtx:"; for ( auto jv : planes.back().vertices ) std::cout << jv<<","; std::cout <<"" << std::endl; + if (debugMode) { + std::cout <<"phB:face:" << ip <<":vtx:"; + for ( auto jv : planes.back().vertices ) std::cout << jv<<","; std::cout <<"" << std::endl; + } // overlapping planes for (unsigned int ipA=0; ipA < nPA; ipA++) { NPH_plane plA = planes[ipA]; double nn = plA.normal.dot(phB->faceNormal(ip)); @@ -104,6 +115,8 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed if (debugMode) { std::cout << "processing plane:" << ip <<":origin:" << plane.index_ph <<":overlapping planes:"; for (auto op : plane.overlapping) std::cout << op <<","; std::cout <<" " << std::endl; + std::cout << "original vertices:"; + for (auto iv : plane.vertices) std::cout << iv<<","; std::cout << ""<< std::endl; } for ( auto ov : plane.overlapping ) { // add shared vertices TO DO : this loop seem obsolete / superflu for ( auto iv : planes[ov%1000].vertices ) { if (!vlog[iv].shared) continue; @@ -183,6 +196,7 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed plane_edges.push_back(ple); } } + // loop over edges to identify vertices with protected line connection for (unsigned int ie = 0; ie< plane_edges.size()-1; ie++) { if ( plane_edges[ie].shared != plane_edges[ie+1].shared ) planes[ip].hit_vertices[plane_edges[ie].endpoint_hitvx.second].onEdgeProtected = true; @@ -196,13 +210,14 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } } + // // ======================== prepare active lines ( mixed edges ) ==================================== std::vector<NPL_edge> resolved_lines = evaluateVertexLogic(ip, vlog, edges, planes, vtx); if (debugMode) { - std::cout << "resolved lines:" << resolved_lines.size() <<":"; for (auto il : resolved_lines) std::cout << il.adjacent_face <<","; - std::cout <<""<<std::endl; + std::cout << "resolved lines:" << resolved_lines.size() <<":"; + for (auto il : resolved_lines) std::cout << "adj:"<<il.adjacent_face <<":" << il.endpoints.first << "," <<il.endpoints.second<<std::endl; } plane = planes[ip]; @@ -247,8 +262,6 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed edgeInPlane = false; for ( auto ep : edge.inPlane ) if (ap == ep) edgeInPlane = true; if (!edgeInPlane && inPlane(vlog[ple_next.endpoints.second],edges,ap) ) edgeInPlane = true; if (!edgeInPlane) pruned_lines.push_back(ap); - if (edgeInPlane && ( plane.hit_vertices[ple.endpoint_hitvx.first].onEdgeProtected || plane.hit_vertices[ple.endpoint_hitvx.second].onEdgeProtected) ) - std::cout << "pruning removed protected line:" << ap <<":endpoints:" << ple.endpoints.first <<"," << ple.endpoints.second << std::endl; } int nlines = pruned_lines.size(); if ( nlines == 1 ) { @@ -293,12 +306,16 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } plane.hit_vertices[ple.endpoint_hitvx.second].faces.first = ple.adjacent_face ; plane.hit_vertices[ple.endpoint_hitvx.second].faces.second = plane_edges[ie].endpoint_faces.second; - plane.hit_vertices[ple_next.endpoint_hitvx.second].faces.second = ple_next.adjacent_face ; - plane.hit_vertices[ple_next.endpoint_hitvx.second].faces.first = plane_edges[ie].endpoint_faces.second; + if ( ple_next.endpoint_hitvx.second >=0 ) { + plane.hit_vertices[ple_next.endpoint_hitvx.second].faces.second = ple_next.adjacent_face ; + plane.hit_vertices[ple_next.endpoint_hitvx.second].faces.first = plane_edges[ie].endpoint_faces.second; + } } } // end non/shared vertices } // end second loop over edges + planes[ip].edge_loop_origin = plane_edges; + if (debugMode) { // print overview of shared edges for (unsigned int ie = 0; ie<plane_edges.size(); ie++) { if (!plane_edges[ie].shared ) continue; @@ -314,6 +331,7 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed << plane.hit_vertices[ple.endpoint_hitvx.second].faces_shared_loop.second << std::endl; } } + // ============== merge edges and lines ================================================ // at this point, lines are not oriented and have not been symmetrized yet // the ordering ensures oriented edges are recovered first @@ -442,9 +460,24 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed // =================== shared loops : base =========================================== // select shared non-overlapping first, then add all unused shared + + + for (unsigned int ie=0; ie<plane_edges.size(); ie++ ) { + if ( plane_edges[ie].generating_edge>=0 && plane_edges[ie].dummy_overlap>=0 ) { + for (unsigned int je=ie+1; je<plane_edges.size(); je++) { + if (plane_edges[je].endpoints.first == plane_edges[ie].endpoints.first && + plane_edges[je].endpoints.second == plane_edges[ie].endpoints.second && plane_edges[je].generating_edge<0 ) + plane_edges[je].dummy_overlap = plane_edges[ie].dummy_overlap; + if (plane_edges[je].endpoints.first == plane_edges[ie].endpoints.second && + plane_edges[je].endpoints.second == plane_edges[ie].endpoints.first && plane_edges[je].generating_edge<0 ) + plane_edges[je].dummy_overlap = plane_edges[ie].dummy_overlap; + } + } + } + int nedge = 0; std::vector<int> edgeSelect; - for (unsigned int ie=0; ie<plane_edges.size(); ie++ ) { + for (unsigned int ie=0; ie<plane_edges.size(); ie++ ) { if ( !plane_edges[ie].used && plane_edges[ie].shared && plane_edges[ie].overlap<0 ) { edgeSelect.push_back(ie); nedge++; } @@ -463,54 +496,120 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed edgeSelect.push_back(ie); nedge++; } } - - if (edgeSelect.size()>1) { - std::vector<int>::iterator it = edgeSelect.begin(); - NPL_ordered loop; loop.edges.push_back(*it); plane_edges[*it].used = true; - loop.vtx.push_back(plane_edges[*it].endpoints.first); - loop.vtx.push_back(plane_edges[*it].endpoints.second); - loop.shared=true; loop.oriented = plane_edges[*it].generating_edge>=0 ? true : false; // after including check on dummy shared edges, oriented edges may appear in the middle of the loop - it = edgeSelect.begin(); - while ( loop.vtx.front() != loop.vtx.back() && it != edgeSelect.end()) { - if ( loop.edges.size() && plane_edges[loop.edges.back()].symmetrized == (*it) ) { - it++; - } else if (!plane_edges[*it].used && plane_edges[*it].endpoints.first == loop.vtx.back() ) { - // - loop.edges.push_back(*it); loop.vtx.push_back(plane_edges[*it].endpoints.second); - plane_edges[*it].used = true; it = edgeSelect.begin(); // std::cout << ":adding:" << (*it) << std::endl; - - } else if (!plane_edges[*it].used && plane_edges[*it].generating_edge<0 && plane_edges[*it].symmetrized<0 - && plane_edges[*it].endpoints.second == loop.vtx.back()) { // need to symmetrize the line now - NPL_edge symLine = symmetrize(plane_edges[*it]); plane_edges[*it].symmetrized=plane_edges.size(); symLine.used=true; symLine.symmetrized = (*it); - (*it) = plane_edges.size(); plane_edges.push_back(symLine); // std::cout << ":adding symmetrized:" << (*it) << std::endl; - loop.edges.push_back(*it); loop.vtx.push_back(symLine.endpoints.second); it = edgeSelect.begin(); - - } else it++; + } + + /* + std::cout << "shared edges:"<< std::endl; + for (auto ie : edgeSelect) std::cout << plane_edges[ie].endpoints.first <<":" << plane_edges[ie].endpoints.second + <<":adj:" << plane_edges[ie].adjacent_face<<":gen.edge:" << plane_edges[ie].generating_edge <<":sym:" << plane_edges[ie].symmetrized + <<":shared:" << plane_edges[ie].shared <<":hitvx:" << plane_edges[ie].endpoint_hitvx.first <<"," + << plane_edges[ie].endpoint_hitvx.second <<":dummy overlap:" << plane_edges[ie].dummy_overlap << std::endl; + */ + while ( nedge>2 ) { + if (shared_loops.size() && shared_loops.back().top_overlap<0) std::cout << "running for multiple shared loops" << std::endl; + int io = -1; int ien = -1; + //if (edgeSelect.size()>1) { + std::vector<int>::iterator it = edgeSelect.begin(); while (plane_edges[*it].used || plane_edges[*it].dummy_overlap>=1000) it++; if ( it == edgeSelect.end() ) break; + //if ( vlog[plane_edges[*it].endpoints.first].edges.size()>3) + // std::cout << "WARNING: ambiguous choice of shared loop start:" << plane_edges[*it].endpoints.first <<":" << plane_edges[*it].endpoint_hitvx.first << std::endl; + NPL_ordered loop; loop.edges.push_back(*it); plane_edges[*it].used = true; + loop.vtx.push_back(plane_edges[*it].endpoints.first); + loop.vtx.push_back(plane_edges[*it].endpoints.second); + loop.shared=true; loop.oriented = plane_edges[*it].generating_edge>=0 ? true : false; // after including check on dummy shared edges, oriented edges may appear in the middle of the loop + it = edgeSelect.begin(); + if (plane_edges[*it].endpoint_hitvx.first>=0 && !planes[ip].hit_vertices[plane_edges[*it].endpoint_hitvx.first].active_lines.size() ) + ien = nextOri(loop.edges.back(),plane_edges,planes[ip].edge_loop_origin,edgeSelect,true); + int inext=(*it); + while ( loop.vtx.front() != loop.vtx.back() && inext>=0 ) { + inext = -1; + // active loop end part of original loop -> fast selection track + if (plane_edges[loop.edges.back()].endpoint_hitvx.second>=0 && + !planes[ip].hit_vertices[plane_edges[loop.edges.back()].endpoint_hitvx.second].active_lines.size() ) { + inext = nextOri(loop.edges.back(),plane_edges,planes[ip].edge_loop_origin,edgeSelect); } - - if (loop.vtx.front() != loop.vtx.back() || loop.edges.size()<2 ) { - for ( auto ie : loop.edges ) plane_edges[ie].used = false; // undo loop if not closed - } else - shared_loops.push_back(loop); - - int nseed = 0; // keep trace of non-symmetrized unused shared edges - for (auto ie : edgeSelect ) if (!plane_edges[ie].used) { - if (plane_edges[ie].symmetrized<0 ) nseed++; - else if (!plane_edges[plane_edges[ie].symmetrized].used) nseed++; + if ( inext>=0 && !plane_edges[inext].used ) { + loop.edges.push_back(inext); loop.vtx.push_back(plane_edges[inext].endpoints.second); + plane_edges[inext].used = true; + } else { // deal with possiblity of multiple connections + std::vector<int>::iterator itn = edgeSelect.begin(); std::vector<int> edgeUpdate; + while (itn != edgeSelect.end() ) { + if ( loop.edges.size() && plane_edges[loop.edges.back()].symmetrized == (*itn) ) { + } else if (!plane_edges[*itn].used && plane_edges[*itn].endpoints.first == loop.vtx.back() ) { + if ( plane_edges[*itn].generating_edge<0 && plane_edges[*itn].symmetrized<0 ) { + NPL_edge symLine = symmetrize(plane_edges[*itn]); plane_edges[*itn].symmetrized=plane_edges.size(); + symLine.symmetrized = (*itn); plane_edges.push_back(symLine); edgeUpdate.push_back(plane_edges.size()-1); + } + if (inext<0) inext = *itn; + else { + if (plane_edges[inext].generating_edge >= 0 && plane_edges[*itn].generating_edge < 0 + && !plane_edges[plane_edges[*itn].symmetrized].used ) inext = *itn; + //std::cout <<"multiple choice:" << plane_edges[inext].generating_edge <<":"<<plane_edges[*itn].generating_edge << std::endl; + } + } else if (!plane_edges[*itn].used && plane_edges[*itn].generating_edge<0 && plane_edges[*itn].symmetrized<0 + && plane_edges[*itn].endpoints.second == loop.vtx.back()) { // need to symmetrize the line now + NPL_edge symLine = symmetrize(plane_edges[*itn]); plane_edges[*itn].symmetrized=plane_edges.size(); + symLine.symmetrized = (*itn); plane_edges.push_back(symLine); edgeUpdate.push_back(plane_edges.size()-1); + if (inext<0) inext = plane_edges.size()-1; + else { + if (plane_edges[inext].generating_edge >= 0 && !plane_edges[*itn].used) inext = plane_edges.size()-1; + //std::cout <<"multiple choice:" << plane_edges[inext].generating_edge <<":"<<plane_edges.back().generating_edge << std::endl; + } + } + itn++; } - - if (debugMode) { - std::cout << "base shared loop:selected:" << edgeSelect.size() <<":loop size:vtx:"<< loop.vtx.size() - <<":loop size:edge:" << loop.edges.size() << std::endl; - if (nseed>0) { - std::cout <<"WARNING:remaining seeds:" << nseed << std::endl; - for (auto iv : planes[ip].vertices) std::cout << "vtx ori:" <<iv<<":" << vtx[iv].x() <<"," << vtx[iv].y() <<"," << vtx[iv].z() << std::endl; - for (auto iv : planes[ip].hit_vertices) std::cout << "vtx hit:" <<iv.index<<":" << vtx[iv.index].x() <<"," << vtx[iv.index].y() <<"," << vtx[iv.index].z() << std::endl; + if (inext>=0) { + //std::cout << ":next shared edge:" << inext <<":" << plane_edges[inext].endpoints.second << std::endl; + loop.edges.push_back(inext); loop.vtx.push_back(plane_edges[inext].endpoints.second); + plane_edges[inext].used = true; + } + if (edgeUpdate.size()) { edgeSelect.insert(edgeSelect.end(),edgeUpdate.begin(),edgeUpdate.end()); edgeUpdate.clear();} + } + // double-check closing conditions + if (ien>=0 && loop.vtx.front() == loop.vtx.back() && loop.edges.back()!=ien) { + int jnext = -1; + if (plane_edges[loop.edges.back()].endpoint_hitvx.second>=0 && + !planes[ip].hit_vertices[plane_edges[loop.edges.back()].endpoint_hitvx.second].active_lines.size() ) { + jnext = nextOri(loop.edges.back(),plane_edges,planes[ip].edge_loop_origin,edgeSelect); + } + if ( jnext>=0 && !plane_edges[jnext].used ) { + loop.edges.push_back(jnext); loop.vtx.push_back(plane_edges[jnext].endpoints.second); + plane_edges[jnext].used = true; it = edgeSelect.begin(); + //std::cout << "fast search applied in closing sequence" << std::endl; } } } - } + if (loop.vtx.front() != loop.vtx.back() || loop.edges.size()<2 ) { + for ( auto ie : loop.edges ) plane_edges[ie].used = false; // undo loop if not closed + if (debugMode) std::cout << "undo shared loop:"; for ( auto iv : loop.vtx ) std::cout <<iv<<","; std::cout <<"" << std::endl; + break; + } else { + shared_loops.push_back(loop); + if (debugMode) { + if (ien >= 0) { + for (auto iv : loop.vtx) std::cout << iv <<","; std::cout <<""<<std::endl; + for (auto ie : loop.edges) std::cout << plane_edges[ie].adjacent_face <<","; std::cout <<""<<std::endl; + std::cout << "closing edge:" << plane_edges[loop.edges.back()].endpoints.first << ":adj:" << plane_edges[loop.edges.back()].adjacent_face << std::endl; + if (plane_edges[loop.edges.back()].adjacent_face != planes[ip].edge_loop_origin[ien].adjacent_face) std::cout <<"CLOSING MISMATCH" << std::endl; + } + } + } + + nedge = 0; // keep trace of non-symmetrized unused shared edges + for (auto ie : edgeSelect ) if (!plane_edges[ie].used) { + if (plane_edges[ie].symmetrized<0 ) nedge++; + else if (!plane_edges[plane_edges[ie].symmetrized].used) nedge++; + } + + if (debugMode) { + std::cout << "base shared loop:selected:" << edgeSelect.size() <<":loop size:vtx:"<< loop.vtx.size() + <<":loop size:edge:" << loop.edges.size() << std::endl; + if (nedge>0) { + std::cout <<"WARNING:remaining seeds:" << nedge << std::endl; + } + } + } + //================ symmetrized remaining active lines ===================================== for (unsigned int ie=0; ie<plane_edges.size(); ie++ ) { @@ -543,11 +642,11 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed loopi.shared = il.shared; // resolve orientation if ( areaVec(il.vtx,vtx).dot(plane.normal)>=0 ) { - il.oriented = true; loopi.oriented = true; + il.oriented = true; loopi.oriented = true; il.guess_orientation = true; planes[ip].subfaces.push_back(il); shared_inverted_subface.push_back(loopi); } else { - il.oriented = true; loopi.oriented = true; + il.oriented = true; loopi.oriented = true; loopi.guess_orientation = true; planes[ip].subfaces.push_back(loopi); shared_inverted_subface.push_back(il); } @@ -679,8 +778,10 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed if ( non_shared_loops.size() ) { // merge inverted shared with non-shared loops - for (unsigned int il=0; il<shared_inverted_subface.size(); il++ ) { - non_shared_loops[0] = mergeLoops(non_shared_loops[0], shared_inverted_subface[il], vtx); + for (unsigned int il=0; il<shared_inverted_subface.size(); il++ ) { + non_shared_loops[0] = mergeLoops(non_shared_loops[0], shared_inverted_subface[il], vtx); + //for (auto iv : non_shared_loops[0].vtx ) std::cout << iv <<","; std::cout <<""<< std::endl; + //for (auto ie : non_shared_loops[0].edges ) std::cout << ie <<","; std::cout <<""<< std::endl; } } @@ -706,8 +807,75 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed */ } // end loop over planes + + // make final check of face orientation ( inner loops ... ) + for ( unsigned int ip=0; ip<planes.size(); ip++ ) { NPH_plane plane = planes[ip]; + for (unsigned int il=0; il<plane.subfaces.size(); il++) { + if (plane.subfaces[il].guess_orientation) { + bool swap = false; bool noswap = false; + for ( auto ie : plane.subfaces[il].edges ) { + if (ie<0) continue; + for (unsigned int jp=0; jp<planes.size(); jp++) { + bool overlap = false; for ( auto ov : planes[ip].overlapping ) if (jp == ov%1000) overlap = true; + if (overlap) continue; + for (unsigned int jf=0; jf<planes[jp].subfaces.size(); jf++) { + if (!planes[jp].subfaces[jf].shared) continue; + if (planes[jp].subfaces[jf].guess_orientation) continue; + for (auto je : planes[jp].subfaces[jf].edges) { + if (je<0) continue; + if (jp==ip && jf==il && je==ie) continue; + if (planes[jp].plane_edges[je].endpoints.first == plane.plane_edges[ie].endpoints.first && + planes[jp].plane_edges[je].endpoints.second == plane.plane_edges[ie].endpoints.second) { swap = true; break; } + if (planes[jp].plane_edges[je].endpoints.first == plane.plane_edges[ie].endpoints.second && + planes[jp].plane_edges[je].endpoints.second == plane.plane_edges[ie].endpoints.first) { noswap = true; break; } + } + if (swap || noswap) break; + } + if (swap || noswap) break; + } + if (swap || noswap) break; + } + if (noswap) { planes[ip].subfaces[il].guess_orientation = false; } + if (swap) { planes[ip].subfaces[il].guess_orientation = false; + NPL_ordered loop = planes[ip].subfaces[il]; + planes[ip].subfaces[il].reverse(planes[ip].plane_edges); + /* + for (auto iv : planes[ip].subfaces[il].vtx ) std::cout << iv <<","; std::cout <<""<< std::endl; + for (auto ie : planes[ip].subfaces[il].edges ) { + if (ie<0) std::cout << "dummy edge link:" << std::endl; + else std::cout << planes[ip].plane_edges[ie].endpoints.first <<"->" << planes[ip].plane_edges[ie].endpoints.second << std::endl; + } + */ + for ( unsigned int jl = 0; jl < plane.subfaces.size(); jl++) { + if ( plane.subfaces[jl].shared ) continue; + // by construction, the inverted loop sits at the beginning of non-shared loop + if (planes[ip].subfaces[jl].vtx.front() == planes[ip].subfaces[jl].vtx[loop.vtx.size()] && + vlog[planes[ip].subfaces[jl].vtx.front()].shared) { + if ( planes[ip].subfaces[jl].vtx.front() != loop.vtx.front() ) loop.reorder(planes[ip].subfaces[jl].vtx.front()); + //std::cout << "before replacement:" << std::endl; + //for ( auto iv : planes[ip].subfaces[jl].vtx ) std::cout << iv<<"("<<vlog[iv].shared<<"),"; std::cout <<"" <<std::endl; + //for ( auto ie : planes[ip].subfaces[jl].edges ) { + // if (ie<0) std::cout << "dummy edge link:" << std::endl; + // else std::cout << planes[ip].plane_edges[ie].endpoints.first <<"->" << planes[ip].plane_edges[ie].endpoints.second << std::endl; + //} + for (unsigned int i=0; i<loop.vtx.size(); i++) { + planes[ip].subfaces[jl].vtx[i] = loop.vtx[i]; + planes[ip].subfaces[jl].edges[i] = loop.edges[i]; + } + } + // + //for ( auto iv : planes[ip].subfaces[jl].vtx ) std::cout << iv<<"("<<vlog[iv].shared<<"),"; std::cout <<"" <<std::endl; + //for ( auto ie : planes[ip].subfaces[jl].edges ) { + // if (ie<0) std::cout << "dummy edge link:" << std::endl; + // else std::cout << planes[ip].plane_edges[ie].endpoints.first <<"->" << planes[ip].plane_edges[ie].endpoints.second << std::endl; + //} + } + } + } + } + } - GeoPolyhedronGeneric* gpg = nullptr; + //GeoPolyhedronGeneric gpg; // construct intersection GeoPolyhedronGeneric intersection; @@ -722,20 +890,43 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } } - if (debugMode && intersection.getNFaces()>0 && !intersection.construct(true)) { + if (!intersection.construct(debugMode) && debugMode) { + //if (debugMode && intersection.getNFaces()>0 && !intersection.construct(true)) { std::cout <<"VERIFY intersection:GPG origin:" << phA->getOrigin() <<":"<<phB->getOrigin() << std::endl; + std::vector<std::pair<int,int> > missing = missing_edges(intersection); for (unsigned int ii=0; ii<intersection.getNFaces(); ii++) { std::vector<size_t> vtx = intersection.getFace(ii); std::cout <<"face:"<<ii<<":"; for (auto vx : vtx) std::cout <<vx <<","; std::cout <<"" << std::endl; } + std::vector<int> planes_to_check; + for (auto ii : missing) { int np = 0; + for (auto ip : planes) { + for (auto ie : ip.plane_edges) { + if (ie.endpoints.first == ii.first && ie.endpoints.second == ii.second ) { + std::cout << "missing edge:"<< ii.first <<":"<<ii.second <<":plane:"<< np << ":adj:" << ie.adjacent_face<<":gen.edge:" + << ie.generating_edge <<":protected:" <<ie.protectedLine << std::endl; + planes_to_check.push_back(np); planes_to_check.push_back(ie.adjacent_face); + } + } + np++; + } + } for (unsigned int ip=0; ip<planes.size(); ip++) { NPH_plane plane = planes[ip]; + bool failed = false; for ( auto jp : planes_to_check) if (ip==jp) failed = true; + if (!failed) continue; + std::cout << "plane check:" <<ip <<":original edge loop:"; + for (auto ie : plane.edge_loop_origin) std::cout << ie.endpoints.first << "("<< vlog[ie.endpoints.first].shared<<")"; std::cout <<""<<std::endl; + for (auto ie : plane.edge_loop_origin) std::cout << ie.adjacent_face <<","; std::cout <<""<<std::endl; + for (auto il : plane.subfaces) { std::cout <<"subface(" << il.shared <<"):overlap:"<<il.top_overlap<<":"; + for ( auto iv : il.vtx ) std::cout << iv <<","; std::cout <<"" << std::endl; + } + /* int nShared = 0; for ( auto il : plane.subfaces ) if (il.shared) nShared++; if ( plane.hit_vertices.size()>2 && nShared<1 ) std::cout <<"PROBLEM in plane:" << ip << std::endl; + */ } } - if ( modeBoolean == 0 && intersection.getNFaces() > 3 ) gpg = new GeoPolyhedronGeneric(intersection); - // construct subtraction GeoPolyhedronGeneric subtraction; subtraction.addVertices(vtx); @@ -763,7 +954,8 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } } - if (debugMode && subtraction.getNFaces()>0 && !subtraction.construct(true)) { + if (!subtraction.construct(debugMode) && debugMode) { + //if (debugMode && subtraction.getNFaces()>0 && !subtraction.construct(true)) { std::cout <<"VERIFY subtraction:GPG origin:" << phA->getOrigin() <<":"<<phB->getOrigin() << std::endl; for (unsigned int ii=0; ii<subtraction.getNFaces(); ii++) { std::vector<size_t> vtx = subtraction.getFace(ii); @@ -771,8 +963,6 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } - if ( modeBoolean == 1 && subtraction.getNFaces()>3 ) gpg = new GeoPolyhedronGeneric(subtraction); - // construct union : non-shared + half of overlaps GeoPolyhedronGeneric uni; uni.addVertices(vtx); @@ -793,7 +983,8 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } } - if (debugMode && !uni.construct(true)) { + if (!uni.construct(debugMode) && debugMode) { + //if (debugMode && !uni.construct(true)) { std::cout <<"VERIFY union:GPG origin:" << phA->getOrigin() <<":"<<phB->getOrigin()<<":valid? " << uni.isValid() << std::endl; std::cout << "review input polyhedrons:A:vtx:faces:" << phA->getNVertices() <<":" << phA->getNFaces() << std::endl; for (unsigned int iv=0 ; iv<phA->getNVertices(); iv++) { GeoTrf::Vector3D xx = phA->getVertex(iv); @@ -822,7 +1013,6 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed } } - if ( modeBoolean == 2 ) gpg = new GeoPolyhedronGeneric(uni); if (debugMode) { if (uni.isValid() && intersection.isValid()) std::cout <<"VOLUME check uni:" << phA->volume()+phB->volume()-intersection.volume() @@ -831,20 +1021,34 @@ GeoPolyhedronGeneric* GeoPolyhedronManipulator::resolveBoolean(const GeoPolyhed <<"=?" << subtraction.volume() << std::endl; } - double v0 = (gpg && gpg->isValid()) ? gpg->volume() : 0.; + if ( modeBoolean == 0 ) { + intersection.cleanAfterBooleanOperation(); + return intersection; + } + if ( modeBoolean == 1 ) { + subtraction.cleanAfterBooleanOperation(); + return subtraction; + } + if ( modeBoolean == 2 ) { + uni.cleanAfterBooleanOperation(); + return uni; + } + + /* + double v0 = gpg.isValid() ? gpg.volume() : 0.; - if (debugMode && gpg) std::cout << "test gpg before cleanup:" << gpg->isValid() <<":volume:" << v0 << std::endl; + if (debugMode) std::cout << "test gpg before cleanup:" << gpg.isValid() <<":volume:" << v0 << std::endl; - if (gpg && gpg->isValid()) gpg->cleanAfterBooleanOperation(); + if (gpg.isValid()) gpg.cleanAfterBooleanOperation(); if (debugMode) { - if (gpg) { std::cout << "gpg conversion test:valid:" << gpg->isValid(); - if (gpg->isValid()) std::cout <<":volume:" << gpg->volume() <<":v0:"<<v0; - std::cout<<""<< std::endl; - } + std::cout << "gpg conversion test:valid:" << gpg.isValid(); + if (gpg.isValid()) std::cout <<":volume:" << gpg.volume() <<":v0:"<<v0; + std::cout<<""<< std::endl; } - - return gpg; + */ + + return GeoPolyhedronGeneric(); } std::vector<NPH_edge> GeoPolyhedronManipulator::collectEdges(std::vector<NPH_plane>& planes, std::vector<NPH_vertex>& vlog, bool debugMode ) const { @@ -903,6 +1107,18 @@ std::vector<NPH_edge> GeoPolyhedronManipulator::collectEdges(std::vector<NPH_pla planes[iplane].vlog_ori.push_back(plv); } // end loop vertices } // end loop planes + + // fourth loop to check presence of adjacent faces + for (unsigned int ie=0; ie<edges.size(); ie++) { if (edges[ie].faces.second<0) { + std::cout << "edge without adjacent face:" << edges[ie].endpoints.first <<"," << edges[ie].endpoints.second <<":" <<edges[ie].faces.first <<":" << edges[ie].faces.second << std::endl; + for (unsigned int je=0; je<edges.size(); je++) { if (je==ie) continue; + if (edges[je].endpoints.first== edges[ie].endpoints.first && edges[je].endpoints.second== edges[ie].endpoints.second ) { + std::cout << "duplicated edges" << edges[je].endpoints.first <<"," << edges[je].endpoints.second <<":" <<edges[je].faces.first <<":" << edges[je].faces.second << std::endl; + edges[ie].faces.second = edges[je].faces.second; + } + } + } + } } // end loop ph @@ -992,6 +1208,7 @@ void GeoPolyhedronManipulator::collectLines(std::vector<NPH_plane>& planes, std: } // vlog[index].edges.push_back(std::make_pair<int>(ie,ip)); + //std::cout <<"vlog.edges:" << index <<":"<<ie<<":" << ip <<":" << vlog[index].edges.size() << ":edges:" << edges.size() <<std::endl; } // valid edge intersection with face } else { // special configuration: edge laying on face plane, need to calculate edge intersections @@ -1088,7 +1305,7 @@ void GeoPolyhedronManipulator::intersectFace(unsigned int in_edge, std::vector<N else { GeoTrf::Vector3D hit = eInit + t*edge; for (unsigned int jv = 0; jv<vtx.size(); jv++) if ( (hit - vtx[jv]).norm() < m_tolerance ) { index = jv ; break ;} - if (index < 0) { vtx.push_back(hit); index = vtx.size()-1; NPH_vertex pv; pv.index = index; pv.shared = true; vlog.push_back(pv); } + if (index < 0) { vtx.push_back(hit); index = vtx.size()-1; NPH_vertex pv; pv.index = index; pv.shared = true; vlog.push_back(pv); } } // save on probe edge NPH_vtx nvtx(index); nvtx.edge=in_edge ; nvtx.hitPlane = edges[in_edge].faces.second ; nvtx.distance = dist; nvtx.faces = std::pair<int,int>(edges[ie].faces); @@ -1221,7 +1438,7 @@ double GeoPolyhedronManipulator::edgeFaceIntersection( GeoTrf::Vector3D eInit, G return pen / en ; } -std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_index, std::vector<NPH_vertex>& vlog, std::vector<NPH_edge> edges, std::vector<NPH_plane>& planes, std::vector<GeoTrf::Vector3D> vtx) const { +std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_index, std::vector<NPH_vertex> vlog, std::vector<NPH_edge> edges, std::vector<NPH_plane>& planes, std::vector<GeoTrf::Vector3D> vtx) const { // loop over vertices to determine the level of ambiguity : results save as NPL_vertex properties // default mode processes hit vertices ( intersections ) @@ -1230,7 +1447,8 @@ std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_in std::vector<NPL_edge> lines; std::vector< std::pair< int, std::vector< int > > > active_intersected; - for (unsigned int ih = 0; ih< plane.hit_vertices.size(); ih++) { NPL_vertex iplv = plane.hit_vertices[ih]; NPH_vertex iv = vlog[iplv.index]; + for (unsigned int ih = 0; ih< plane.hit_vertices.size(); ih++) { + NPL_vertex iplv = plane.hit_vertices[ih]; NPH_vertex iv = vlog[iplv.index]; // overview of adjacent planes std::vector<int> np; std::vector<int> native_planes; std::vector<int> intersected_planes; int pl; bool found; for (auto ie : iv.edges) { @@ -1286,10 +1504,6 @@ std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_in if ( np.size() == 5) { std::pair<int,int> doublEdg = hitDoubleEdge(iplv.index, plane_index, plane.index_ph, vlog, edges); // indicates adjacent face - if (doublEdg.first>=0 && iv.index_ph==plane.index_ph) { - vlog[iplv.index].hitDoublEdge = doublEdg.first; - vlog[iplv.index].onDoublEdge = (planes[doublEdg.first].index_ph == plane.index_ph) ? 0 : 1; - } if (doublEdg.first>=0 && iv.index_ph!=plane.index_ph) { planes[plane_index].hit_vertices[ih].faces.first = doublEdg.second; // check if valid intersecting plane @@ -1299,8 +1513,6 @@ std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_in } planes[plane_index].hit_vertices[ih].faces.second = validPlane ? doublEdg.first : doublEdg.second; if (!validPlane) iplv.onEdgeDummy = true; - vlog[iplv.index].hitDoublEdge = validPlane ? doublEdg.first : doublEdg.second ; - vlog[iplv.index].onDoublEdge = validPlane ? 1 : 0; } } } @@ -1353,6 +1565,14 @@ std::vector<NPL_edge> GeoPolyhedronManipulator::evaluateVertexLogic(int plane_in // create line edge for (unsigned int jl =0; jl<vxord.size()-1; jl++) { + GeoTrf::Vector3D vlmid = 0.5 * (vtx[vxord[jl].first] + vtx[vxord[jl+1].first]); + //std::cout << "mid-line check:" << vxord[jl].first <<","<<vxord[jl+1].first <<":inside face:" << insideFace(plane_index,vlmid) + // << ":phA contains:"<< m_phA->contains(vlmid) <<":phB contains:" << m_phB->contains(vlmid) << std::endl; + if (!insideFace(plane_index,vlmid) || !m_phA->contains(vlmid) || !m_phB->contains(vlmid) ) continue; + bool foundLine = false; + for ( auto il : lines ) if ( vxord[jl].first == il.endpoints.first && vxord[jl+1].first == il.endpoints.second) foundLine = true; + for ( auto il : lines ) if ( vxord[jl].first == il.endpoints.second && vxord[jl+1].first == il.endpoints.first) foundLine = true; + if (foundLine) continue; // avoid duplicates lines.push_back(createLine(vxord[jl].first,vxord[jl+1].first,ii.first, plane) ); if (!splitLine) lines.back().protectedLine = true; } @@ -1480,8 +1700,6 @@ void GeoPolyhedronManipulator::saveHitOnEdge(NPH_vtx nvtx, std::vector<NPH_edge else break; } edges[nvtx.edge].evtx.insert(vIt,nvtx); - //std::cout <<"inserting evtx(method):" << nvtx.index <<":at:" << nvtx.distance <<":endpoints:" << - // edges[nvtx.edge].endpoints.first << "," << edges[nvtx.edge].endpoints.second<<":hit plane:" << nvtx.hitPlane<< std::endl; } NPL_edge GeoPolyhedronManipulator::createLine(int iv1, int iv2, int adj, NPH_plane plane) const { @@ -1545,8 +1763,12 @@ NPL_ordered GeoPolyhedronManipulator::mergeLoops( NPL_ordered loop1, NPL_ordered merged.vtx.push_back(merged.vtx.front()); loop2.vtx.push_back(loop2.vtx.front()); + merged.edges.push_back(-1); + loop2.edges.push_back(-1); merged.vtx.insert(merged.vtx.begin(),loop2.vtx.begin(),loop2.vtx.end()); + merged.edges.insert(merged.edges.begin(),loop2.edges.begin(),loop2.edges.end()); + } return merged; @@ -1562,3 +1784,189 @@ GeoTrf::Vector3D GeoPolyhedronManipulator::areaVec( std::vector<size_t> loop, st return area; } + +int GeoPolyhedronManipulator::nextOri(int input, std::vector<NPL_edge> plane_edges, + std::vector<NPL_edge> edge_loop_origin, std::vector<int> availableEdges, bool previous) const { + + int next = -1; + + // find input edge in the original loop + int ori = -1; + for ( unsigned int ieo = 0; ieo < edge_loop_origin.size(); ieo++) { + if (plane_edges[input].endpoints.first == edge_loop_origin[ieo].endpoints.first && + plane_edges[input].endpoints.second == edge_loop_origin[ieo].endpoints.second && + plane_edges[input].adjacent_face == edge_loop_origin[ieo].adjacent_face ) { ori = ieo; break; } + } + // next edge in original set + int ori_next = ori<edge_loop_origin.size()-1 ? ori+1 : 0; + if (previous) ori_next = ori>0 ? ori-1 : edge_loop_origin.size()-1; + + // find index in full set + for ( unsigned int ie = 0; ie < plane_edges.size(); ie++) { + if (plane_edges[ie].endpoints.first == edge_loop_origin[ori_next].endpoints.first && + plane_edges[ie].endpoints.second == edge_loop_origin[ori_next].endpoints.second && + plane_edges[ie].adjacent_face == edge_loop_origin[ori_next].adjacent_face ) { next = ori_next; break; } + } + // check is available + bool available = false; + for ( auto ie : availableEdges) if (next == ie) available = true; + + if (available) return next; + else return -1; + +} + +std::vector<std::pair<int,int> > GeoPolyhedronManipulator::missing_edges( const GeoPolyhedronGeneric gpg) const { + + std::vector<std::pair<int,int> > missing; + + // loop over edges, check that each appears with its mirrored version ( attached faces ) + for ( unsigned int ic=0; ic < gpg.getNFaces(); ic++) { + std::vector<size_t> vtx = gpg.getFace(ic); + if (vtx.size()<2) continue; // should not happen though + for (unsigned int iv=0; iv<vtx.size(); iv++) { + std::pair<size_t,size_t> edge(vtx[iv], iv<vtx.size()-1 ? vtx[iv+1] : vtx[0]); // probe + bool mirrored = false; // search mirrored edge + for ( unsigned int icm=0; icm < gpg.getNFaces(); icm++) { + std::vector<size_t> vtm = gpg.getFace(icm); + if (vtm.size()<2) continue; // should not happen though + for (unsigned int ivm=0; ivm<vtm.size(); ivm++) { + std::pair<size_t,size_t> edgm(vtm[ivm], ivm<vtm.size()-1 ? vtm[ivm+1] : vtm[0]); // test + if ( edgm.first == edge.second && edgm.second == edge.first) mirrored = true; + if (mirrored) break; + } // end loop over other edges + if (mirrored) break; + } // end loop over other faces + if (!mirrored) { + missing.push_back(std::pair<int,int>(edge.second,edge.first)); + } + } // end loop over edges + } // end loop over faces + + return missing; +} + +GeoPolyhedronGeneric GeoPolyhedronManipulator::resolve(const GeoShape* shape, GeoTrf::Transform3D& trf, int polyhedrize, int level, bool debugMode) { + + if (debugMode) std::cout << "recursively resolve:" << shape->type() << std::endl; + + if (shape->type() == "Shift") { + const GeoShapeShift* shift = dynamic_cast<const GeoShapeShift*> (shape); + if (shift) { + GeoTrf::Transform3D trshift = trf*shift->getX(); + GeoPolyhedronGeneric gp = resolve(shift->getOp(), trshift, polyhedrize, level+1 ); + if (debugMode) { + std::cout << "resolved?:"<< gp.getStatus() <<":level:"<<level<<":" << shape->type() <<":number of faces:" << gp.getNFaces(); + if (gp.getStatus()==0) std::cout<<":vol:"<< gp.volume()<< std::endl; + else std::cout << ""<< std::endl; + } + return gp; + } + } + else if (shape->type() == "Union") { + const GeoShapeUnion* uni = dynamic_cast<const GeoShapeUnion*> (shape); + GeoPolyhedronGeneric gpA = resolve(uni->getOpA(), trf, polyhedrize, level+1 ); + GeoPolyhedronGeneric gpB = resolve(uni->getOpB(), trf, polyhedrize, level+1 ); + if (gpA.getStatus() > 0 || gpB.getStatus() > 0 ) return ( gpA.getStatus() > gpB.getStatus() ? gpA : gpB ); + if (debugMode) std::cout << "entering resolveBoolean for union:faces:" << gpA.getNFaces() <<"," << gpB.getNFaces() <<":status:" << gpA.getStatus()<<"," << gpB.getStatus()<< std::endl; + GeoPolyhedronGeneric gpp = (gpA.getNFaces()==0 || gpB.getNFaces()==0) ? (gpA.getNFaces()==0 ? gpB : gpA) : resolveBoolean(&gpA,&gpB,2,false); + if (debugMode) { + std::cout << "resolved ?:"<< gpp.getStatus()<<":level:" <<level<<":" << shape->type() <<":number of faces:" << gpp.getNFaces(); + if (gpp.getStatus()==0) std::cout<<":vol:"<< gpp.volume()<< std::endl; + else std::cout << ""<< std::endl; + } + return gpp; + } + else if (shape->type() == "Subtraction") { + const GeoShapeSubtraction* sub = dynamic_cast<const GeoShapeSubtraction*> (shape); + GeoPolyhedronGeneric gpA = resolve(sub->getOpA(), trf, polyhedrize, level+1 ); + GeoPolyhedronGeneric gpB = resolve(sub->getOpB(), trf, polyhedrize, level+1 ); + if (gpA.getStatus() > 0 || gpB.getStatus() > 0 ) return ( gpA.getStatus() > gpB.getStatus() ? gpA : gpB ); + if (debugMode) std::cout << "entering resolveBoolean for subtraction:faces:" << gpA.getNFaces() <<"," << gpB.getNFaces() <<":status:" << gpA.getStatus()<<"," << gpB.getStatus()<< std::endl; + GeoPolyhedronGeneric gpp = (gpA.getNFaces()==0 || gpB.getNFaces()==0) ? gpA : resolveBoolean(&gpA,&gpB,1,false); + if (debugMode) { + std::cout << "resolved?:"<< gpp.getStatus()<<":level:" <<level<<":" << shape->type() <<":number of faces:" << gpp.getNFaces(); + if (gpp.getStatus()==0) std::cout<<":vol:"<< gpp.volume()<< std::endl; + else std::cout << ""<< std::endl; + } + return gpp; + } + else if (shape->type() == "Intersection") { + const GeoShapeIntersection* ix = dynamic_cast<const GeoShapeIntersection*> (shape); + GeoPolyhedronGeneric gpA = resolve(ix->getOpA(), trf, polyhedrize, level+1 ); + GeoPolyhedronGeneric gpB = resolve(ix->getOpB(), trf, polyhedrize, level+1 ); + if (gpA.getStatus() > 0 || gpB.getStatus() > 0 ) return ( gpA.getStatus() > gpB.getStatus() ? gpA : gpB ); + if (debugMode) std::cout << "entering resolveBoolean for intersection:faces:" << gpA.getNFaces() <<"," << gpB.getNFaces() <<":status:" << gpA.getStatus()<<"," << gpB.getStatus()<< std::endl; + GeoPolyhedronGeneric gpp = (gpA.getNFaces()==0 || gpB.getNFaces()==0) ? (gpA.getNFaces()==0 ? gpA : gpB) : resolveBoolean(&gpA,&gpB,0,false); + if (debugMode) { + std::cout << "resolved?:"<< gpp.getStatus()<<":level:" <<level<<":" << shape->type() <<":number of faces:" << gpp.getNFaces(); + if (gpp.getStatus()==0) std::cout<<":vol:"<< gpp.volume()<< std::endl; + else std::cout << ""<< std::endl; + } + return gpp; + } else { + GeoPolyhedronGeneric gp(shape,trf,polyhedrize); + if (debugMode) { + if (shape->type() == "PolyhedronGeneric") std::cout << "gpg on input:" << gp.isValid() << std::endl; + if (gp.isValid()) std::cout << "resolved:"<<level<<":" << shape->type() <<":number of faces:" << gp.getNFaces()<<":vol:"<<gp.volume() << std::endl; + } + if (gp.isValid()) return gp; + else if (debugMode) std::cout << "shape conversion ->gpg fails:" << shape->type() << std::endl; + } + + GeoPolyhedronGeneric gpu; gpu.setStatus(1); + if (debugMode) std::cout << "unresolved:" <<level<<":"<<shape->type()<< std::endl; + return gpu; + +} + +void GeoPolyhedronManipulator::collectFaceNumber(const GeoShape* shape, int& nFaces ) { + + if ( shape->type() == "Box" || shape->type() == "Trd") nFaces+=6; + else if ( shape->type() == "SimplePolygonBrep") { + const GeoSimplePolygonBrep* spb = dynamic_cast<const GeoSimplePolygonBrep*> (shape); + nFaces += 2+spb->getNVertices(); + } + else if (shape->type() == "Shift") { + const GeoShapeShift* ix = dynamic_cast<const GeoShapeShift*> (shape); + collectFaceNumber( ix->getOp(), nFaces ); + } + else if (shape->type() == "Intersection") { + const GeoShapeIntersection* ix = dynamic_cast<const GeoShapeIntersection*> (shape); + collectFaceNumber( ix->getOpA(), nFaces ); + collectFaceNumber( ix->getOpB(), nFaces ); + } + else if (shape->type() == "Subtraction") { + const GeoShapeSubtraction* ix = dynamic_cast<const GeoShapeSubtraction*> (shape); + collectFaceNumber( ix->getOpA(), nFaces ); + collectFaceNumber( ix->getOpB(), nFaces ); + } + else if (shape->type() == "Union") { + const GeoShapeUnion* ix = dynamic_cast<const GeoShapeUnion*> (shape); + collectFaceNumber( ix->getOpA(), nFaces ); + collectFaceNumber( ix->getOpB(), nFaces ); + } + else if (shape->type() == "Tube") { + const GeoTube* tub = dynamic_cast<const GeoTube*> (shape); + nFaces +=3; + if (tub->getRMin() > 0 ) nFaces +=1; + //if (tub->getDPhi() < acos(-1.) ) nFaces +=2; + } + else if (shape->type() == "Tubs") { + const GeoTubs* tubs = dynamic_cast<const GeoTubs*> (shape); + nFaces +=3; + if (tubs->getRMin() > 0 ) nFaces +=1; + if (tubs->getDPhi() < acos(-1.) ) nFaces +=2; + } + else if (shape->type() == "Pcon") { + const GeoPcon* pcon = dynamic_cast<const GeoPcon*> (shape); + int np = pcon->getNPlanes()-1; + nFaces +=2 + np; + if (pcon->getRMinPlane(0) > 0 ) nFaces += np; + if (pcon->getDPhi() < acos(-1.) ) nFaces += 2*np ; + } + else std::cout << "faces not collected:" << shape->type() << std::endl; + + + +}