// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. /*********************************************************************** * * * Name: BooleanProcessor Date: 10.12.99 * * Author: E.Chernyaev Revised: * * * * Function: Internal class for executing boolean operations * * on Polyhedra * * * ***********************************************************************/ #include "../lina/plane" //#define TOOLS_HEP_BP_OUT_ERR //#define TOOLS_HEP_BP_CHECK_INDEX //#define TOOLS_HEP_BP_VERBOSE //#define TOOLS_HEP_BP_NOT_OPT #if defined(TOOLS_HEP_BP_OUT_ERR) || defined(TOOLS_HEP_BP_VERBOSE) || defined(TOOLS_HEP_BP_CHECK_INDEX) #include #endif namespace tools { namespace hep { typedef plane HVPlane3D; const double GRANULARITY = 10.e+5; // Operations const int OP_UNION = 0; const int OP_INTERSECTION = 1; const int OP_SUBTRACTION = 2; // Face vs face statuses const int OUT_OF_PLANE = 0; const int ON_PLANE = 1; const int INTERSECTION = 2; const int EDGE = 3; const int NON_PLANAR_FACE = 4; // Face statuses const int UNKNOWN_FACE = 0; const int ORIGINAL_FACE = -1; const int NEW_FACE = -2; const int UNSUITABLE_FACE = -3; const int DEFECTIVE_FACE = -4; // -------------------------------------------- Simplified STL vector --- //G.Barrand : begin //#include //G.Barrand : end // ---------------------------------------------------- Extended node --- class ExtNode { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::hep::ExtNode) #endif public: HVPoint3D v; int s; public: ExtNode(HVPoint3D vertex=HVPoint3D(), int status=0) : v(vertex), s(status) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ~ExtNode() { #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } ExtNode(const ExtNode & node) : v(node.v), s(node.s) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ExtNode & operator=(const ExtNode & node) { v = node.v; s = node.s; return *this; } }; // ---------------------------------------------------- Extended edge --- class ExtEdge { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::hep::ExtEdge) #endif public: int i1, i2; // end points int iface1; // native face int iface2; // neighbouring face int ivis; // visibility: +1 (visible), -1 (invisible) int inext; // index of next edge public: ExtEdge(int k1=0, int k2=0, int kface1=0, int kface2=0, int kvis=0) : i1(k1), i2(k2), iface1(kface1), iface2(kface2), ivis(kvis), inext(0) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ~ExtEdge() { #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } ExtEdge(const ExtEdge & edge) : i1(edge.i1), i2(edge.i2), iface1(edge.iface1), iface2(edge.iface2), ivis(edge.ivis), inext(edge.inext) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ExtEdge & operator=(const ExtEdge & edge) { i1 = edge.i1; i2 = edge.i2; iface1 = edge.iface1; iface2 = edge.iface2; ivis = edge.ivis; inext = edge.inext; return *this; } void invert() { int w; //#define SWAP(A,B) w = A; A = B; B = w //SWAP(i1, i2); w = i1;i1=i2;i2=w; } }; // ---------------------------------------------------- Extended face --- class ExtFace { private: #ifdef TOOLS_MEM TOOLS_SCLASS(tools::hep::ExtFace) #endif std::vector& edges; //G.Barrand public: int iedges[4]; // indices of original edges HVPlane3D plane; // face plane double rmin[3], rmax[3]; // bounding box int iold; // head of the list of the original edges int inew; // head of the list of the new edges int iprev; // index of previous face int inext; // index of next face public: //G.Barrand : ExtFace(int iedge=0) : iold(iedge), inew(0), iprev(iprev), inext(0) {} ExtFace(std::vector& a_edges,int iedge) : edges(a_edges), iold(iedge), inew(0), iprev(0), inext(0) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif //G.Barrand : initialize arrays to quiet valgrind. {for (int i=0; i<4; i++) { iedges[i] = 0; }} {for (int i=0; i<3; i++) { rmin[i] = 0; rmax[i] = 0; }} } ~ExtFace() { #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } ExtFace(const ExtFace & face) : edges(face.edges), //G.Barrand plane(face.plane), iold(face.iold), inew(face.inew), iprev(face.iprev), inext(face.inext) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif int i; for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; } for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; } } ExtFace & operator=(const ExtFace & face) { //FIXME : edges(face.edges) ???? //G.Barrand int i; for (i=0; i<4; i++) { iedges[i] = face.iedges[i]; } plane = face.plane; for (i=0; i<3; i++) { rmin[i] = face.rmin[i]; rmax[i] = face.rmax[i]; } iold = face.iold; inew = face.inew; iprev = face.iprev; inext = face.inext; return *this; } bool invert(); //G.Barrand : return bool. //G.Barrand #ifdef TOOLS_HEP_BP_CHECK_INDEX bool check_edge_index(const std::string& a_where,int a_index) { if(a_index<0) { std::cerr << "ExtFace::check_edge_index :" << " " << a_where << " :" << " i<0." << std::endl; return false; } if(a_index>=int(edges.size())) { std::cerr << "ExtFace::check_edge_index :" << " " << a_where << " :" << " i>=sz." << " i=" << a_index << " sz=" << edges.size() << " cap=" << edges.capacity() << std::endl; return false; } return true; } #endif }; // ---------------------------------------------------- Global arrays --- //G.Barrand : MacIntel : crash with g++-4.0.1 with -O on some subtract. // Anyway static of objects is proved to be not safe. // We put the below vector as members of BooleanProcessor. //GB static std::vector nodes; // vector of nodes //GB static std::vector edges; // vector of edges //GB static std::vector faces; // vector of faces // ---------------------------------------------------- List of faces --- class FaceList { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::hep::FaceList) #endif private: std::vector& faces; //G.Barrad : end private: int ihead; int ilast; public: //G.Barrand : FaceList() : ihead(0), ilast(0) {} FaceList(std::vector& a_faces) : faces(a_faces),ihead(0),ilast(0) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ~FaceList() { #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } protected: FaceList(const FaceList& a_from) :faces(a_from.faces),ihead(0),ilast(0){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } FaceList& operator=(const FaceList&) {return *this;} public: void clean() { ihead = 0; ilast = 0; } int front() { return ihead; } void push_back(int i) { if (ilast == 0) { ihead = i; } else { faces[ilast].inext = i; } ExtFace& face = faces[i]; //G.Barrand : optimize. face.iprev = ilast; face.inext = 0; ilast = i; } void remove(int i) { ExtFace& face = faces[i]; //G.Barrand : optimize. if (ihead == i) { ihead = face.inext; }else{ faces[face.iprev].inext = face.inext; } if (ilast == i) { ilast = face.iprev; }else{ faces[face.inext].iprev = face.iprev; } face.iprev = 0; face.inext = 0; } }; // --------------------- Polyhedron with extended access to // its members from the BooleanProcessor class --- class ExtPolyhedron : public polyhedron { friend class BooleanProcessor; virtual polyhedron& operator = (const polyhedron& from) { return polyhedron::operator = (from); } }; // ----------------------------------------- Boolean processor class --- class BooleanProcessor { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::hep::BooleanProcessor) #endif private: //static int ishift; //G.Barrand std::vector nodes; // vector of nodes //G.Barrand std::vector edges; // vector of edges //G.Barrand std::vector faces; // vector of faces //G.Barrand private: //int processor_error; // is set in case of error int operation; // 0 (union), 1 (intersection), 2 (subtraction) int ifaces1, ifaces2; // lists of faces int iout1, iout2; // lists of faces with status "out" int iunk1, iunk2; // lists of faces with status "unknown" double rmin[3], rmax[3]; // intersection of bounding boxes double del; // precision (tolerance) FaceList result_faces; // list of accepted faces FaceList suitable_faces; // list of suitable faces FaceList unsuitable_faces; // list of unsuitable faces FaceList unknown_faces; // list of unknown faces std::vector external_contours; // heads of external contours std::vector internal_contours; // heads of internal contours public: private: bool takePolyhedron(const polyhedron & p, double, double, double); double findMinMax(); void selectOutsideFaces(int & ifaces, int & iout); int testFaceVsPlane(ExtEdge & edge); void renumberNodes(int & i1, int & i2, int & i3, int & i4); int testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2); void removeJunkNodes() { while(nodes.back().s != 0) nodes.pop_back(); } void divideEdge(int & i1, int & i2); void insertEdge(const ExtEdge & edge); void caseII(ExtEdge & edge1, ExtEdge & edge2); bool caseIE(ExtEdge & edge1, ExtEdge & edge2); bool caseEE(ExtEdge & edge1, ExtEdge & edge2); bool testFaceVsFace(int iface1, int iface2); void invertNewEdges(int iface); void checkDoubleEdges(int iface); bool assembleFace(int what, int iface); bool assembleNewFaces(int what, int ihead); bool initiateLists(); bool assemblePolyhedra(); void findABC(double x1, double y1, double x2, double y2, double &a, double &b, double &c) const; int checkDirection(double *x, double *y) const; int checkIntersection(int ix, int iy, int i1, int i2) const; void mergeContours(int ix, int iy, int kext, int kint); bool checkTriangle(int iedge1, int iedge2, int ix, int iy) const; bool triangulateContour(int ix, int iy, int ihead); bool modifyReference(int iface, int i1, int i2, int iref); bool triangulateFace(int iface); polyhedron createPolyhedron(); public: //G.Barrand : BooleanProcessor() {} BooleanProcessor() //G.Barrand //:processor_error(0) //G.Barrand :result_faces(faces) ,suitable_faces(faces) ,unsuitable_faces(faces) ,unknown_faces(faces) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } ~BooleanProcessor() { #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } private: BooleanProcessor(const BooleanProcessor&) //:processor_error(0) //G.Barrand :result_faces(faces) ,suitable_faces(faces) ,unsuitable_faces(faces) ,unknown_faces(faces) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } BooleanProcessor& operator=(const BooleanProcessor&){return *this;} public: polyhedron execute(int op, const polyhedron &a, const polyhedron &b, int& err); //G.Barrand : begin : drawing disconnected. //void draw(); //void draw_edge(int, int); //void draw_contour(int, int, int); //void draw_faces(int, int, int); //void print_face(int); //void print_edge(int); //G.Barrand : end //int get_processor_error() const {return processor_error;} void dump(std::ostream&); //G.Barrand static int& get_shift(); //G.Barrand static void set_shift(int); //G.Barrand static void inc_shift(); //G.Barrand static int get_num_shift(); //G.Barrand private: bool inc_try_count(int,const polyhedron&,const polyhedron&,int&); //GB static HVPoint3D CRAZY_POINT(){return HVPoint3D(-10.e+6, -10.e+6, -10.e+6);} #ifdef TOOLS_HEP_BP_OUT_ERR static void PROCESSOR_ERROR(int a_what){ std::cerr << "BooleanProcessor: boolean operation problem (" << a_what << "). Try again with other shifts." << std::endl; } #else static void PROCESSOR_ERROR(int){} #endif //G.Barrand : #ifdef TOOLS_HEP_BP_CHECK_INDEX bool check_face_index(const std::string& a_where,int a_index) { if(a_index<0) { std::cerr << "BooleanProcessor::check_face_index :" << " " << a_where << " :" << " i<0." << std::endl; return false; } if(a_index>=int(faces.size())) { std::cerr << "BooleanProcessor::check_face_index :" << " " << a_where << " :" << " i>=sz." << " i=" << a_index << " sz=" << faces.size() << " cap=" << faces.capacity() << std::endl; return false; } return true; } bool check_edge_index(const std::string& a_where,int a_index) { if(a_index<0) { std::cerr << "BooleanProcessor::check_edge_index :" << " " << a_where << " :" << " i<0." << std::endl; return false; } if(a_index>=int(edges.size())) { std::cerr << "BooleanProcessor::check_edge_index :" << " " << a_where << " :" << " i>=sz." << " i=" << a_index << " sz=" << edges.size() << " cap=" << edges.capacity() << std::endl; return false; } return true; } #endif }; inline bool ExtFace::invert() //G.Barrand : return bool. /*********************************************************************** * * * Name: ExtFace::invert() Date: 28.02.00 * * Author: E.Chernyaev Revised: * * * * Function: Invert face * * * ***********************************************************************/ { int iEprev, iEcur, iEnext; iEprev = 0; iEcur = iold; while (iEcur > 0) { #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_edge_index("ExtFace::invert(1)",iEcur)) return false; #endif ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize. edge.invert(); iEnext = edge.inext; edge.inext = iEprev; iEprev = iEcur; iEcur = iEnext; } if (iold > 0) iold = iEprev; iEprev = 0; iEcur = inew; while (iEcur > 0) { #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_edge_index("ExtFace::invert(2)",iEcur)) return false; #endif ExtEdge& edge = edges[iEcur]; //G.Barrand : optimize. edge.invert(); iEnext = edge.inext; edge.inext = iEprev; iEprev = iEcur; iEcur = iEnext; } if (inew > 0) inew = iEprev; //plane = HVPlane3D(-plane.a(), -plane.b(), -plane.c(), -plane.d()); HVNormal3D n = plane.normal(); n *= -1; plane.set(n, -plane.distance_from_origin()); return true; } inline bool BooleanProcessor::takePolyhedron(const polyhedron & p, double dx, double dy, double dz) /*********************************************************************** * * * Name: BooleanProcessor::takePolyhedron Date: 16.12.99 * * Author: E.Chernyaev Revised: * * * * Function: Transfer Polyhedron to internal representation * * * ***********************************************************************/ { int i, k, nnode, iNodes[5], iVis[4], iFaces[4]; int dnode = int(nodes.size()) - 1; int dface = int(faces.size()) - 1; // S E T N O D E S // for (i=1; i <= p.GetNoVertices(); i++) { // nodes.push_back(ExtNode(p.GetVertex(i))); // } HVPoint3D ppp; for (i=1; i <= p.GetNoVertices(); i++) { #ifndef TOOLS_HEP_BP_NOT_OPT //G.Barrand nodes.push_back(ExtNode()); ExtNode& node = nodes.back(); node.v = p.GetVertexFast(i); node.v.add(dx,dy,dz); #else ppp = p.GetVertexFast(i); ppp += HVPoint3D(dx,dy,dz); nodes.push_back(ExtNode(ppp)); #endif } // S E T F A C E S HVNormal3D plane_n; //G.Barrand HVPoint3D plane_p; //G.Barrand for (int iface=1; iface <= p.GetNoFacets(); iface++) { faces.push_back(ExtFace(edges,int(edges.size()))); // S E T F A C E N O D E S p.GetFacet(iface, nnode, iNodes, iVis, iFaces); for (i=0; i p.GetNoVertices()) processor_error = 1; //if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) processor_error = 1; if (iNodes[i] < 1 || iNodes[i] > p.GetNoVertices()) { //G.Barrand //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::takePolyhedron : problem 1." << " nnode " << nnode << " p.GetNoVertices() " << p.GetNoVertices() << " p.GetNoFacets() " << p.GetNoFacets() << " iface " << iface << " i " << i << " iNodes[i] " << iNodes[i] << std::endl; #endif return false; //G.Barrand } if (iFaces[i] < 1 || iFaces[i] > p.GetNoFacets()) { //G.Barrand //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::takePolyhedron : problem 2." << " p.GetNoVertices() " << p.GetNoVertices() << " p.GetNoFacets() " << p.GetNoFacets() << " iface " << iface << " i " << i << " iFaces[i] " << iFaces[i] << std::endl; #endif return false; //G.Barrand } iNodes[i] += dnode; iFaces[i] += dface; } // S E T E D G E S iNodes[nnode] = iNodes[0]; faces.back().iedges[3] = 0; for (i=0; i node.v[k]) face.rmin[k] = node.v[k]; if (face.rmax[k] < node.v[k]) face.rmax[k] = node.v[k]; } } // S E T F A C E P L A N E (nodes[iNodes[2]].v-nodes[iNodes[0]].v).cross(nodes[iNodes[3]].v-nodes[iNodes[1]].v,plane_n); plane_p.set_value(0,0,0); for (i=0; i 0) { ExtFace& face = faces[iface]; //G.Barrand for (i=0; i<3; i++) { if (rmin1[i] > face.rmin[i]) rmin1[i] = face.rmin[i]; if (rmax1[i] < face.rmax[i]) rmax1[i] = face.rmax[i]; } iface = face.inext; } iface = faces[ifaces2].inext; while(iface > 0) { ExtFace& face = faces[iface]; //G.Barrand for (i=0; i<3; i++) { if (rmin2[i] > face.rmin[i]) rmin2[i] = face.rmin[i]; if (rmax2[i] < face.rmax[i]) rmax2[i] = face.rmax[i]; } iface = face.inext; } // F I N D I N T E R S E C T I O N O F B O U N D I N G B O X E S for (i=0; i<3; i++) { rmin[i] = (rmin1[i] > rmin2[i]) ? rmin1[i] : rmin2[i]; rmax[i] = (rmax1[i] < rmax2[i]) ? rmax1[i] : rmax2[i]; } // F I N D T O L E R A N C E double del1 = 0; double del2 = 0; for (i=0; i<3; i++) { if ((rmax1[i]-rmin1[i]) > del1) del1 = rmax1[i]-rmin1[i]; if ((rmax2[i]-rmin2[i]) > del2) del2 = rmax2[i]-rmin2[i]; } return ((del1 < del2) ? del1 : del2) / GRANULARITY; } inline void BooleanProcessor::selectOutsideFaces(int & ifaces, int & iout) /*********************************************************************** * * * Name: BooleanProcessor::selectOutsideFaces Date: 10.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Preselection of outside faces * * * ***********************************************************************/ { int i, outflag, iface = ifaces, *prev; HVPoint3D mmbox[8] = { HVPoint3D(rmin[0],rmin[1],rmin[2]), HVPoint3D(rmax[0],rmin[1],rmin[2]), HVPoint3D(rmin[0],rmax[1],rmin[2]), HVPoint3D(rmax[0],rmax[1],rmin[2]), HVPoint3D(rmin[0],rmin[1],rmax[2]), HVPoint3D(rmax[0],rmin[1],rmax[2]), HVPoint3D(rmin[0],rmax[1],rmax[2]), HVPoint3D(rmax[0],rmax[1],rmax[2]) }; prev = &ifaces; while (iface > 0) { // B O U N D I N G B O X vs B O U N D I N G B O X outflag = 0; ExtFace& face = faces[iface]; //G.Barrand : optimize. for (i=0; i<3; i++) { if (face.rmin[i] > rmax[i] + del) { outflag = 1; break; } if (face.rmax[i] < rmin[i] - del) { outflag = 1; break; } } // B O U N D I N G B O X vs P L A N E if (outflag == 0) { int npos = 0, nneg = 0; double d; for (i=0; i<8; i++) { d = face.plane.distance(mmbox[i]); //G.Barrand : optimize if (d > +del) npos++; if (d < -del) nneg++; } if (npos == 8 || nneg == 8) outflag = 1; } // U P D A T E L I S T S if (outflag == 1) { *prev = face.inext; face.inext = iout; iout = iface; }else{ prev = &face.inext; } iface = *prev; } } inline int BooleanProcessor::testFaceVsPlane(ExtEdge & edge) /*********************************************************************** * * * Name: BooleanProcessor::testFaceVsPlane Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Find result of intersection of face by plane * * * ***********************************************************************/ { int iface = edge.iface1; const HVPlane3D& plane = faces[edge.iface2].plane; int i, nnode, npos = 0, nneg = 0, nzer = 0; double dd[5]; // F I N D D I S T A N C E S nnode = (faces[iface].iedges[3] == 0) ? 3 : 4; for (i=0; i del) { npos++; }else if (dd[i] < -del) { nneg++; }else{ nzer++; dd[i] = 0; } } // S O M E S I M P L E C A S E S ( N O I N T E R S E C T I O N ) if (npos == nnode || nneg == nnode) return OUT_OF_PLANE; if (nzer == 1 && nneg == 0) return OUT_OF_PLANE; if (nzer == 1 && npos == 0) return OUT_OF_PLANE; if (nzer == nnode) return ON_PLANE; if (nzer == 3) return NON_PLANAR_FACE; // F I N D I N T E R S E C T I O N int ie1 = 0, ie2 = 0, s1 = 0, s2 = 0, status, nint = 0; enum { PLUS_MINUS, MINUS_PLUS, ZERO_ZERO, ZERO_PLUS, ZERO_MINUS }; dd[nnode] = dd[0]; for (i=0; i 0) { if (dd[i+1] >= 0) continue; status = PLUS_MINUS; }else if (dd[i] < 0) { if (dd[i+1] <= 0) continue; status = MINUS_PLUS; }else{ status = ZERO_ZERO; if (dd[i+1] > 0) status = ZERO_PLUS; if (dd[i+1] < 0) status = ZERO_MINUS; } switch (nint) { case 0: ie1 = i; s1 = status; nint++; break; case 1: ie2 = i; s2 = status; nint++; break; default: return NON_PLANAR_FACE; } } if (nint != 2) return NON_PLANAR_FACE; // F O R M I N T E R S E C T I O N S E G M E N T if (s1 != ZERO_ZERO && s2 != ZERO_ZERO) { if (s1 == s2) return NON_PLANAR_FACE; int iedge, i1 = 0, i2 = 0, ii[2]; double d1 = 0., d2 = 0., ddd ; ii[0] = ie1; ii[1] = ie2; for (i=0; i<2; i++) { iedge = faces[iface].iedges[ii[i]]; while (iedge > 0) { i1 = edges[iedge].i1; i2 = edges[iedge].i2; d1 = plane.distance(nodes[i1].v); d2 = plane.distance(nodes[i2].v); if (d1 > del) { if (d2 < -del) { ii[i] = int(nodes.size()); break; } // +- }else if (d1 < -del) { if (d2 > del) { ii[i] = int(nodes.size()); break; } // -+ }else{ ii[i] = i1; break; // 0+ or 0- } iedge = edges[iedge].inext; } if (ii[i] == (int)nodes.size()) { ddd = d2-d1; d1 = d1/ddd; d2 = d2/ddd; nodes.push_back(ExtNode(d2*nodes[i1].v-d1*nodes[i2].v, iedge)); } } edge.inext = 0; if (s1 == MINUS_PLUS || s1 == ZERO_PLUS) { edge.i1 = ii[1]; edge.i2 = ii[0]; }else{ edge.i1 = ii[0]; edge.i2 = ii[1]; } return INTERSECTION; }else{ if (npos == nneg) return NON_PLANAR_FACE; edge.inext = (s1 == ZERO_ZERO) ? ie1+1 : ie2+1; if (s1 == ZERO_PLUS || s2 == ZERO_MINUS) { edge.i1 = edges[faces[iface].iedges[ie2]].i1; edge.i2 = edges[faces[iface].iedges[ie1]].i1; }else{ edge.i1 = edges[faces[iface].iedges[ie1]].i1; edge.i2 = edges[faces[iface].iedges[ie2]].i1; } return EDGE; } } inline void BooleanProcessor::renumberNodes(int & i1, int & i2, int & i3, int & i4) /*********************************************************************** * * * Name: BooleanProcessor::renumberNodes Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Renumber nodes and remove last temporary node. * * Remark: In principal this routine can be replaced just * * with i1 = i2; * * Removal of temporary nodes provides additional control * * on number of nodes, that is very useful for debugging. * * * ***********************************************************************/ { if (i1 == i2) return; if (nodes[i1].s == 0 || nodes.back().s == 0) { i1 = i2; return; } int ilast = int(nodes.size())-1; if (i1 == ilast) { i1 = i2; nodes.pop_back(); return; } if (i2 == ilast) { i2 = i1; } if (i3 == ilast) { i3 = i1; } if (i4 == ilast) { i4 = i1; } nodes[i1] = nodes.back(); i1 = i2; nodes.pop_back(); } inline int BooleanProcessor::testEdgeVsEdge(ExtEdge & edge1, ExtEdge & edge2) /*********************************************************************** * * * Name: BooleanProcessor::testEdgeVsEdge Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Find common part of two edges * * * ***********************************************************************/ { int i, ii = 0; double d, dd = 0.; for (i=0; i<3; i++) { d = nodes[edge1.i1].v[i]-nodes[edge1.i2].v[i]; if (d < 0.) d = -d; if (d > dd) { dd = d; ii = i; } } double t1 = nodes[edge1.i1].v[ii]; double t2 = nodes[edge1.i2].v[ii]; double t3 = nodes[edge2.i1].v[ii]; double t4 = nodes[edge2.i2].v[ii]; if (t2-t1 < 0.) { t1 = -t1; t2 = -t2; t3 = -t3; t4 = -t4; } if (t3 <= t1+del || t4 >= t2-del) return 0; if (t3 > t2+del) { renumberNodes(edge2.i1, edge1.i2, edge1.i1, edge2.i2); }else if (t3 < t2-del) { renumberNodes(edge1.i2, edge2.i1, edge1.i1, edge2.i2); } if (t4 < t1-del) { renumberNodes(edge2.i2, edge1.i1, edge1.i2, edge2.i1); }else if (t4 > t1+del) { renumberNodes(edge1.i1, edge2.i2, edge1.i2, edge2.i1); } return 1; } inline void BooleanProcessor::divideEdge(int & i1, int & i2) /*********************************************************************** * * * Name: BooleanProcessor::divideEdge Date: 24.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Unify the nodes and divide edge on two parts by the node. * * * ***********************************************************************/ { int iedges[2]; iedges[0] = nodes[i1].s; iedges[1] = nodes[i2].s; // U N I F Y N O D E S if (i1 < i2) { i2 = i1; } else if (i1 > i2) { i1 = i2; } else { iedges[1] = 0; } if (iedges[0] == iedges[1]) return; int ie1, ie2, inode = i1; nodes[inode].s = 0; for (int i=0; i<2; i++) { // F I N D C O R R E S P O N D I N G E D G E if ((ie1 = iedges[i]) == 0) continue; ie2 = faces[edges[ie1].iface2].iedges[0]; while (ie2 > 0) { if (edges[ie2].i1 == edges[ie1].i2 && edges[ie2].i2 == edges[ie1].i1) break; ie2 = edges[ie2].inext; } // D I V I D E E D G E S edges.push_back(edges[ie1]); edges[ie1].inext = int(edges.size()) - 1; edges[ie1].i2 = inode; edges.back().i1 = inode; edges.push_back(edges[ie2]); edges[ie2].inext = int(edges.size()) - 1; edges[ie2].i2 = inode; edges.back().i1 = inode; } } inline void BooleanProcessor::insertEdge(const ExtEdge & edge) /*********************************************************************** * * * Name: BooleanProcessor::insertEdge Date: 24.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Insert edge to the list of new edges * * * ***********************************************************************/ { int iface = edge.iface1; edges.push_back(edge); edges.back().inext = faces[iface].inew; faces[iface].inew = int(edges.size()) - 1; } inline void BooleanProcessor::caseII(ExtEdge & edge1, ExtEdge & edge2) /*********************************************************************** * * * Name: BooleanProcessor::caseII Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Intersection/Intersection case * * * ***********************************************************************/ { divideEdge(edge1.i1, edge2.i2); divideEdge(edge1.i2, edge2.i1); edge1.ivis = 1; edge2.ivis = 1; insertEdge(edge1); insertEdge(edge2); } inline bool BooleanProcessor::caseIE(ExtEdge &, ExtEdge &) /*********************************************************************** * * * Name: BooleanProcessor::caseIE Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Intersection/Edge-touch case * * * ***********************************************************************/ { //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::caseIE : unimplemented case" << std::endl; #endif return false; //G.Barrand } inline bool BooleanProcessor::caseEE(ExtEdge &, ExtEdge &) /*********************************************************************** * * * Name: BooleanProcessor::caseEE Date: 19.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Edge-touch/Edge-touch case * * * ***********************************************************************/ { //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::caseEE : unimplemented case" << std::endl; #endif return false; } inline bool BooleanProcessor::testFaceVsFace(int iface1, int iface2) /*********************************************************************** * * * Name: BooleanProcessor::testFaceVsFace Date: 11.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Find result (an edge) of intersection of two faces * * * ***********************************************************************/ { ExtEdge edge1, edge2; int irep1, irep2; // M I N - M A X {const ExtFace& face_1 = faces[iface1]; //G.Barrand : optimize const ExtFace& face_2 = faces[iface2]; for (int i=0; i<3; i++) { if (face_1.rmin[i] > face_2.rmax[i] + del) return true; //GB : true ? if (face_1.rmax[i] < face_2.rmin[i] - del) return true; //GB : true ? }} // F A C E - 1 vs P L A N E - 2 edge1.iface1 = iface1; edge1.iface2 = iface2; irep1 = testFaceVsPlane(edge1); if (irep1 == OUT_OF_PLANE || irep1 == ON_PLANE) { removeJunkNodes(); return true; //GB : true ? } // F A C E - 2 vs P L A N E - 1 edge2.iface1 = iface2; edge2.iface2 = iface1; irep2 = testFaceVsPlane(edge2); if (irep2 == OUT_OF_PLANE || irep2 == ON_PLANE) { removeJunkNodes(); return true; //GB : true ? } // C H E C K F O R N O N P L A N A R F A C E if (irep1 == NON_PLANAR_FACE || irep2 == NON_PLANAR_FACE) { removeJunkNodes(); return true; //GB : true ? } // F I N D I N T E R S E C T I O N P A R T if (testEdgeVsEdge(edge1, edge2) == 0) { return true; //GB : true ? } // C O N S I D E R D I F F E R E N T C A S E S if (irep1 == INTERSECTION && irep2 == INTERSECTION) caseII(edge1, edge2); if (irep1 == INTERSECTION && irep2 == EDGE) { if(!caseIE(edge1, edge2)) { //G.Barrand : processor_error = 1; removeJunkNodes(); //G.Barrand return false; //G.Barrand } } if (irep1 == EDGE && irep2 == INTERSECTION) { if(!caseIE(edge2, edge1)) { //G.Barrand : processor_error = 1; removeJunkNodes(); //G.Barrand return false; //G.Barrand } } if (irep1 == EDGE && irep2 == EDGE) { if(!caseEE(edge1, edge2)) { //G.Barrand : processor_error = 1; removeJunkNodes(); //G.Barrand return false; //G.Barrand } } removeJunkNodes(); return true; //G.Barrand } inline void BooleanProcessor::invertNewEdges(int iface) /*********************************************************************** * * * Name: BooleanProcessor::invertNewEdges Date: 04.02.00 * * Author: E.Chernyaev Revised: * * * * Function: Invert direction of new edges * * * ***********************************************************************/ { int iedge = faces[iface].inew; while (iedge > 0) { edges[iedge].invert(); iedge = edges[iedge].inext; } } inline void BooleanProcessor::checkDoubleEdges(int) /*********************************************************************** * * * Name: BooleanProcessor::checkDoubleEdges Date: 04.02.00 * * Author: E.Chernyaev Revised: * * * * Function: Eliminate duplication of edges * * * ***********************************************************************/ { } inline bool BooleanProcessor::assembleFace(int what, int iface) /*********************************************************************** * * * Name: BooleanProcessor::assembleFace Date: 19.02.00 * * Author: E.Chernyaev Revised: * * * * Function: Assemble face * * * ***********************************************************************/ { // A S S E M B L E N E W F A C E int ihead; // head of the list of edges for new face int icur; // current edge in the list - last edge inserted to the list int *ilink; // pointer to the current link int ifirst; // first node of a contour int *i; // pointer to the index of the current edge in a loop int ioldflag=0; // is set if an edge from iold has been taken ExtFace& face = faces[iface]; //G.Barrand : optimize. ilink = &ihead; for(;;) { if (face.inew == 0) break; // S T A R T N E W C O N T O U R icur = face.inew; face.inew = edges[icur].inext; //INSERT_EDGE_TO_THE_LIST(icur); //G.Barrand *ilink = icur; ilink = &edges[icur].inext; *ilink = 0; //G.Barrand ifirst = edges[icur].i1; // C O N S T R U C T T H E C O N T O U R for (;;) { i = &face.inew; ExtEdge& edge_cur = edges[icur]; while(*i > 0) { ExtEdge& edge_i = edges[*i]; if (edge_i.i1 == edge_cur.i2) break; i = &edge_i.inext; } if (*i == 0) { i = &face.iold; while(*i > 0) { ExtEdge& edge_i = edges[*i]; if (edge_i.i1 == edge_cur.i2) { ioldflag = 1; break; } i = &edge_i.inext; } } if (*i > 0) { icur = *i; *i = edges[icur].inext; //INSERT_EDGE_TO_THE_LIST(icur); *ilink = icur; ilink = &edges[icur].inext; *ilink = 0; //G.Barrand if (edges[icur].i2 == ifirst) { break; } else { continue; } }else{ //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::assembleFace(" << iface << ") : " << "could not find next edge of the contour" << std::endl; #endif face.inew = DEFECTIVE_FACE; return false; //G.Barrand : false } } } // C H E C K O R I G I N A L C O N T O U R int iedge; iedge = face.iold; if (what == 0 && ioldflag == 0 && iedge > 0) { for (;;) { if (edges[iedge].inext > 0) { if (edges[iedge].i2 == edges[edges[iedge].inext].i1) { iedge = edges[iedge].inext; }else{ break; } }else{ if (edges[iedge].i2 == edges[face.iold].i1) { edges[iedge].inext = ihead; // set new face return true; //G.Barrand : true. }else{ break; } } } } // M A R K U N S U I T A B L E N E I G H B O U R I N G F A C E S int iface2; iedge = face.iold; while(iedge > 0) { iface2 = edges[iedge].iface2; if (faces[iface2].inew == 0) faces[iface2].inew = UNSUITABLE_FACE; iedge = edges[iedge].inext; } face.iold = ihead; // set new face return true; } inline bool BooleanProcessor::assembleNewFaces(int what, int ihead) /*********************************************************************** * * * Name: BooleanProcessor::assembleNewFaces Date: 30.01.00 * * Author: E.Chernyaev Revised: * * * * Function: Assemble internal or external parts of faces * * * ***********************************************************************/ { int iface = ihead; while(iface > 0) { if (faces[iface].inew > 0) { if (what != 0) invertNewEdges(iface); checkDoubleEdges(iface); if(!assembleFace(what, iface)) return false; //G.Barrand : test. faces[iface].inew = (faces[iface].iold == 0) ? UNSUITABLE_FACE : NEW_FACE; } iface = faces[iface].inext; } return true; //G.Barrand } inline bool BooleanProcessor::initiateLists() //G.Barrand : return bool. /*********************************************************************** * * * Name: BooleanProcessor::initiateLists Date: 28.02.00 * * Author: E.Chernyaev Revised: * * * * Function: Initiate lists of faces. * * * ***********************************************************************/ { int i, iface; // R E S E T L I S T S O F F A C E S result_faces.clean(); suitable_faces.clean(); unsuitable_faces.clean(); unknown_faces.clean(); // I N I T I A T E T H E L I S T S iface = iout1; while (iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(1)",i)) return false; #endif iface = faces[i].inext; if (operation == OP_INTERSECTION) { unsuitable_faces.push_back(i); faces[i].inew = UNSUITABLE_FACE; }else{ suitable_faces.push_back(i); faces[i].inew = ORIGINAL_FACE; } } iface = iout2; while (iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(2)",i)) return false; #endif iface = faces[i].inext; if (operation == OP_UNION) { suitable_faces.push_back(i); faces[i].inew = ORIGINAL_FACE; }else{ unsuitable_faces.push_back(i); faces[i].inew = UNSUITABLE_FACE; } } iface = iunk1; while (iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(3)",i)) return false; #endif iface = faces[i].inext; unknown_faces.push_back(i); } iface = iunk2; while (iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(4)",i)) return false; #endif iface = faces[i].inext; if (operation == OP_SUBTRACTION) { if(!faces[i].invert()) return false; //G.Barrand } unknown_faces.push_back(i); } iface = ifaces1; while (iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(5)",i)) return false; #endif iface = faces[i].inext; switch(faces[i].inew) { case UNKNOWN_FACE: unknown_faces.push_back(i); break; case ORIGINAL_FACE: case NEW_FACE: suitable_faces.push_back(i); break; case UNSUITABLE_FACE: unsuitable_faces.push_back(i); break; default: faces[i].iprev = 0; faces[i].inext = 0; break; } } iface = ifaces2; while (iface > 0) { i = iface; iface = faces[i].inext; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("initiateLists(6)",i)) return false; #endif if (operation == OP_SUBTRACTION) { if(!faces[i].invert()) return false; } switch(faces[i].inew) { case UNKNOWN_FACE: unknown_faces.push_back(i); break; case ORIGINAL_FACE: case NEW_FACE: suitable_faces.push_back(i); break; case UNSUITABLE_FACE: unsuitable_faces.push_back(i); break; default: faces[i].iprev = 0; faces[i].inext = 0; break; } } ifaces1 = ifaces2 = iout1 = iout2 = iunk1 = iunk2 = 0; return true; //G.Barrand. } inline bool BooleanProcessor::assemblePolyhedra() //G.Barrand : return bool. /*********************************************************************** * * * Name: BooleanProcessor::assemblePolyhedra() Date: 10.12.99 * * Author: E.Chernyaev Revised: * * * * Function: Collect suitable faces and remove unsuitable ones. * * * ***********************************************************************/ { int i, iedge, iface; // L O O P A L O N G S U I T A B L E F A C E S iface = suitable_faces.front(); while(iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(1)",i)) return false; #endif iedge = faces[i].iold; while(iedge > 0) { #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_edge_index("assemblePolyhedra(2)",iedge)) return false; #endif iface = edges[iedge].iface2; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(3)",iface)) return false; #endif if (faces[iface].inew == UNKNOWN_FACE) { unknown_faces.remove(iface); suitable_faces.push_back(iface); faces[iface].inew = ORIGINAL_FACE; } iedge = edges[iedge].inext; } #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(4)",i)) return false; #endif iface = faces[i].inext; suitable_faces.remove(i); result_faces.push_back(i); } if (unknown_faces.front() == 0) return true; // L O O P A L O N G U N S U I T A B L E F A C E S iface = unsuitable_faces.front(); while(iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(5)",i)) return false; #endif iedge = faces[i].iold; while(iedge > 0) { #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_edge_index("assemblePolyhedra(6)",iedge)) return false; #endif iface = edges[iedge].iface2; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(7)",iface)) return false; #endif if (faces[iface].inew == UNKNOWN_FACE) { unknown_faces.remove(iface); unsuitable_faces.push_back(iface); faces[iface].inew = UNSUITABLE_FACE; } iedge = edges[iedge].inext; } #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(8)",i)) return false; #endif iface = faces[i].inext; unsuitable_faces.remove(i); } //G.Barrand : begin /* From S.Ponce At last, there is a problem in the assemblePolyhedra method. At least, I think it is there. The problem deals with boolean operations on solids, when one of the two contains entirely the other one. It has no sense for intersection and union but still has sense for subtraction. In this case, faces from the inner solid are stored in the unknown_faces FaceList. And an error occurs in the execute method. This may be correct for intersection and union but in the case of subtraction, one should do that in assemblePolyhedra : */ // Unknown faces are actually suitable face !!! iface = unknown_faces.front(); while(iface > 0) { i = iface; #ifdef TOOLS_HEP_BP_CHECK_INDEX if(!check_face_index("assemblePolyhedra(9)",i)) return false; #endif faces[i].inew = ORIGINAL_FACE; iface = faces[i].inext; unknown_faces.remove(i); result_faces.push_back(i); } /* Otherwise, the inner hole that the second solid was building in the first one does not exist. I'm not very clear on what to do for unions and intersections. I think this kind of situation should be detected and one of the solid should simply be ignored. */ //G.Barrand : end return true; } inline void BooleanProcessor::findABC(double x1, double y1, double x2, double y2, double &a, double &b, double &c) const /*********************************************************************** * * * Name: BooleanProcessor::findABC Date: 07.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Find line equation Ax+By+C=0 * * * ***********************************************************************/ { double w; a = y1 - y2; b = x2 - x1; //G.Barrand : w = std::abs(a)+std::abs(b); w = ::fabs(a)+::fabs(b); //G.Barrand a /= w; b /= w; c = -(a*x2 + b*y2); } inline int BooleanProcessor::checkDirection(double *x, double *y) const /*********************************************************************** * * * Name: BooleanProcessor::checkDirection Date: 06.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Check direction of line 1-4 * * * ***********************************************************************/ { double a1, b1, c1, a2, b2, c2, d1, d2; // T E S T L I N E 1 - 4 V S E X T E R N A L C O N T O U R findABC(x[0], y[0], x[1], y[1], a1, b1, c1); findABC(x[1], y[1], x[2], y[2], a2, b2, c2); d1 = a1*x[4] + b1*y[4] + c1; d2 = a2*x[4] + b2*y[4] + c2; if (d1 <= del && d2 <= del) return 1; if (! (d1 > del && d2 > del)) { if ( a1*x[2] + b1*y[2] + c1 >= -del) return 1; } // T E S T L I N E 1 - 4 V S I N T E R N A L C O N T O U R findABC(x[3], y[3], x[4], y[4], a1, b1, c1); findABC(x[4], y[4], x[5], y[5], a2, b2, c2); d1 = a1*x[1] + b1*y[1] + c1; d2 = a2*x[1] + b2*y[1] + c2; if (d1 <= del && d2 <= del) return 1; if (!(d1 > del && d2 > del)) { if ( a1*x[5] + b1*y[5] + c1 >= -del) return 1; } return 0; } inline int BooleanProcessor::checkIntersection(int ix, int iy, int i1, int i2) const /*********************************************************************** * * * Name: BooleanProcessor::checkDirection Date: 06.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Check line i1-i2 on intersection with contours * * * ***********************************************************************/ { // F I N D L I N E E Q U A T I O N double x1, y1, x2, y2, a1, b1, c1; x1 = nodes[i1].v[ix]; y1 = nodes[i1].v[iy]; x2 = nodes[i2].v[ix]; y2 = nodes[i2].v[iy]; findABC(x1, y1, x2, y2, a1, b1, c1); // L O O P A L O N G E X T E R N A L C O N T O U R S int icontour, iedge, k1, k2; double x3, y3, x4, y4, a2, b2, c2, d1, d2; for(icontour=0; icontour<(int)external_contours.size(); icontour++) { iedge = external_contours[icontour]; while(iedge > 0) { k1 = edges[iedge].i1; k2 = edges[iedge].i2; iedge = edges[iedge].inext; if (k1 == i1 || k2 == i1) continue; if (k1 == i2 || k2 == i2) continue; x3 = nodes[k1].v[ix]; y3 = nodes[k1].v[iy]; x4 = nodes[k2].v[ix]; y4 = nodes[k2].v[iy]; d1 = a1*x3 + b1*y3 + c1; d2 = a1*x4 + b1*y4 + c1; if (d1 > del && d2 > del) continue; if (d1 < -del && d2 < -del) continue; findABC(x3, y3, x4, y4, a2, b2, c2); d1 = a2*x1 + b2*y1 + c2; d2 = a2*x2 + b2*y2 + c2; if (d1 > del && d2 > del) continue; if (d1 < -del && d2 < -del) continue; return 1; } } // L O O P A L O N G E X T E R N A L C O N T O U R S for(icontour=0; icontour<(int)internal_contours.size(); icontour++) { iedge = internal_contours[icontour]; while(iedge > 0) { k1 = edges[iedge].i1; k2 = edges[iedge].i2; iedge = edges[iedge].inext; if (k1 == i1 || k2 == i1) continue; if (k1 == i2 || k2 == i2) continue; x3 = nodes[k1].v[ix]; y3 = nodes[k1].v[iy]; x4 = nodes[k2].v[ix]; y4 = nodes[k2].v[iy]; d1 = a1*x3 + b1*y3 + c1; d2 = a1*x4 + b1*y4 + c1; if (d1 > del && d2 > del) continue; if (d1 < -del && d2 < -del) continue; findABC(x3, y3, x4, y4, a2, b2, c2); d1 = a2*x1 + b2*y1 + c2; d2 = a2*x2 + b2*y2 + c2; if (d1 > del && d2 > del) continue; if (d1 < -del && d2 < -del) continue; return 1; } } return 0; } inline void BooleanProcessor::mergeContours(int ix, int iy, int kext, int kint) /*********************************************************************** * * * Name: BooleanProcessor::mergeContours Date: 06.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Attemp to merge internal contour with external one * * * ***********************************************************************/ { int i1ext, i2ext, i1int, i2int, i, k[6]; double x[6], y[6]; // L O O P A L O N G E X T E R N A L C O N T O U R i1ext = external_contours[kext]; while (i1ext > 0) { i2ext = edges[i1ext].inext; if (i2ext == 0) i2ext = external_contours[kext]; k[0] = edges[i1ext].i1; k[1] = edges[i1ext].i2; k[2] = edges[i2ext].i2; for (i=0; i<3; i++) { x[i] = nodes[k[i]].v[ix]; y[i] = nodes[k[i]].v[iy]; } // L O O P A L O N G I N T E R N A L C O N T O U R i1int = internal_contours[kint]; while (i1int > 0) { i2int = edges[i1int].inext; if (i2int == 0) i2int = internal_contours[kint]; k[3] = edges[i1int].i1; k[4] = edges[i1int].i2; k[5] = edges[i2int].i2; for (i=3; i<6; i++) { x[i] = nodes[k[i]].v[ix]; y[i] = nodes[k[i]].v[iy]; } // T E S T L I N E K1 - K4 // I F O K T H E N M E R G E C O N T O U R S if (checkDirection(x, y) == 0) { if (checkIntersection(ix, iy, k[1], k[4]) == 0) { i = i1int; for(;;) { if (edges[i].inext == 0) { edges[i].inext = internal_contours[kint]; internal_contours[kint] = 0; break; }else{ i = edges[i].inext; } } i = edges[i1int].iface1; edges.push_back(ExtEdge(k[1], k[4], i, -1*(int(edges.size())+1), -1)); edges.back().inext = i2int; edges.push_back(ExtEdge(k[4], k[1], i, -1*(int(edges.size())-1), -1)); edges.back().inext = edges[i1ext].inext; edges[i1ext].inext = int(edges.size())-2; edges[i1int].inext = int(edges.size())-1; return; } } i1int = edges[i1int].inext; } i1ext = edges[i1ext].inext; } } inline bool BooleanProcessor::checkTriangle(int iedge1, int iedge2, int ix, int iy) const /*********************************************************************** * * * Name: BooleanProcessor::checkTriangle Date: 08.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Check triangle for correctness * * * ***********************************************************************/ { int k[3]; double x[3], y[3]; double a1, b1, c1; k[0] = edges[iedge1].i1; k[1] = edges[iedge1].i2; k[2] = edges[iedge2].i2; for (int i=0; i<3; i++) { x[i] = nodes[k[i]].v[ix]; y[i] = nodes[k[i]].v[iy]; } // C H E C K P R I N C I P A L C O R R E C T N E S S findABC(x[2], y[2], x[0], y[0], a1, b1, c1); if (a1*x[1]+b1*y[1]+c1 <= 0.1*del) return true; // C H E C K T H A T T H E R E I S N O P O I N T S I N S I D E int inode, iedge; double a2, b2, c2, a3, b3, c3; findABC(x[0], y[0], x[1], y[1], a2, b2, c2); findABC(x[1], y[1], x[2], y[2], a3, b3, c3); iedge = iedge2; for (;;) { iedge = edges[iedge].inext; if (edges[iedge].inext == iedge1) return false; inode = edges[iedge].i2; if (inode == k[0]) continue; if (inode == k[1]) continue; if (inode == k[2]) continue; x[1] = nodes[inode].v[ix]; y[1] = nodes[inode].v[iy]; if (a1*x[1]+b1*y[1]+c1 < -0.1*del) continue; if (a2*x[1]+b2*y[1]+c2 < -0.1*del) continue; if (a3*x[1]+b3*y[1]+c3 < -0.1*del) continue; return true; } } inline bool BooleanProcessor::triangulateContour(int ix, int iy, int ihead) /*********************************************************************** * * * Name: BooleanProcessor::triangulateContour Date: 06.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Triangulate external contour * * * ***********************************************************************/ { //int draw_flag = 0; //if (draw_flag) draw_contour(5, 3, ihead); // C L O S E C O N T O U R int ipnext = ihead, nnode = 1; for (;;) { if (edges[ipnext].inext > 0) { ipnext = edges[ipnext].inext; nnode++; }else{ edges[ipnext].inext = ihead; break; } } // L O O P A L O N G C O N T O U R //std::cerr << "debug : contour : begin : =================" << std::endl; //dump();//debug int iedge1, iedge2, iedge3, istart = 0; for (;;) { iedge1 = edges[ipnext].inext; iedge2 = edges[iedge1].inext; //std::cerr << "debug :" // << " ipnext " << ipnext // << " iedge1 " << iedge1 // << " iedge2 " << iedge2 // << " : istart " << istart // << " , nnode " << nnode // << std::endl; if (istart == 0) { istart = iedge1; if (nnode <= 3) { iedge3 = edges[iedge2].inext; edges[iedge1].iface1 = int(faces.size()); edges[iedge2].iface1 = int(faces.size()); edges[iedge3].iface1 = int(faces.size()); edges[iedge3].inext = 0; faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? faces.back().iold = iedge1; faces.back().inew = ORIGINAL_FACE; //if (draw_flag) draw_contour(4, 2, iedge1); break; } }else if (istart == iedge1) { //G.Barrand processor_error = 1; //use returned status. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateContour : " << "could not generate a triangle (infinite loop)" << std::endl; #endif return false; //G.Barrand } // C H E C K C O R E C T N E S S O F T H E T R I A N G L E if(checkTriangle(iedge1,iedge2,ix,iy)) { ipnext = edges[ipnext].inext; continue; } // M O D I F Y C O N T O U R int i1 = edges[iedge1].i1; int i3 = edges[iedge2].i2; int iface1 = edges[iedge1].iface1; int iface2 = int(faces.size()); edges[ipnext].inext = int(edges.size()); edges.push_back(ExtEdge(i1, i3, iface1, -1*(int(edges.size())+1), -1)); edges.back().inext = edges[iedge2].inext; // A D D N E W T R I A N G L E T O T H E L I S T edges[iedge2].inext = int(edges.size()); edges.push_back(ExtEdge(i3, i1, iface2, -1*(int(edges.size())-1), -1)); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? faces.back().iold = iedge1; faces.back().inew = ORIGINAL_FACE; edges[iedge1].iface1 = iface2; edges[iedge2].iface1 = iface2; ipnext = edges[ipnext].inext; istart = 0; nnode--; //if (draw_flag) draw_contour(4, 2, iedge1); } return true; } inline bool BooleanProcessor::modifyReference(int iface, int i1, int i2, int iref) /*********************************************************************** * * * Name: BooleanProcessor::modifyReference Date: 13.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Modify reference to the neighbouring face * * * ***********************************************************************/ { int iedge = faces[iface].iold; while (iedge > 0) { if (edges[iedge].i1 == i2 && edges[iedge].i2 == i1) { edges[iedge].iface2 = iref; return true; } iedge = edges[iedge].inext; } //G.Barrand : processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::modifyReference : could not find the edge, " << "iface=" << iface << ", i1,i2=" << i1 << "," << i2 << ", iref=" << iref << std::endl; #endif return false; //G.Barrand } inline bool BooleanProcessor::triangulateFace(int iface) /*********************************************************************** * * * Name: BooleanProcessor::triangulateFace Date: 02.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Triangulation of an extended face * * * ***********************************************************************/ { // F I N D M A X C O M P O N E N T O F T H E N O R M A L // S E T IX, IY, IZ //HVNormal3D normal = faces[iface].plane.normal(); const HVNormal3D& normal = faces[iface].plane.normal(); int ix, iy, iz = 0; //G.Barrand : if (std::abs(normal[1]) > std::abs(normal[iz])) iz = 1; //G.Barrand : if (std::abs(normal[2]) > std::abs(normal[iz])) iz = 2; if (::fabs(normal[1]) > ::fabs(normal[iz])) iz = 1; //G.Barrand if (::fabs(normal[2]) > ::fabs(normal[iz])) iz = 2; //G.Barrand if (normal[iz] > 0) { ix = (iz+1)%3; iy = (ix+1)%3; }else{ iy = (iz+1)%3; ix = (iy+1)%3; } // F I L L L I S T S O F C O N T O U R S external_contours.clear(); internal_contours.clear(); double z; int i1, i2, ifirst, iedge, icontour = faces[iface].iold; while (icontour > 0) { iedge = icontour; ifirst = edges[iedge].i1; z = 0.0; for(;;) { if (iedge > 0) { i1 = edges[iedge].i1; i2 = edges[iedge].i2; ExtNode& node_1 = nodes[i1]; ExtNode& node_2 = nodes[i2]; z += node_1.v[ix]*node_2.v[iy]-node_2.v[ix]*node_1.v[iy]; if (ifirst != i2) { iedge = edges[iedge].inext; continue; }else{ if (z > del*del) { external_contours.push_back(icontour); }else if (z < -del*del) { internal_contours.push_back(icontour); }else{ //G.Barrand : processor_error = 1; //use returned value. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateFace : too small contour" << " z " << z << " del*del " << del*del << std::endl; #endif return false; //G.Barrand. } icontour = edges[iedge].inext; edges[iedge].inext = 0; break; } }else{ //G.Barrand : processor_error = 1; //use returned value. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateFace : broken contour" << std::endl; #endif icontour = 0; //G.Barrand : break; return false; } } } // G E T R I D O F I N T E R N A L C O N T O U R S int kint, kext; for (kint=0; kint < (int)internal_contours.size(); kint++) { for (kext=0; kext < (int)external_contours.size(); kext++) { mergeContours(ix, iy, kext, kint); if (internal_contours[kint] == 0) break; } if (kext == (int)external_contours.size()) { //G.Barrand : processor_error = 1; //use returned value. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateFace : " << "could not merge internal contour " << kint << std::endl; #endif return false; //G.Barrand } } // T R I A N G U L A T E C O N T O U R S int nface = int(faces.size()); for (kext=0; kext < (int)external_contours.size(); kext++) { if(!triangulateContour(ix, iy, external_contours[kext])) { //G.Barrand : processor_error = 1; //use returned value. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateFace : " << "triangulateContour failed." << std::endl; #endif //break; //G.Barrand : ok ? //return; //G.Barrand : ok ? return false; //G.Barrand } } faces[iface].inew = UNSUITABLE_FACE; // M O D I F Y R E F E R E N C E S for (int ifa=nface; ifa<(int)faces.size(); ifa++) { iedge = faces[ifa].iold; while (iedge > 0) { if (edges[iedge].iface1 != ifa) { //G.Barrand : processor_error = 1; //use returned value. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::triangulateFace : wrong reference to itself, " << "iface=" << ifa << ", iface1=" << edges[iedge].iface1 << std::endl; #endif return false; //G.Barrand }else if (edges[iedge].iface2 > 0) { if(!modifyReference(edges[iedge].iface2, edges[iedge].i1, edges[iedge].i2, ifa)) { //G.Barrand return false; //G.Barrand } }else if (edges[iedge].iface2 < 0) { edges[iedge].iface2 = edges[-edges[iedge].iface2].iface1; } iedge = edges[iedge].inext; } } return true; //G.Barrand. } inline polyhedron BooleanProcessor::createPolyhedron() /*********************************************************************** * * * Name: BooleanProcessor::createPolyhedron() Date: 14.03.00 * * Author: E.Chernyaev Revised: * * * * Function: Create polyhedron. * * * ***********************************************************************/ { int i, iedge, nnode = 0, nface = 0; // R E N U M E R A T E N O D E S A N D F A C E S for (i=1; i<(int)nodes.size(); i++) nodes[i].s = 0; for (i=1; i<(int)faces.size(); i++) { if (faces[i].inew == ORIGINAL_FACE) { faces[i].inew = ++nface; iedge = faces[i].iold; while (iedge > 0) { nodes[edges[iedge].i1].s = 1; iedge = edges[iedge].inext; } }else{ faces[i].inew = 0; } } for (i=1; i<(int)nodes.size(); i++) { if (nodes[i].s == 1) nodes[i].s = ++nnode; } // A L L O C A T E M E M O R Y ExtPolyhedron polyhedron; if (nface == 0) return polyhedron; polyhedron.AllocateMemory(nnode, nface); // S E T N O D E S for (i=1; i<(int)nodes.size(); i++) { if (nodes[i].s != 0) polyhedron.pV[nodes[i].s] = nodes[i].v; } // S E T F A C E S int k, v[4], f[4]; for (i=1; i<(int)faces.size(); i++) { if (faces[i].inew == 0) continue; v[3] = f[3] = k = 0; iedge = faces[i].iold; while (iedge > 0) { if (k > 3) { #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor::createPolyhedron : too many edges" << std::endl; #endif break; } v[k] = nodes[edges[iedge].i1].s; if (edges[iedge].ivis < 0) v[k] = -v[k]; f[k] = faces[edges[iedge].iface2].inew; iedge = edges[iedge].inext; k++; } if (k < 3) { #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor::createPolyhedron : " << "face has only " << k << " edges" << std::endl; #endif } //polyhedron.pF[faces[i].inew] = // SbFacet(v[0],f[0], v[1],f[1], v[2],f[2], v[3],f[3]); polyhedron.pF[faces[i].inew].set( //G.Barrand v[0],f[0], v[1],f[1], v[2],f[2], v[3],f[3]); } return polyhedron; } //G.Barrand : begin //int BooleanProcessor::ishift = 0; //does not work with pure header code. inline int& BooleanProcessor::get_shift() { //& not thread safe. static int s_ishift; return s_ishift; } inline void BooleanProcessor::set_shift(int a_shift) { get_shift() = a_shift; } inline void BooleanProcessor::inc_shift() { int i = get_shift(); i++; if(i>=get_num_shift()) i = 0; get_shift() = i; } inline int BooleanProcessor::get_num_shift() { return 8;} //G.Barrand : end //G.Barrand : inline bool BooleanProcessor::inc_try_count( #ifdef TOOLS_HEP_BP_VERBOSE int a_op,const polyhedron& a,const polyhedron& b #else int,const polyhedron&,const polyhedron& #endif ,int& a_try_count){ if(a_try_count>get_num_shift()) { #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor: " << " all shifts tried. Boolean operation (" << a_op << ") failure." << " a name \"" << a.getName() << "\"" << " b name \"" << b.getName() << "\"" << std::endl; #endif return false; //stop } #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor::execute : try another tilt..." << std::endl; #endif a_try_count++; return true; } inline polyhedron BooleanProcessor::execute(int op, const polyhedron & a, const polyhedron & b, int& a_err) //G.Barrand /*********************************************************************** * * * Name: BooleanProcessor::execute Date: 10.12.99 * * Author: E.Chernyaev Revised: * * * * Function: Execute boolean operation. * * * ***********************************************************************/ { //static int ishift = 0; //G.Barrand //static double shift[8][3] = { static double shift[/*NUM_SHIFT*/ 8][3] = { //G.Barrand { 31, 23, 17}, { -31, -23, -17}, { -23, 17, 31}, { 23, -17, -31}, { -17, -31, 23}, { 17, 31, -23}, { 31, -23, 17}, { -31, 23, -17} }; //std::cerr << "BooleanProcessor::execute : ++++++++++++++++++++++" // << a.getName() // << b.getName() // << std::endl; // I N I T I A T E P R O C E S S O R operation = op; nodes.clear(); nodes.push_back(CRAZY_POINT()); edges.clear(); edges.push_back(ExtEdge()); faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? // T A K E P O L Y H E D R A ifaces1 = int(faces.size()); if(!takePolyhedron(a,0,0,0)){ //G.Barrand : use returned value. // corrapted polyhedron #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: a corrapted input polyhedron" << std::endl; #endif a_err = 1; //G.Barrand return polyhedron(); } ifaces2 = int(faces.size()); if(!takePolyhedron(b,0,0,0)){ // corrapted polyhedron #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: b corrapted input polyhedron" << std::endl; #endif a_err = 1; //G.Barrand return polyhedron(); } if (ifaces1 == ifaces2) { // a is empty a_err = 0; //G.Barrand switch (operation) { case OP_UNION: return b; case OP_INTERSECTION: #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor: intersection with empty polyhedron" << std::endl; #endif return polyhedron(); case OP_SUBTRACTION: #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor: subtraction from empty polyhedron" << std::endl; #endif return polyhedron(); } } if (ifaces2 == (int)faces.size()) { // b is empty a_err = 0; //G.Barrand switch (operation) { case OP_UNION: return a; case OP_INTERSECTION: #ifdef TOOLS_HEP_BP_VERBOSE std::cerr << "BooleanProcessor: intersection with empty polyhedron" << std::endl; #endif return polyhedron(); case OP_SUBTRACTION: return a; } } // S E T I N I T I A L M I N - M A X A N D T O L E R A N C E del = findMinMax(); // W O R K A R O U N D T O A V O I D I E A N D E E int try_count = 1; while(true) { //G.Barrand double ddxx = del*shift[get_shift()][0]; double ddyy = del*shift[get_shift()][1]; double ddzz = del*shift[get_shift()][2]; //ishift++; if (ishift == get_num_shift()) ishift = 0; inc_shift(); operation = op; nodes.clear(); nodes.push_back(CRAZY_POINT()); edges.clear(); edges.push_back(ExtEdge()); faces.clear(); faces.push_back(ExtFace(edges,0)); //G.Barrand : ok ? ifaces1 = int(faces.size()); if(!takePolyhedron(a,0,0,0)) { #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: shifted a corrapted input polyhedron" << std::endl; #endif if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. } ifaces2 = int(faces.size()); if(!takePolyhedron(b,ddxx,ddyy,ddzz)){ #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: shifted b corrapted input polyhedron" << std::endl; #endif if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. } del = findMinMax(); // P R E S E L E C T O U T S I D E F A C E S iout1 = iout2 = 0; selectOutsideFaces(ifaces1, iout1); selectOutsideFaces(ifaces2, iout2); // P R E S E L E C T N O I N T E R S E C T I O N F A C E S int ifa1, ifa2; iunk1 = iunk2 = 0; if (iout1 != 0 || iout2 != 0) { for(;;) { ifa1 = iunk1; ifa2 = iunk2; selectOutsideFaces(ifaces1, iunk1); selectOutsideFaces(ifaces2, iunk2); if (iunk1 == ifa1 && iunk2 == ifa2) break; findMinMax(); } } // F I N D N E W E D G E S {int processor_error = 0; //G.Barrand if (ifaces1 != 0 && ifaces2 != 0 ) { ifa1 = ifaces1; while (ifa1 > 0) { ifa2 = ifaces2; while (ifa2 > 0) { if(!testFaceVsFace(ifa1, ifa2)) { processor_error = 1; //G.Barrand break; //G.Barrand } ifa2 = faces[ifa2].inext; } if(processor_error) break; //G.Barrand ifa1 = faces[ifa1].inext; } } if (processor_error) { PROCESSOR_ERROR(4); if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. }} //G.Barrand // C O N S T R U C T N E W F A C E S if(!assembleNewFaces((operation == OP_INTERSECTION) ? 1 : 0, ifaces1)){ //G.Barrand PROCESSOR_ERROR(5); if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. } if(!assembleNewFaces((operation == OP_UNION) ? 0 : 1, ifaces2)){ //G.Barrand PROCESSOR_ERROR(6); if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. } // A S S E M B L E S U I T A B L E F A C E S if(!initiateLists()) { //G.Barrand : return status. #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: initiateLists failed." << std::endl; #endif if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. } {int processor_error = 0; for (;;) { if(!assemblePolyhedra()) { //G.Barrand : handle returned value. processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor: assemblePolyhedra failed." << std::endl; #endif break; } if (unknown_faces.front() != 0) { processor_error = 1; #ifdef TOOLS_HEP_BP_OUT_ERR std::cerr << "BooleanProcessor::execute : unknown faces !!!" << std::endl; #endif break; } break; } if (processor_error) { PROCESSOR_ERROR(7); if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. }} // T R I A N G U L A T E A C C E P T E D F A C E S {int processor_error = 0; ifa1 = result_faces.front(); while (ifa1 > 0) { ifa2 = ifa1; ifa1 = faces[ifa2].inext; if(faces[ifa2].inew == NEW_FACE) { if(!triangulateFace(ifa2)) { //G.Barrand : use returned status. processor_error = 1; break; //G.Barrand } } } if (processor_error) { PROCESSOR_ERROR(8); if(!inc_try_count(op,a,b,try_count)) {a_err = 1;return a;} continue; //try another shift. }} #ifdef TOOLS_HEP_BP_VERBOSE if(try_count!=1) { std::cerr << "BooleanProcessor::execute : had converged." << std::endl; } #endif break; } //G.Barrand : end while shift. // C R E A T E P O L Y H E D R O N a_err = 0; return createPolyhedron(); } //#include //#include //#include "zbuf.h" //void BooleanProcessor::draw() /*********************************************************************** * * * Name: BooleanProcessor::draw Date: 10.12.99 * * Author: E.Chernyaev Revised: * * * * Function: Draw * * * ***********************************************************************/ /* { int II; int icol, i1, i2, iedge, iface, ilist[4]; float p1[3], p2[3]; ilist[0] = ifaces1; ilist[1] = ifaces2; ilist[2] = iout1; ilist[3] = iout2; for (int i=0; i<4; i++) { if (i == 0) cout << "========= Ifaces_1" << endl; if (i == 1) cout << "========= Ifaces_2" << endl; if (i == 2) cout << "========= Iout_1" << endl; if (i == 3) cout << "========= Iout_2" << endl; icol = i+1; iface = ilist[i]; while (iface > 0) { cout << "iface = " << iface << endl; cout << "--- iold" << endl; iedge = faces[iface].iold; icol = 2; while (iedge > 0) { cout << " iegde = " << iedge << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2 << " iface1,iface2 = " << edges[iedge].iface1 << "," << edges[iedge].iface2 << endl; i1 = edges[iedge].i1; p1[0] = nodes[i1].v.x(); p1[1] = nodes[i1].v.y(); p1[2] = nodes[i1].v.z(); IHWTON(p1,p1); i2 = edges[iedge].i2; p2[0] = nodes[i2].v.x(); p2[1] = nodes[i2].v.y(); p2[2] = nodes[i2].v.z(); IHWTON(p2,p2); // icol = (edges[iedge].ivis > 0) ? 1 : 2; IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); iedge = edges[iedge].inext; } cout << "--- inew" << endl; iedge = faces[iface].inew; icol = 3; while (iedge > 0) { cout << " iegde = " << iedge << " i1,i2 =" << edges[iedge].i1 << "," << edges[iedge].i2 << " iface1,iface2 = " << edges[iedge].iface1 << "," << edges[iedge].iface2 << endl; i1 = edges[iedge].i1; p1[0] = nodes[i1].v.x(); p1[1] = nodes[i1].v.y(); p1[2] = nodes[i1].v.z(); IHWTON(p1,p1); i2 = edges[iedge].i2; p2[0] = nodes[i2].v.x(); p2[1] = nodes[i2].v.y(); p2[2] = nodes[i2].v.z(); IHWTON(p2,p2); // icol = (edges[iedge].ivis > 0) ? 1 : 2; IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); iedge = edges[iedge].inext; } iface = faces[iface].inext; IHZTOX(0,100,100); ixupdwi(0); cin >> II; ixclrwi(); IHZCLE(0); } } } */ /* //-------------------------------------------------------------------- inline void BooleanProcessor::draw_edge(int icol, int iedge) { int i1, i2; float p1[3], p2[3]; i1 = edges[iedge].i1; p1[0] = nodes[i1].v.x(); p1[1] = nodes[i1].v.y(); p1[2] = nodes[i1].v.z(); IHWTON(p1,p1); i2 = edges[iedge].i2; p2[0] = nodes[i2].v.x(); p2[1] = nodes[i2].v.y(); p2[2] = nodes[i2].v.z(); IHWTON(p2,p2); IHZLIN(icol,p1[0],p1[1],p1[2], p2[0],p2[1],p2[2]); } //-------------------------------------------------------------------- inline void BooleanProcessor::draw_contour(int i1col, int i2col, int ihead) { int iedge, icol; iedge = ihead; while (iedge > 0) { icol = (edges[iedge].ivis > 0) ? i1col : i2col; draw_edge(icol, iedge); iedge = edges[iedge].inext; } IHZTOX(0,100,100); ixupdwi(0); int i; std::cin >> i; } //-------------------------------------------------------------------- inline void BooleanProcessor::print_face(int iface) { cout.precision(3); cout << "\n====== Face N " << iface << endl; cout << "iedges[4] = " << faces[iface].iedges[0] << ", " << faces[iface].iedges[1] << ", " << faces[iface].iedges[2] << ", " << faces[iface].iedges[3] << endl; cout << "rmin[3] = " << faces[iface].rmin[0] << ", " << faces[iface].rmin[1] << ", " << faces[iface].rmin[2] << endl; cout << "rmax[3] = " << faces[iface].rmax[0] << ", " << faces[iface].rmax[1] << ", " << faces[iface].rmax[2] << endl; cout << "iprev,inext = " << faces[iface].iprev << ", " << faces[iface].inext << endl; cout << "iold = " << faces[iface].iold << endl; for(int i = faces[iface].iold; i != 0;) { print_edge(i); i = edges[abs(i)].inext; } cout << "inew = "; switch (faces[iface].inew) { case UNKNOWN_FACE: cout << "UNKNOWN_FACE" << endl; break; case ORIGINAL_FACE: cout << "ORIGINAL_FACE" << endl; break; case NEW_FACE: cout << "NEW_FACE" << endl; break; case UNSUITABLE_FACE: cout << "UNSUITABLE_FACE" << endl; break; case DEFECTIVE_FACE: cout << "DEFECTIVE_FACE" << endl; break; default: cout << faces[iface].inew << endl; for(int k = faces[iface].inew; k != 0;) { print_edge(k); k = edges[abs(k)].inext; } } } //-------------------------------------------------------------------- inline void BooleanProcessor::print_edge(int iedge) { cout << "==== Edge N " << iedge << endl; int i = std::abs(iedge); int i1 = edges[i].i1; int i2 = edges[i].i2; cout << "node[" << i1 << "] = " << nodes[i1].v.x() << ", " << nodes[i1].v.y() << ", " << nodes[i1].v.z() << endl; cout << "node[" << i2 << "] = " << nodes[i2].v.x() << ", " << nodes[i2].v.y() << ", " << nodes[i2].v.z() << endl; cout << "iface1,iface2,ivis,inext = " << edges[i].iface1 << ", " << edges[i].iface2 << ", " << edges[i].ivis << ", " << edges[i].inext << endl; } */ inline void BooleanProcessor::dump(std::ostream& a_out) {//G.Barrand size_t number = nodes.size(); a_out << "nodes : " << number << std::endl; for(size_t index=0;index