From f9169b8ec221d1e0e73b6781a27e69b6008ac67c Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Wed, 2 Nov 2016 12:11:18 +0100 Subject: [PATCH] Refactored a number of cleaning algorithms Issues resolved: - removed assert and used the correct meshassert exceptions - removed wrong use of selection instead of visiting flag (various filters destroyed selection when called) - rewrote a totally clumsy count hole. --- vcg/complex/algorithms/clean.h | 159 ++++++++++----------------------- 1 file changed, 48 insertions(+), 111 deletions(-) diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h index 65606b59..c8f62c68 100644 --- a/vcg/complex/algorithms/clean.h +++ b/vcg/complex/algorithms/clean.h @@ -79,8 +79,6 @@ public: mp=&m; while(!sf.empty()) sf.pop(); UnMarkAll(m); - assert(p); - assert(!p->IsD()); tri::Mark(m,p); sf.push(p); } @@ -272,7 +270,6 @@ public: tri::Index(m,(*fi).V(2)), &*fi)); } - assert (size_t(m.fn) == fvec.size()); std::sort(fvec.begin(),fvec.end()); int total=0; for(int i=0;i::DeleteEdge(m, *(eVec[i].fp) ); - //qDebug("deleting face %i (pos in fvec %i)",tri::Index(m,fvec[i].fp) ,i); } } return total; @@ -440,12 +434,10 @@ public: CountNonManifoldVertexFF(m,true); tri::UpdateSelection::FaceFromVertexLoose(m); int count_removed = 0; - FaceIterator fi; - for(fi=m.face.begin(); fi!=m.face.end();++fi) + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!(*fi).IsD() && (*fi).IsS()) Allocator::DeleteFace(m,*fi); - VertexIterator vi; - for(vi=m.vert.begin(); vi!=m.vert.end();++vi) + for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi) if(!(*vi).IsD() && (*vi).IsS()) { ++count_removed; Allocator::DeleteVertex(m,*vi); @@ -631,22 +623,15 @@ public: return count_fd; } - /* - The following functions remove faces that are geometrically "bad" according to edges and area criteria. - They remove the faces that are out of a given range of area or edges (e.g. faces too large or too small, or with edges too short or too long) - but that could be topologically correct. - These functions can optionally take into account only the selected faces. - */ - template - static int RemoveFaceOutOfRangeAreaSel(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)()) + /* Remove the faces that are out of a given range of area */ + static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)(), bool OnlyOnSelected=false) { - FaceIterator fi; int count_fd = 0; MinAreaThr*=2; MaxAreaThr*=2; - for(fi=m.face.begin(); fi!=m.face.end();++fi) + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi){ if(!(*fi).IsD()) - if(!Selected || (*fi).IsS()) + if(!OnlyOnSelected || (*fi).IsS()) { const ScalarType doubleArea=DoubleArea(*fi); if((doubleArea<=MinAreaThr) || (doubleArea>=MaxAreaThr) ) @@ -655,17 +640,13 @@ public: count_fd++; } } + } return count_fd; } - // alias for the old style. Kept for backward compatibility - static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m);} + static int RemoveZeroAreaFace(MeshType& m) { return RemoveFaceOutOfRangeArea(m,0);} - // Aliases for the functions that do not look at selection - static int RemoveFaceOutOfRangeArea(MeshType& m, ScalarType MinAreaThr=0, ScalarType MaxAreaThr=(std::numeric_limits::max)()) - { - return RemoveFaceOutOfRangeAreaSel(m,MinAreaThr,MaxAreaThr); - } + /** * Is the mesh only composed by quadrilaterals? @@ -850,7 +831,7 @@ public: */ static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false) { - assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh... + MeshAssert::OnlyEdgeMesh(m); RequireEEAdjacency(m); tri::UpdateTopology::EdgeEdge(m); @@ -1031,61 +1012,27 @@ public: static int CountHoles( MeshType & m) { - int numholev=0; - FaceIterator fi; - - FaceIterator gi; - vcg::face::Pos he; - vcg::face::Pos hei; - - std::vector< std::vector > holes; //indices of vertices - - vcg::tri::UpdateFlags::VertexClearS(m); - - gi=m.face.begin(); fi=gi; - - for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do + UpdateFlags::FaceClearV(m); + int loopNum=0; + for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) if(!fi->IsD()) { - for(int j=0;j<3;j++)//for all edges - { - if(fi->V(j)->IsS()) continue; - - if(face::IsBorder(*fi,j))//found an unvisited border edge + for(int j=0;j<3;++j) { - he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex - std::vector hole; //start of a new hole - hole.push_back(fi->P(j)); // including the first vertex - numholev++; - he.v->SetS(); //set the current vertex as selected - he.NextB(); //go to the next boundary edge - - - while(fi->V(j) != he.v)//will we do not encounter the first boundary edge. + if(!fi->IsV() && face::IsBorder(*fi,j)) { - CoordType newpoint = he.v->P(); //select its vertex. - if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole. + face::Pos startPos(&*fi,j); + face::Pos curPos=startPos; + do { - //cut and paste the additional hole. - std::vector hole2; - int index = static_cast(find(hole.begin(),hole.end(),newpoint) - - hole.begin()); - for(unsigned int i=index; iSetV(); } - hole.push_back(newpoint); - numholev++; - he.v->SetS(); //set the current vertex as selected - he.NextB(); //go to the next boundary edge + while(curPos!=startPos); + ++loopNum; } - holes.push_back(hole); } - } } - return static_cast(holes.size()); + return loopNum; } /* @@ -1102,14 +1049,14 @@ public: { tri::RequireFFAdjacency(m); CCV.clear(); - tri::UpdateSelection::FaceClear(m); + tri::UpdateFlags::FaceClearV(m); std::stack sf; FacePointer fpt=&*(m.face.begin()); for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) { - if(!((*fi).IsD()) && !(*fi).IsS()) + if(!((*fi).IsD()) && !(*fi).IsV()) { - (*fi).SetS(); + (*fi).SetV(); CCV.push_back(std::make_pair(0,&*fi)); sf.push(&*fi); while (!sf.empty()) @@ -1122,9 +1069,9 @@ public: if( !face::IsBorder(*fpt,j) ) { FacePointer l = fpt->FFp(j); - if( !(*l).IsS() ) + if( !(*l).IsV() ) { - (*l).SetS(); + (*l).SetV(); sf.push(l); } } @@ -1260,6 +1207,8 @@ public: static bool IsCoherentlyOrientedMesh(MeshType &m) { + RequireFFAdjacency(m); + MeshAssert::FFAdjacencyIsInitialized(m); for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) for(int i=0;i<3;++i) @@ -1269,26 +1218,22 @@ public: return true; } - static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable) + static void OrientCoherentlyMesh(MeshType &m, bool &_IsOriented, bool &_IsOrientable) { RequireFFAdjacency(m); - assert(&Oriented != &Orientable); - assert(m.face.back().FFp(0)); // This algorithms require FF topology initialized + MeshAssert::FFAdjacencyIsInitialized(m); + bool IsOrientable = true; + bool IsOriented = true; - Orientable = true; - Oriented = true; - - tri::UpdateSelection::FaceClear(m); + UpdateFlags::FaceClearV(m); std::stack faces; for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { - if (!fi->IsD() && !fi->IsS()) + if (!fi->IsD() && !fi->IsV()) { // each face put in the stack is selected (and oriented) - fi->SetS(); + fi->SetV(); faces.push(&(*fi)); - - // empty the stack while (!faces.empty()) { FacePointer fp = faces.top(); @@ -1297,42 +1242,35 @@ public: // make consistently oriented the adjacent faces for (int j = 0; j < 3; j++) { - // get one of the adjacent face - FacePointer fpaux = fp->FFp(j); - int iaux = fp->FFi(j); - - if (!fpaux->IsD() && fpaux != fp && face::IsManifold(*fp, j)) + if (!face::IsBorder(*fp,j) && face::IsManifold(*fp, j)) { + FacePointer fpaux = fp->FFp(j); + int iaux = fp->FFi(j); if (!CheckOrientation(*fpaux, iaux)) { - Oriented = false; + IsOriented = false; - if (!fpaux->IsS()) - { + if (!fpaux->IsV()) face::SwapEdge(*fpaux, iaux); - assert(CheckOrientation(*fpaux, iaux)); - } else { - Orientable = false; + IsOrientable = false; break; } } - - // put the oriented face into the stack - - if (!fpaux->IsS()) + if (!fpaux->IsV()) { - fpaux->SetS(); + fpaux->SetV(); faces.push(fpaux); } } } } } - - if (!Orientable) break; + if (!IsOrientable) break; } + _IsOriented = IsOriented; + _IsOrientable = IsOrientable; } @@ -1666,7 +1604,6 @@ public: */ static bool TestFaceFaceIntersection(FaceType *f0,FaceType *f1) { - assert(f0!=f1); int sv = face::CountSharedVertex(f0,f1); if(sv==3) return true; if(sv==0) return (vcg::IntersectionTriangleTriangle((*f0),(*f1)));