/** * Returns a new quad (convex) from the merge of two triangles that share the * vertex index v. * @param faceI mesh triangle * @param faceJ mesh triangle * @param v vertex index shared by both triangles * @return a new convex quad if the merge is possible */ BOP_Face* BOP_Merge::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) { BOP_Face *faceK = NULL; // Get faces data BOP_Index prevI, nextI, prevJ, nextJ; faceI->getNeighbours(v,prevI,nextI); faceJ->getNeighbours(v,prevJ,nextJ); MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); // Quad test if (prevI == nextJ) { if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) && BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) { faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } } else if (nextI == prevJ) { if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) && BOP_convex(vertex,vNextJ,vNextI,vPrevI)) { faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } } return faceK; }
/** * Returns a new triangle from the merge of two triangles that share the vertex * v and come from the same original face. * @param faceI mesh triangle * @param faceJ mesh triangle * @param v vertex index shared by both triangles * @return If the merge is possible, a new triangle without v */ BOP_Face* BOP_Merge::mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) { BOP_Face *faceK = NULL; // Get faces data BOP_Index prevI, nextI, prevJ, nextJ; faceI->getNeighbours(v,prevI,nextI); faceJ->getNeighbours(v,prevJ,nextJ); MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); // Merge test if (prevI == nextJ) { // Both faces share the edge (prevI,v) == (v,nextJ) if (BOP_between(vertex,vNextI,vPrevJ)) { faceK = new BOP_Face3(prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } } else if (nextI == prevJ) { // Both faces share the edge (v,nextI) == (prevJ,v) if (BOP_between(vertex,vPrevI,vNextJ)) { faceK = new BOP_Face3(prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } } return faceK; }
/** * Returns a new quad (convex) from the merge of two triangles that share the * vertex index v. * @param faceI mesh triangle * @param faceJ mesh triangle * @param v vertex index shared by both triangles * @return a new convex quad if the merge is possible */ BOP_Face* BOP_Merge2::createQuad(BOP_Face4 *faceI, BOP_Face4 *faceJ) { BOP_Face *faceK = NULL; // // Test if both quads share a vertex index // BOP_Index v; unsigned int i; for(i=0;i<4 ;i++) { v = faceI->getVertex(i); if( faceJ->containsVertex(v) ) break; } if (i == 3) return NULL; // Get faces data BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ; faceI->getNeighbours(v,prevI,nextI,oppI); faceJ->getNeighbours(v,prevJ,nextJ,oppJ); // Quad test BOP_Index edge; if (nextI == prevJ) { if (prevI == nextJ) { // v is in center faceK = new BOP_Face4(nextI,oppI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); m_mesh->getIndexEdge(v,prevI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(prevI)->removeEdge(edge); m_mesh->getIndexEdge(v,nextI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(nextI)->removeEdge(edge); freeVerts(v, m_mesh->getVertex(v)); } else if (oppI == oppJ) { // nextI is in center faceK = new BOP_Face4(v,nextJ,oppJ,prevI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); m_mesh->getIndexEdge(v,nextI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(nextI)->removeEdge(edge); m_mesh->getIndexEdge(prevI,nextI,edge); m_mesh->getVertex(prevI)->removeEdge(edge); m_mesh->getVertex(nextI)->removeEdge(edge); freeVerts(nextI, m_mesh->getVertex(nextI)); } } else if (prevI == nextJ && oppI == oppJ) { // prevI is in center faceK = new BOP_Face4(v,nextI,oppJ,prevJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); m_mesh->getIndexEdge(v,prevI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(prevI)->removeEdge(edge); m_mesh->getIndexEdge(nextI,prevI,edge); m_mesh->getVertex(nextI)->removeEdge(edge); m_mesh->getVertex(prevI)->removeEdge(edge); freeVerts(prevI, m_mesh->getVertex(prevI)); } return faceK; }
/** * Creates a list of lists L1, L2, ... LN where * LX = mesh faces with vertex v that come from the same original face * and without any of the vertices that appear before v in vertices * @param facesByOriginalFace list of faces lists * @param vertices vector with vertices indexs that contains v * @param v vertex index */ void BOP_Merge2::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v) { // Get edges with vertex v BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges(); const BOP_IT_Indexs edgeEnd = edgeIndexs.end(); for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) { // Foreach edge, add its no broken faces to the output list BOP_Edge* edge = m_mesh->getEdge(*edgeIndex); BOP_Indexs faceIndexs = edge->getFaces(); const BOP_IT_Indexs faceEnd = faceIndexs.end(); for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) { BOP_Face* face = m_mesh->getFace(*faceIndex); if (face->getTAG() != BROKEN) { // Search if the face contains any of the forbidden vertices bool found = false; for(BOP_IT_Indexs vertex = vertices.begin();*vertex!= v;vertex++) { if (face->containsVertex(*vertex)) { // face contains a forbidden vertex! found = true; break; } } if (!found) { // Search if we already have created a list with the // faces that come from the same original face const BOP_IT_LFaces lfEnd = facesByOriginalFace.end(); for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin(); facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) { if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) { // Search that the face has not been added to the list before for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) { if ((*facesByOriginalFaceX)[i] == face) { found = true; break; } } if (!found) { // Add face to the list if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face); else facesByOriginalFaceX->push_back(face); found = true; } break; } } if (!found) { // Create a new list and add the current face BOP_Faces facesByOriginalFaceX; facesByOriginalFaceX.push_back(face); facesByOriginalFace.push_back(facesByOriginalFaceX); } } } } } }
/** * Computes intesections of coplanars faces from object A with faces from object B. * @param mesh mesh that contains the faces, edges and vertices * @param facesA set of faces from object A * @param facesB set of faces from object B */ void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) { for(unsigned int idxFaceB = 0; idxFaceB < facesB->size(); idxFaceB++) { BOP_Face *faceB = (*facesB)[idxFaceB]; MT_Plane3 planeB = faceB->getPlane(); MT_Point3 p1 = mesh->getVertex(faceB->getVertex(0))->getPoint(); MT_Point3 p2 = mesh->getVertex(faceB->getVertex(1))->getPoint(); MT_Point3 p3 = mesh->getVertex(faceB->getVertex(2))->getPoint(); for(unsigned int idxFaceA = 0; idxFaceA < facesA->size() && faceB->getTAG() != BROKEN && faceB->getTAG() != PHANTOM; idxFaceA++) { BOP_Face *faceA = (*facesA)[idxFaceA]; if ((faceA->getTAG() != BROKEN)&&(faceA->getTAG() != PHANTOM)) { MT_Plane3 planeA = faceA->getPlane(); if (BOP_containsPoint(planeA,p1) && BOP_containsPoint(planeA,p2) && BOP_containsPoint(planeA,p3)) { if (BOP_orientation(planeA,planeB) > 0) { BOP_intersectCoplanarFaces(mesh,facesA,faceB,faceA,true); } } } } } }
/** * testMesh */ void BOP_Mesh::testMesh() { BOP_Face* cares[10]; unsigned int nedges=0,i; for(i=0;i<m_edges.size();i++) { BOP_Edge *edge = m_edges[i]; BOP_Indexs faces = edge->getFaces(); unsigned int count = 0; const BOP_IT_Indexs facesEnd = faces.end(); for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { if (m_faces[*it]->getTAG()!=BROKEN) { cares[count] = m_faces[*it]; count++; } } if ((count%2)!=0) nedges++; } if (nedges) cout << nedges << " wrong edges." << endl; else cout << "well edges." << endl; unsigned int duplFaces = 0; unsigned int wrongFaces = 0; for(i=0;i<m_faces.size();i++){ BOP_Face *faceI = m_faces[i]; if (faceI->getTAG()==BROKEN) continue; if (testFace(faceI)){ wrongFaces++; cout << "Wrong Face: " << faceI << endl; } for(unsigned int j=i+1;j<m_faces.size();j++){ BOP_Face *faceJ = m_faces[j]; if (faceJ->getTAG()==BROKEN) continue; if (testFaces(faceI,faceJ)){ duplFaces++; cout << "Duplicate FaceI: " << faceI << endl; cout << "Duplicate FaceJ: " << faceJ << endl; } } } cout << duplFaces << " duplicate faces." << endl; cout << wrongFaces << " wrong faces." << endl; }
/** * updatePlanes */ void BOP_Mesh::updatePlanes() { const BOP_IT_Faces facesEnd = m_faces.end(); for(BOP_IT_Faces it = m_faces.begin();it!=facesEnd;it++) { BOP_Face *face = *it; MT_Plane3 plane(m_vertexs[face->getVertex(0)]->getPoint(), m_vertexs[face->getVertex(1)]->getPoint(), m_vertexs[face->getVertex(2)]->getPoint()); face->setPlane(plane); } }
/** * Returns a new face (quad or triangle) from the merge of one quad and one * triangle that share the vertex v and come from the same original face. * @param faceI mesh quad * @param faceJ mesh triangle * @param pending vector with pending vertices (required to merge one quad * and one triangle into a new triangle; it supposes to remove two vertexs, * v and its neighbour, that will be a new pending vertex if it wasn't) * @param v vertex index shared by both faces * @return If the merge is possible, a new face without v */ BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v) { BOP_Face *faceK = NULL; // Get faces data BOP_Index prevI, nextI, opp, prevJ, nextJ; faceI->getNeighbours(v,prevI,nextI,opp); faceJ->getNeighbours(v,prevJ,nextJ); MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint(); MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); // Merge test if (prevI == nextJ) { if (BOP_between(vertex,vNextI,vPrevJ)) { if (!BOP_collinear(vPrevJ,vPrevI,vOpp) && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) { // The result is a new quad faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } else if (BOP_between(vPrevI,vPrevJ,vOpp)) { // The result is a triangle (only if prevI can be merged) if (prevI < m_firstVertex) return NULL; // It can't be merged faceK = new BOP_Face3(nextI,opp,prevJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); if (!containsIndex(pending, prevI)) pending.push_back(prevI); } } } else if (nextI == prevJ) { if (BOP_between(vertex,vPrevI,vNextJ)) { if (!BOP_collinear(vNextJ,vNextI,vOpp) && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) { // The result is a new quad faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); } else if (BOP_between(vNextI,vOpp,vNextJ)) { // The result is a triangle (only if nextI can be merged) if (nextI < m_firstVertex) return NULL; faceK = new BOP_Face3(prevI,nextJ,opp,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); if (!containsIndex(pending, nextI)) pending.push_back(nextI); } } } return faceK; }
/** * Returns a new quad (convex) from the merge of two triangles that share the * vertex index v. * @param faceI mesh triangle * @param faceJ mesh triangle * @param v vertex index shared by both triangles * @return a new convex quad if the merge is possible */ BOP_Face* BOP_Merge2::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ) { // Test if both triangles share a vertex index BOP_Index v; unsigned int i; for(i=0;i<3 ;i++) { v = faceI->getVertex(i); if( faceJ->containsVertex(v) ) break; } if (i == 3) return NULL; BOP_Face *faceK = NULL; // Get faces data BOP_Index prevI, nextI, prevJ, nextJ; faceI->getNeighbours(v,prevI,nextI); faceJ->getNeighbours(v,prevJ,nextJ); MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); // Quad test if (prevI == nextJ) { if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) && BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) { faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); BOP_Index edge; m_mesh->getIndexEdge(v,prevI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(prevI)->removeEdge(edge); } } else if (nextI == prevJ) { if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) && BOP_convex(vertex,vNextJ,vNextI,vPrevI)) { faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); BOP_Index edge; m_mesh->getIndexEdge(v,nextI,edge); m_mesh->getVertex(v)->removeEdge(edge); m_mesh->getVertex(nextI)->removeEdge(edge); } } return faceK; }
/** * Pre-process to filter no collisioned faces. * @param meshC Input & Output mesh data * @param faces Faces list to test * @param bsp BSP tree used to filter * @param inverted determines if the object is inverted */ void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted) { BOP_IT_Faces it; it = faces->begin(); while (it!=faces->end()) { BOP_Face *face = *it; MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); if (bsp->filterFace(p1,p2,p3,face)==OUT) { if (!inverted) face->setTAG(BROKEN); it = faces->erase(it); } else { it++; } } }
/** * Returns the first face of faces that shares the input edge of face. * @param mesh mesh that contains the faces, edges and vertices * @param faces set of faces * @param face input face * @param edge face's edge * @return first face that shares the edge of input face */ BOP_Face *BOP_getOppositeFace(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Edge* edge) { if (edge == NULL) return NULL; BOP_Indexs auxfaces = edge->getFaces(); const BOP_IT_Indexs auxfacesEnd = auxfaces.end(); for(BOP_IT_Indexs it = auxfaces.begin(); it != auxfacesEnd; it++) { BOP_Face *auxface = mesh->getFace(*it); if ((auxface != face) && (auxface->getTAG()!=BROKEN) && BOP_containsFace(faces,auxface)) { return auxface; } } return NULL; }
/** * Preprocess to filter no collisioned faces. * @param meshC Input & Output mesh data * @param faces Faces list to test * @param bsp BSP tree used to filter */ void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp) { BOP_IT_Faces it; BOP_TAG tag; it = faces->begin(); while (it!=faces->end()) { BOP_Face *face = *it; MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); if ((tag = bsp->classifyFace(p1,p2,p3,face->getPlane()))==OUT||tag==OUTON) { face->setTAG(BROKEN); it = faces->erase(it); } else if (tag == IN) { it = faces->erase(it); }else{ it++; } } }
/** * Returns a new quad from the merge of two quads that share * the vertex v and come from the same original face. * @param faceI mesh quad * @param faceJ mesh quad * @param pending vector with pending vertices (required to merge the two * quads supposes to remove two vertexs, v and its neighbour, * that will be a new pending vertex if it wasn't) * @param v vertex index shared by both quads * @return If the merge is possible, a new quad without v */ BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v) { BOP_Face *faceK = NULL; // Get faces data BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ; faceI->getNeighbours(v,prevI,nextI,oppI); faceJ->getNeighbours(v,prevJ,nextJ,oppJ); MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); MT_Point3 vOppI = m_mesh->getVertex(oppI)->getPoint(); MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); MT_Point3 vOppJ = m_mesh->getVertex(oppJ)->getPoint(); // Merge test if (prevI == nextJ) { // prevI/nextJ will be a new vertex required to merge if (prevI < m_firstVertex) return NULL; // It can't be merged if (BOP_between(vertex,vPrevJ,vNextI) && BOP_between(vNextJ,vOppJ,vOppI)) { faceK = new BOP_Face4(oppJ,prevJ,nextI,oppI,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); // We add prevI to the pending list if it wasn't yet if (!containsIndex(pending, prevI)) pending.push_back(prevI); } } else if (nextI == prevJ) { // nextI/prevJ will be a new vertex required to merge if (nextI < m_firstVertex) return NULL; // It can't be merged if (BOP_between(vertex,vPrevI,vNextJ) && BOP_between(vNextI,vOppI,vOppJ)) { faceK = new BOP_Face4(oppI,prevI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace()); faceK->setTAG(faceI->getTAG()); // Add nextI to the pending list if it wasn't yet if (!containsIndex(pending, nextI)) pending.push_back(nextI); } } return faceK; }
void BOP_Merge2::cleanup( void ) { BOP_Edges edges = m_mesh->getEdges(); for (BOP_IT_Edges edge = edges.begin(); edge != edges.end(); ++edge) { BOP_Indexs faces = (*edge)->getFaces(); for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); ++face) { BOP_Face *f = m_mesh->getFace(*face); if(f->getTAG()== UNCLASSIFIED) ; else (*edge)->removeFace(*face); } if( (*edge)->getFaces().size() == 0) (*edge)->setUsed(false); } BOP_Vertexs v = m_mesh->getVertexs(); for( BOP_IT_Vertexs it = v.begin(); it != v.end(); ++it ) { if( (*it)->getTAG() != BROKEN) { BOP_Indexs iedges = (*it)->getEdges(); for(BOP_IT_Indexs i = iedges.begin();i!=iedges.end();i++) if( m_mesh->getEdge((*i))->getUsed( ) == false) (*it)->removeEdge( *i ); if( (*it)->getEdges().size() == 0 ) (*it)->setTAG(BROKEN); } } // clean_nonmanifold( m_mesh ); }
/** * Adds the new face into the faces set and the mesh and sets it a new tag. * @param mesh mesh that contains the faces, edges and vertices * @param faces set of faces that contains oldFace * @param face input face to be added * @param tag tag of the new face */ void BOP_addFace(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_TAG tag) { BOP_Index av1 = face->getVertex(0); BOP_Index av2 = face->getVertex(1); BOP_Index av3 = face->getVertex(2); /* * Before adding a new face to the face list, be sure it's not * already there. Duplicate faces have been found to cause at * least two instances of infinite loops. Also, some faces are * created which have the same vertex twice. Don't add these either. * * When someone has more time to look into this issue, it's possible * this code may be removed again. */ if( av1==av2 || av2==av3 || av3==av1 ) return; for(unsigned int idxFace=0;idxFace<faces->size();idxFace++) { BOP_Face *faceA = (*faces)[idxFace]; BOP_Index bv1 = faceA->getVertex(0); BOP_Index bv2 = faceA->getVertex(1); BOP_Index bv3 = faceA->getVertex(2); if( ( av1==bv1 && av2==bv2 && av3==bv3 ) || ( av1==bv1 && av2==bv3 && av3==bv2 ) || ( av1==bv2 && av2==bv1 && av3==bv3 ) || ( av1==bv2 && av2==bv3 && av3==bv1 ) || ( av1==bv3 && av2==bv2 && av3==bv1 ) || ( av1==bv3 && av2==bv1 && av3==bv3 ) ) return; } face->setTAG(tag); faces->push_back(face); mesh->addFace(face); }
/** * Tests if faces since firstFace have all vertexs non-coincident of colinear, otherwise repairs the mesh. * @param mesh mesh that contains the faces, edges and vertices * @param firstFace first face index to be tested */ void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace) { unsigned int numFaces = mesh->getNumFaces(); for(unsigned int idxFace = firstFace; idxFace < numFaces; idxFace++) { BOP_Face *face = mesh->getFace(idxFace); if ((face->getTAG() != BROKEN) && (face->getTAG() != PHANTOM)) { MT_Point3 vertex1 = mesh->getVertex(face->getVertex(0))->getPoint(); MT_Point3 vertex2 = mesh->getVertex(face->getVertex(1))->getPoint(); MT_Point3 vertex3 = mesh->getVertex(face->getVertex(2))->getPoint(); if (BOP_collinear(vertex1,vertex2,vertex3)) // collinear triangle face->setTAG(PHANTOM); } } }
void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) { for(unsigned int idxFaceA=0;idxFaceA<facesA->size();idxFaceA++) { BOP_Face *faceA = (*facesA)[idxFaceA]; MT_Plane3 planeA = faceA->getPlane(); MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); /* get (or create) bounding box for face A */ if( faceA->getBBox() == NULL ) faceA->setBBox(p1,p2,p3); BOP_BBox *boxA = faceA->getBBox(); /* start checking B faces with the previously stored split index */ for(unsigned int idxFaceB=faceA->getSplit(); idxFaceB<facesB->size() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) { BOP_Face *faceB = (*facesB)[idxFaceB]; faceA->setSplit(idxFaceB); if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) { /* get (or create) bounding box for face B */ if( faceB->getBBox() == NULL ) faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(), mesh->getVertex(faceB->getVertex(1))->getPoint(), mesh->getVertex(faceB->getVertex(2))->getPoint()); BOP_BBox *boxB = faceB->getBBox(); if (boxA->intersect(*boxB)) { MT_Plane3 planeB = faceB->getPlane(); if (BOP_containsPoint(planeB,p1) && BOP_containsPoint(planeB,p2) && BOP_containsPoint(planeB,p3)) { if (BOP_orientation(planeB,planeA)>0) { BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false); } } else { BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB); } } } idxFaceB++; } } // Clean broken faces from facesA BOP_IT_Faces it; it = facesA->begin(); while (it != facesA->end()) { BOP_Face *face = *it; if (face->getTAG() == BROKEN) it = facesA->erase(it); else it++; } /* it = facesB->begin(); while (it != facesB->end()) { BOP_Face *face = *it; if (face->getTAG() == BROKEN) it = facesB->erase(it); else it++; } */ }
/** * Triangulates the input face according to the specified segment. * @param mesh mesh that contains the faces, edges and vertices * @param faces set of faces that contains the original face and the new triangulated faces * @param face face to be triangulated * @param s segment used to triangulate face */ void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s) { if (BOP_Segment::isUndefined(s.m_cfg1)) { // Nothing to do } else if (BOP_Segment::isVertex(s.m_cfg1)) { // VERTEX(v1) + VERTEX(v2) => nothing to do } else if (BOP_Segment::isEdge(s.m_cfg1)) { if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { // EDGE(v1) + VERTEX(v2) BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); BOP_triangulateA(mesh,faces,face,s.m_v1,BOP_Segment::getEdge(s.m_cfg1)); BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); if (opposite != NULL) { unsigned int e; opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); } } else { // EDGE(v1) + EDGE(v2) if (BOP_Segment::getEdge(s.m_cfg1) == BOP_Segment::getEdge(s.m_cfg2)) { // EDGE(v1) == EDGE(v2) BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); BOP_triangulateD(mesh, faces, face, s.m_v1, s.m_v2, BOP_Segment::getEdge(s.m_cfg1)); BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); if (opposite != NULL) { unsigned int e; opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); BOP_triangulateD(mesh, faces, opposite, s.m_v1, s.m_v2, e); } } else { // EDGE(v1) != EDGE(v2) BOP_Edge *edge1 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); BOP_Edge *edge2 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); BOP_triangulateE(mesh, faces, face, s.m_v1, s.m_v2, BOP_Segment::getEdge(s.m_cfg1), BOP_Segment::getEdge(s.m_cfg2)); BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge1); if (opposite != NULL) { unsigned int e; opposite->getEdgeIndex(edge1->getVertex1(), edge1->getVertex2(),e); BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); } opposite = BOP_getOppositeFace(mesh,faces,face,edge2); if (opposite != NULL) { unsigned int e; opposite->getEdgeIndex(edge2->getVertex1(), edge2->getVertex2(),e); BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); } } } } else if (BOP_Segment::isIn(s.m_cfg1)) { if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { // IN(v1) + VERTEX(v2) BOP_triangulateB(mesh,faces,face,s.m_v1); } else if (BOP_Segment::isEdge(s.m_cfg2)) { // IN(v1) + EDGE(v2) BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); BOP_triangulateF(mesh,faces,face,s.m_v1,s.m_v2,BOP_Segment::getEdge(s.m_cfg2)); BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); if (opposite != NULL) { unsigned int e; opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); } } else // IN(v1) + IN(v2) BOP_triangulateC(mesh,faces,face,s.m_v1,s.m_v2); } }
/** * Removes faces from facesB that are overlapped with anyone from facesA. * @param mesh mesh that contains the faces, edges and vertices * @param facesA set of faces from object A * @param facesB set of faces from object B */ void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) { for(unsigned int i=0;i<facesA->size();i++) { BOP_Face *faceI = (*facesA)[i]; if (faceI->getTAG()==BROKEN) continue; bool overlapped = false; MT_Point3 p1 = mesh->getVertex(faceI->getVertex(0))->getPoint(); MT_Point3 p2 = mesh->getVertex(faceI->getVertex(1))->getPoint(); MT_Point3 p3 = mesh->getVertex(faceI->getVertex(2))->getPoint(); for(unsigned int j=0;j<facesB->size();) { BOP_Face *faceJ = (*facesB)[j]; if (faceJ->getTAG()!=BROKEN) { MT_Plane3 planeJ = faceJ->getPlane(); if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2) && BOP_containsPoint(planeJ,p3)) { MT_Point3 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint(); MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint(); MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint(); if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()), p1,p2,p3,q1,q2,q3)) { facesB->erase(facesB->begin()+j,facesB->begin()+(j+1)); faceJ->setTAG(BROKEN); overlapped = true; } else j++; } else j++; }else j++; } if (overlapped) faceI->setTAG(OVERLAPPED); } }
/** * Triangulates faceB using edges of faceA that both are complanars. * @param mesh mesh that contains the faces, edges and vertices * @param facesB set of faces from object B * @param faceA face from object A * @param faceB face from object B * @param invert indicates if faceA has priority over faceB */ void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, BOP_Faces* facesB, BOP_Face* faceA, BOP_Face* faceB, bool invert) { unsigned int oldSize = facesB->size(); unsigned int originalFaceB = faceB->getOriginalFace(); MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); MT_Vector3 normal(faceA->getPlane().x(),faceA->getPlane().y(),faceA->getPlane().z()); MT_Vector3 p1p2 = p2-p1; MT_Plane3 plane1((p1p2.cross(normal).normalized()),p1); BOP_Segment sA; sA.m_cfg1 = BOP_Segment::createVertexCfg(1); sA.m_v1 = faceA->getVertex(0); sA.m_cfg2 = BOP_Segment::createVertexCfg(2); sA.m_v2 = faceA->getVertex(1); BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane1,invert); MT_Vector3 p2p3 = p3-p2; MT_Plane3 plane2((p2p3.cross(normal).normalized()),p2); sA.m_cfg1 = BOP_Segment::createVertexCfg(2); sA.m_v1 = faceA->getVertex(1); sA.m_cfg2 = BOP_Segment::createVertexCfg(3); sA.m_v2 = faceA->getVertex(2); if (faceB->getTAG() == BROKEN) { for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { BOP_Face *face = (*facesB)[idxFace]; if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane2,invert); } } else { BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane2,invert); } MT_Vector3 p3p1 = p1-p3; MT_Plane3 plane3((p3p1.cross(normal).safe_normalized()),p3); sA.m_cfg1 = BOP_Segment::createVertexCfg(3); sA.m_v1 = faceA->getVertex(2); sA.m_cfg2 = BOP_Segment::createVertexCfg(1); sA.m_v2 = faceA->getVertex(0); if (faceB->getTAG() == BROKEN) { for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { BOP_Face *face = (*facesB)[idxFace]; if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane3,invert); } } else { BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane3,invert); } }
void dumpmesh ( BOP_Mesh *m, bool force ) { unsigned int nonmanifold = 0; { BOP_Edges edges = m->getEdges(); int count = 0; for (BOP_IT_Edges edge = edges.begin(); edge != edges.end(); ++count, ++edge) { if (!(*edge)->getUsed() && (*edge)->getFaces().size() == 0 ) continue; BOP_Vertex * v1 = m->getVertex((*edge)->getVertex1()); BOP_Vertex * v2 = m->getVertex((*edge)->getVertex2()); if(v1->getTAG()!= BROKEN || v2->getTAG()!= BROKEN ) { int fcount = 0; BOP_Indexs faces = (*edge)->getFaces(); for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); face++) { BOP_Face *f = m->getFace(*face); if(f->getTAG()== UNCLASSIFIED) ++fcount; } if(fcount !=0 && fcount !=2 ) { ++nonmanifold; } } } if (!force && nonmanifold == 0) return; } if( nonmanifold ) cout << nonmanifold << " edges detected" << endl; #ifdef BOP_DEBUG cout << "---------------------------" << endl; BOP_Edges edges = m->getEdges(); int count = 0; for (BOP_IT_Edges edge = edges.begin(); edge != edges.end(); ++count, ++edge) { BOP_Vertex * v1 = m->getVertex((*edge)->getVertex1()); BOP_Vertex * v2 = m->getVertex((*edge)->getVertex2()); if(v1->getTAG()!= BROKEN || v2->getTAG()!= BROKEN ) { int fcount = 0; BOP_Indexs faces = (*edge)->getFaces(); cout << count << ", " << (*edge) << ", " << faces.size() << endl; for (BOP_IT_Indexs face = faces.begin(); face != faces.end(); face++) { BOP_Face *f = m->getFace(*face); if(f->getTAG()== UNCLASSIFIED) ++fcount; cout << " face " << f << endl; } if(fcount !=0 && fcount !=2 ) cout << " NON-MANIFOLD" << endl; } } BOP_Faces faces = m->getFaces(); count = 0; for (BOP_IT_Faces face = faces.begin(); face != faces.end(); face++) { if( count < 12*2 || (*face)->getTAG() != BROKEN ) { cout << count << ", " << *face << endl; } ++count; } BOP_Vertexs verts = m->getVertexs(); count = 0; for (BOP_IT_Vertexs vert = verts.begin(); vert != verts.end(); vert++) { cout << count++ << ", " << *vert << " " << (*vert)->getNumEdges() << endl; BOP_Indexs edges = (*vert)->getEdges(); for( BOP_IT_Indexs it = edges.begin(); it != edges.end(); ++it) { BOP_Edge *edge = m->getEdge(*it); cout << " " << edge << endl; } } cout << "===========================" << endl; #endif }