From 527953434d7d08cb07028f192be1db940dbe3896 Mon Sep 17 00:00:00 2001 From: korialis Date: Fri, 13 Nov 2020 15:30:38 +0100 Subject: [PATCH] bug fix on isotropic remeshing collapse strategy --- vcg/complex/algorithms/edge_collapse.h | 164 ++++++++++++------- vcg/complex/algorithms/isotropic_remeshing.h | 55 ++++--- 2 files changed, 132 insertions(+), 87 deletions(-) diff --git a/vcg/complex/algorithms/edge_collapse.h b/vcg/complex/algorithms/edge_collapse.h index 57da15b9..074edc6d 100644 --- a/vcg/complex/algorithms/edge_collapse.h +++ b/vcg/complex/algorithms/edge_collapse.h @@ -211,77 +211,117 @@ public: // To do a collapse onto a vertex simply pass p as the position of the surviving vertex static int Do(TriMeshType &m, VertexPair & c, const Point3 &p, const bool preserveFaceEdgeS = false) { - EdgeSet es; - FindSets(c,es); - - int n_face_del=0 ; + EdgeSet es, es1; + FindSets(c,es); - static int VtoE[3][3] = { -1, 0, 2, - 0, -1, 1, - 2, 1, -1 }; + if (preserveFaceEdgeS) + { + VertexPair c1(c.V(1), c.V(0)); + FindSets(c1, es1); + } -// bool toSel = false; + int n_face_del=0 ; - VertexType* top[2]; - std::map toSel; + static int VtoE[3][3] = { -1, 0, 2, + 0, -1, 1, + 2, 1, -1 }; - std::vector v2s; v2s.reserve(2); + std::vector topVertices; topVertices.reserve(2); + std::vector fan1V2S; fan1V2S.reserve(2); + std::vector v2s; v2s.reserve(2); + std::map toSel; - for(auto i=es.AV01().begin();i!=es.AV01().end();++i) - { - FaceType & f = *((*i).f); - assert(f.V((*i).z) == c.V(0)); - if (preserveFaceEdgeS && f.IsFaceEdgeS(VtoE[((*i).z+1)%3][((*i).z+2)%3])) - { -// std::cout << "2 " <::DeleteFace(m,f); - n_face_del++; - } - - // Very LOW LEVEL update of VF Adjacency; - // for all the faces incident in v[0] - // - v[0] will be deleted so we substitute v[0] with v[1] - // - we prepend that face to the list of the faces incident on v[1] - for(auto i=es.AV0().begin();i!=es.AV0().end();++i) - { - FaceType & f = *((*i).f); + if (preserveFaceEdgeS) + { + VertexPointer top; + size_t topIdx; + if (f.V(((*i).z+1)%3) == c.V(1)) + { + top = f.V(((*i).z+2)%3); + topIdx = ((*i).z+2)%3; + } + else + { + top = f.V(((*i).z+1)%3); + topIdx = ((*i).z+1)%3; + } - if (preserveFaceEdgeS) - { - for (size_t j = 0; j < v2s.size(); ++j) - { - if ((*i).f->V(((*i).z+1)%3) == v2s[j]) - { - (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+1)%3]); - break; - } - if ((*i).f->V(((*i).z+2)%3) == v2s[j]) - { - (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+2)%3]); - break; - } - } - } - (*i).f->V((*i).z) = c.V(1); // For each face in v0 we substitute v0 with v1 - (*i).f->VFp((*i).z) = c.V(1)->VFp(); - (*i).f->VFi((*i).z) = c.V(1)->VFi(); - c.V(1)->VFp() = (*i).f; - c.V(1)->VFi() = (*i).z; + topVertices.push_back(top); - } - - Allocator::DeleteVertex(m,*(c.V(0))); - c.V(1)->P()=p; - return n_face_del; + if (f.IsFaceEdgeS(VtoE[((*i).z)][topIdx])) + fan1V2S.push_back(top); + + if (f.IsFaceEdgeS(VtoE[((*i).z+1)%3][((*i).z+2)%3])) + v2s.push_back(top); + } + + vcg::face::VFDetach(f,((*i).z+1)%3); + vcg::face::VFDetach(f,((*i).z+2)%3); + Allocator::DeleteFace(m,f); + n_face_del++; + } + + // Very LOW LEVEL update of VF Adjacency; + // for all the faces incident in v[0] + // - v[0] will be deleted so we substitute v[0] with v[1] + // - we prepend that face to the list of the faces incident on v[1] + for(auto i=es.AV0().begin();i!=es.AV0().end();++i) + { + FaceType & f = *((*i).f); + + if (preserveFaceEdgeS) + { + for (size_t j = 0; j < v2s.size(); ++j) + { + if ((*i).f->V(((*i).z+1)%3) == v2s[j]) + { + (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+1)%3]); + break; + } + if ((*i).f->V(((*i).z+2)%3) == v2s[j]) + { + (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+2)%3]); + break; + } + } + } + (*i).f->V((*i).z) = c.V(1); // For each face in v0 we substitute v0 with v1 + (*i).f->VFp((*i).z) = c.V(1)->VFp(); + (*i).f->VFi((*i).z) = c.V(1)->VFi(); + c.V(1)->VFp() = (*i).f; + c.V(1)->VFi() = (*i).z; + } + + if (preserveFaceEdgeS) + { + for (auto i = es1.AV0().begin(); i != es1.AV0().end(); ++i) + { + FaceType & f = *((*i).f); + for (size_t j = 0; j < fan1V2S.size(); ++j) + { + if ((*i).f->V(((*i).z+1)%3) == fan1V2S[j]) + { + (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+1)%3]); + break; + } + if ((*i).f->V(((*i).z+2)%3) == fan1V2S[j]) + { + (*i).f->SetFaceEdgeS(VtoE[((*i).z)%3][((*i).z+2)%3]); + break; + } + } + } + } + + Allocator::DeleteVertex(m,*(c.V(0))); + c.V(1)->P()=p; + return n_face_del; } }; diff --git a/vcg/complex/algorithms/isotropic_remeshing.h b/vcg/complex/algorithms/isotropic_remeshing.h index 06ea33bb..f1f75e3a 100644 --- a/vcg/complex/algorithms/isotropic_remeshing.h +++ b/vcg/complex/algorithms/isotropic_remeshing.h @@ -407,7 +407,7 @@ private: FaceType* fp = GetClosestFaceBase(m, grid, v, maxD, dist, closest); //you can't use this kind of orientation check, since when you stand on edges it fails - if (fp == NULL /*|| (checkOrientation != CoordType(0,0,0) && checkOrientation * fp->N() < 0.5)*/) + if (fp == NULL || (checkOrientation != CoordType(0,0,0) && checkOrientation * fp->N() < 0.7)) { return false; } @@ -563,9 +563,9 @@ private: / \ /|\ / \ / | \ / \ / | \ - / _*p\ -1/ | \ -1 - v2--------v0 ========> v2 | v0 - \ / \ | / + / _*p\ -1/ | \ -1 + v2--------v0 ========> v2 | v0 + \ / \ | / \ / \ | / \ / \ | / \ / \|/ +1 @@ -761,18 +761,21 @@ private: int incidentFeatures = 0; + vcg::tri::UnMarkAll(*params.m); + for (size_t i = 0; i < faces.size(); ++i) - // if (faces[i] != p.F() && faces[i] != p.FFlip()) { - if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+1)%3))) + if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+1)%3)) && !vcg::tri::IsMarked(*params.m, faces[i]->cV1(vIdxes[i]))) { + vcg::tri::Mark(*params.m,faces[i]->cV1(vIdxes[i])); incidentFeatures++; CoordType movingEdgeVector0 = (faces[i]->cP1(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize(); if (std::fabs(movingEdgeVector0 * dEdgeVector) < .9f || !p.IsEdgeS()) return false; } - if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+2)%3))) + if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+2)%3)) && !vcg::tri::IsMarked(*params.m, faces[i]->cV2(vIdxes[i]))) { + vcg::tri::Mark(*params.m,faces[i]->cV2(vIdxes[i])); incidentFeatures++; CoordType movingEdgeVector1 = (faces[i]->cP2(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize(); if (std::fabs(movingEdgeVector1 * dEdgeVector) < .9f || !p.IsEdgeS()) @@ -781,7 +784,7 @@ private: allIncidentFaceSelected &= faces[i]->IsS(); } - if (incidentFeatures > 4) + if (incidentFeatures > 2) return false; return params.selectedOnly ? allIncidentFaceSelected : true; @@ -821,18 +824,23 @@ private: // float div = fastAngle(oldN, newN); // if(div < .9f ) return false; - if (oldN * newN < 0.8f) + if (oldN * newN < 0.5f) return false; // // check on new face distance from original mesh if (params.surfDistCheck) { - std::vector points(4); - points[0] = (v1->cP() + v2->cP() + mp) / 3.; - points[1] = (v1->cP() + mp) / 2.; - points[2] = (v2->cP() + mp) / 2.; - points[3] = mp; - if (!testHausdorff(*(params.mProject), params.grid, points, params.maxSurfDist, newN)) + std::vector points(3); + std::vector baryP(1); + + baryP[0] = (v1->cP() + v2->cP() + mp) / 3.; + + points[0] = (v1->cP() + mp) / 2.; + points[1] = (v2->cP() + mp) / 2.; + points[2] = mp; + + if (!testHausdorff(*(params.mProject), params.grid, points, params.maxSurfDist) || + !testHausdorff(*(params.mProject), params.grid, baryP, params.maxSurfDist, newN)) return false; } } @@ -842,7 +850,7 @@ private: //TODO: Refactor code and implement the correct set up of crease info when collapsing towards a crease edge - static bool checkCollapseFacesAroundVert1(PosType &p, Point3 &mp, Params ¶ms, bool relaxed) + static bool checkCollapseFacesAroundVert1(PosType &p, VertexPair & pair, Point3 &mp, Params ¶ms, bool relaxed) { PosType p0 = p, p1 = p; @@ -863,6 +871,8 @@ private: if (!moveable0 && !moveable1) return false; + pair = moveable0 ? VertexPair(p0.V(), p1.V()) : VertexPair(p1.V(), p0.V()); + //casting int(true) is always 1 and int(false) = =0 assert(int(true) == 1); assert(int(false) == 0); @@ -874,7 +884,7 @@ private: return false; } - static bool testCollapse1(PosType &p, Point3 &mp, ScalarType minQ, ScalarType maxQ, Params ¶ms, bool relaxed = false) + static bool testCollapse1(PosType &p, VertexPair & pair, Point3 &mp, ScalarType minQ, ScalarType maxQ, Params ¶ms, bool relaxed = false) { ScalarType mult = (params.adapt) ? math::ClampedLerp((ScalarType)0.5,(ScalarType)1.5, (((math::Abs(p.V()->Q())+math::Abs(p.VFlip()->Q()))/(ScalarType)2.0)/(maxQ-minQ))) : (ScalarType)1; ScalarType dist = Distance(p.V()->P(), p.VFlip()->P()); @@ -882,7 +892,7 @@ private: ScalarType area = DoubleArea(*(p.F()))/2.f; if(relaxed || (dist < thr || area < params.minLength*params.minLength/100.f))//if to collapse { - return checkCollapseFacesAroundVert1(p, mp, params, relaxed); + return checkCollapseFacesAroundVert1(p, pair, mp, params, relaxed); } return false; } @@ -951,11 +961,8 @@ private: VertexPair bp = VertexPair(pi.V(), pi.VFlip()); Point3 mp = (pi.V()->P()+pi.VFlip()->P())/2.f; - if(testCollapse1(pi, mp, minQ, maxQ, params) && Collapser::LinkConditions(bp)) + if(testCollapse1(pi, bp, mp, minQ, maxQ, params) && Collapser::LinkConditions(bp)) { - //collapsing on pi.V() - bp = VertexPair(pi.VFlip(), pi.V()); - Collapser::Do(m, bp, mp, true); ++params.stat.collapseNum; break; @@ -964,7 +971,6 @@ private: } } } - ss.pop(); } @@ -1129,9 +1135,8 @@ private: VertexPair bp = VertexPair(pi.V(), pi.VFlip()); Point3 mp = (pi.V()->P()+pi.VFlip()->P())/2.f; - if(testCollapse1(pi, mp, 0, 0, params, true) && Collapser::LinkConditions(bp)) + if(testCollapse1(pi, bp, mp, 0, 0, params, true) && Collapser::LinkConditions(bp)) { - bp = VertexPair(pi.VFlip(), pi.V()); Collapser::Do(m, bp, mp, true); ++params.stat.collapseNum; ++count;