small mods to isotropic remeshing

This commit is contained in:
T.Alderighi 2020-01-04 17:03:30 +01:00
parent 1d082b7fbe
commit 662950a347
1 changed files with 149 additions and 130 deletions

View File

@ -176,11 +176,11 @@ public:
if(cb) cb(100*i/params.iter, "Remeshing"); if(cb) cb(100*i/params.iter, "Remeshing");
// debug_crease(toRemesh, std::string("pre_ref"), i); // debug_crease(toRemesh, std::string("pre_ref"), i);
if(params.splitFlag) if(params.splitFlag)
SplitLongEdges(toRemesh, params); SplitLongEdges(toRemesh, params);
#ifdef DEBUG_CREASE #ifdef DEBUG_CREASE
debug_crease(toRemesh, std::string("after_ref"), i); debug_crease(toRemesh, std::string("after_ref"), i);
#endif #endif
if(params.collapseFlag) if(params.collapseFlag)
@ -318,7 +318,7 @@ private:
if (p.IsBorder()) if (p.IsBorder())
p.F()->SetFaceEdgeS(p.E()); p.F()->SetFaceEdgeS(p.E());
// if((p.FFlip() > p.F())) // if((p.FFlip() > p.F()))
{ {
if (!params.userSelectedCreases && (testCreaseEdge(p, params.creaseAngleCosThr) || p.IsBorder())) if (!params.userSelectedCreases && (testCreaseEdge(p, params.creaseAngleCosThr) || p.IsBorder()))
{ {
@ -528,6 +528,7 @@ private:
CoordType swapEdgeMidPoint = (f.cP2(i) + f.cFFp(i)->cP2(f.cFFi(i))) / 2.; CoordType swapEdgeMidPoint = (f.cP2(i) + f.cFFp(i)->cP2(f.cFFi(i))) / 2.;
std::vector<CoordType> toCheck(1, swapEdgeMidPoint); std::vector<CoordType> toCheck(1, swapEdgeMidPoint);
if(((!params.selectedOnly) || (f.IsS() && f.cFFp(i)->IsS())) && if(((!params.selectedOnly) || (f.IsS() && f.cFFp(i)->IsS())) &&
face::IsManifold(f, i) && checkManifoldness(f, i) && face::IsManifold(f, i) && checkManifoldness(f, i) &&
face::CheckFlipEdge(f, i) && face::CheckFlipEdge(f, i) &&
@ -640,22 +641,30 @@ private:
CoordType dEdgeVector = (p.V()->cP() - p.VFlip()->cP()).Normalize(); CoordType dEdgeVector = (p.V()->cP() - p.VFlip()->cP()).Normalize();
int incidentFeatures = 0;
for (size_t i = 0; i < faces.size(); ++i) 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)))
CoordType movingEdgeVector0 = (faces[i]->cP1(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize(); {
if (std::fabs(movingEdgeVector0 * dEdgeVector) < 1.f) incidentFeatures++;
return false; CoordType movingEdgeVector0 = (faces[i]->cP1(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize();
} if (std::fabs(movingEdgeVector0 * dEdgeVector) < .9f || !p.IsEdgeS())
if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+2)%3))) return false;
{ }
CoordType movingEdgeVector1 = (faces[i]->cP2(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize(); if (faces[i]->IsFaceEdgeS(VtoE(vIdxes[i], (vIdxes[i]+2)%3)))
if (std::fabs(movingEdgeVector1 * dEdgeVector) < 1.f) {
return false; incidentFeatures++;
} CoordType movingEdgeVector1 = (faces[i]->cP2(vIdxes[i]) - faces[i]->cP(vIdxes[i])).Normalize();
allIncidentFaceSelected &= faces[i]->IsS(); if (std::fabs(movingEdgeVector1 * dEdgeVector) < .9f || !p.IsEdgeS())
} return false;
}
allIncidentFaceSelected &= faces[i]->IsS();
}
if (incidentFeatures > 4)
return false;
return params.selectedOnly ? allIncidentFaceSelected : true; return params.selectedOnly ? allIncidentFaceSelected : true;
} }
@ -693,9 +702,9 @@ private:
Point3<ScalarType> newN = Normal(mp, v1->P(), v2->P()).Normalize(); Point3<ScalarType> newN = Normal(mp, v1->P(), v2->P()).Normalize();
float div = fastAngle(oldN, newN); float div = fastAngle(oldN, newN);
if(div < .0f ) return false; if(div < .8f ) return false;
// // check on new face distance from original mesh // // check on new face distance from original mesh
if (params.surfDistCheck) if (params.surfDistCheck)
{ {
std::vector<CoordType> points(4); std::vector<CoordType> points(4);
@ -750,83 +759,83 @@ private:
return false; return false;
} }
// //Geometric check on feasibility of the collapse of the given pos // //Geometric check on feasibility of the collapse of the given pos
// //The check fails if: // //The check fails if:
// // -new face has too bad quality. // // -new face has too bad quality.
// // -new face normal changes too much after collapse. // // -new face normal changes too much after collapse.
// // -new face has too long edges. // // -new face has too long edges.
// // TRY: if the vertex has valence 4 (cross vertex) we relax the check on length // // TRY: if the vertex has valence 4 (cross vertex) we relax the check on length
// //TODO: Refine the crease preservance check when collapsing along boundary (or in general maybe) WORK on this // //TODO: Refine the crease preservance check when collapsing along boundary (or in general maybe) WORK on this
// static bool checkCollapseFacesAroundVert(PosType &p, Point3<ScalarType> &mp, Params & params, bool relaxed=false, bool crease=false) // static bool checkCollapseFacesAroundVert(PosType &p, Point3<ScalarType> &mp, Params & params, bool relaxed=false, bool crease=false)
// { // {
// ScalarType minimalAdmittedArea = (params.minLength * params.minLength)/10000.0; // ScalarType minimalAdmittedArea = (params.minLength * params.minLength)/10000.0;
// vector<FaceType*> ff; // vector<FaceType*> ff;
// vector<int> vi; // vector<int> vi;
// face::VFStarVF<FaceType>(p.V(), ff, vi); // face::VFStarVF<FaceType>(p.V(), ff, vi);
// bool allIncidentFaceSelected = true; // bool allIncidentFaceSelected = true;
// for(FaceType *f: ff) // for(FaceType *f: ff)
// if(!(*f).IsD() && f != p.F()) //i'm not a deleted face // if(!(*f).IsD() && f != p.F()) //i'm not a deleted face
// { // {
// allIncidentFaceSelected &= f->IsS(); // allIncidentFaceSelected &= f->IsS();
// PosType pi(f, p.V()); //same vertex // PosType pi(f, p.V()); //same vertex
// VertexType *v0 = pi.V(); // VertexType *v0 = pi.V();
// VertexType *v1 = pi.F()->V1(pi.VInd()); // VertexType *v1 = pi.F()->V1(pi.VInd());
// VertexType *v2 = pi.F()->V2(pi.VInd()); // VertexType *v2 = pi.F()->V2(pi.VInd());
// if( v1 == p.VFlip() || v2 == p.VFlip()) //i'm the other deleted face // if( v1 == p.VFlip() || v2 == p.VFlip()) //i'm the other deleted face
// continue; // continue;
// //check on new face area // //check on new face area
// { // {
// float area = DoubleArea(*(pi.F()))/2.f; // float area = DoubleArea(*(pi.F()))/2.f;
// if (area < params.minimalAdmittedArea) // if (area < params.minimalAdmittedArea)
// return false; // return false;
// } // }
// float area = DoubleArea(*(pi.F()))/2.f; // float area = DoubleArea(*(pi.F()))/2.f;
// //quality and normal divergence checks // //quality and normal divergence checks
// ScalarType newQ = Quality(mp, v1->P(), v2->P()); // ScalarType newQ = Quality(mp, v1->P(), v2->P());
// ScalarType oldQ = Quality(v0->P(), v1->P(), v2->P()); // ScalarType oldQ = Quality(v0->P(), v1->P(), v2->P());
// if(area > minimalAdmittedArea) // for triangles not too small // if(area > minimalAdmittedArea) // for triangles not too small
// { // {
// if( newQ <= 0.5*oldQ ) // if( newQ <= 0.5*oldQ )
// return false; // return false;
// // we prevent collapse that makes edges too long (except for cross) // // we prevent collapse that makes edges too long (except for cross)
// if(!relaxed) // if(!relaxed)
// if((Distance(mp, v1->P()) > params.maxLength || Distance(mp, v2->P()) > params.maxLength)) // if((Distance(mp, v1->P()) > params.maxLength || Distance(mp, v2->P()) > params.maxLength))
// return false; // return false;
// Point3<ScalarType> oldN = NormalizedTriangleNormal(*(pi.F())); // Point3<ScalarType> oldN = NormalizedTriangleNormal(*(pi.F()));
// Point3<ScalarType> newN = Normal(mp, v1->P(), v2->P()).Normalize(); // Point3<ScalarType> newN = Normal(mp, v1->P(), v2->P()).Normalize();
//// float div = fastAngle(oldN, newN); //// float div = fastAngle(oldN, newN);
//// if(crease && div < 0.98) return false; //// if(crease && div < 0.98) return false;
//// { //// {
//// std::vector<CoordType> points(3); //// std::vector<CoordType> points(3);
//// points[0] = (v1->cP() + v2->cP() + mp) / 3.; //// points[0] = (v1->cP() + v2->cP() + mp) / 3.;
//// points[1] = (v1->cP() + v0->cP()) / 2.; //// points[1] = (v1->cP() + v0->cP()) / 2.;
//// points[2] = (v2->cP() + v0->cP()) / 2.; //// points[2] = (v2->cP() + v0->cP()) / 2.;
//// if (!testHausdorff(*(params.mProject), params.grid, points, params.maxSurfDist)) //// if (!testHausdorff(*(params.mProject), params.grid, points, params.maxSurfDist))
//// return false; //// return false;
//// } //// }
// } // }
// } // }
// if(params.selectedOnly) return allIncidentFaceSelected; // if(params.selectedOnly) return allIncidentFaceSelected;
// return true; // return true;
// } // }
static bool testCollapse1(PosType &p, Point3<ScalarType> &mp, ScalarType minQ, ScalarType maxQ, Params &params, bool relaxed = false) static bool testCollapse1(PosType &p, Point3<ScalarType> &mp, ScalarType minQ, ScalarType maxQ, Params &params, bool relaxed = false)
{ {
@ -970,7 +979,7 @@ private:
v3 = fv1; v3 = fv1;
crease[3] = f->IsFaceEdgeS(VtoE(pi.VInd(), (pi.VInd()+1)%3)); crease[3] = f->IsFaceEdgeS(VtoE(pi.VInd(), (pi.VInd()+1)%3));
} }
// v3 = (fv1 == v0) ? fv2 : fv1; // v3 = (fv1 == v0) ? fv2 : fv1;
} }
if(fv1 == v1 || fv2 == v1) if(fv1 == v1 || fv2 == v1)
@ -985,7 +994,7 @@ private:
v2 = fv1; v2 = fv1;
crease[2] = f->IsFaceEdgeS(VtoE(pi.VInd(), (pi.VInd()+1)%3)); crease[2] = f->IsFaceEdgeS(VtoE(pi.VInd(), (pi.VInd()+1)%3));
} }
// v2 = (fv1 == v1) ? fv2 : fv1; // v2 = (fv1 == v1) ? fv2 : fv1;
} }
} }
@ -1005,22 +1014,22 @@ private:
if (crease[0] || crease[1] || crease[2] || crease[3]) if (crease[0] || crease[1] || crease[2] || crease[3])
return false; return false;
// if (crease[0] && crease[1] && crease[2] && crease[3]) // if (crease[0] && crease[1] && crease[2] && crease[3])
// { // {
// return false; // return false;
// } // }
// if (crease[0] || crease[2]) // if (crease[0] || crease[2])
// { // {
// bp = VertexPair(p.V(), v0); // bp = VertexPair(p.V(), v0);
// return true; // return true;
// } // }
// if (crease[1] || crease[3]) // if (crease[1] || crease[3])
// { // {
// bp = VertexPair(p.V(), v1); // bp = VertexPair(p.V(), v1);
// return true; // return true;
// } // }
//no crease //no crease
if(delta1 < delta2 && Q1 >= 0.6f*Q2) if(delta1 < delta2 && Q1 >= 0.6f*Q2)
@ -1059,40 +1068,40 @@ private:
//if tricuspidis need whenever you have at least one crease => can't collapse anywhere //if tricuspidis need whenever you have at least one crease => can't collapse anywhere
if(ff.size() == 4 || ff.size() == 3) if(ff.size() == 4 || ff.size() == 3)
{ {
// VertexPair bp; // VertexPair bp;
VertexPair bp = VertexPair(pi.V(), pi.VFlip()); VertexPair bp = VertexPair(pi.V(), pi.VFlip());
Point3<ScalarType> mp = (pi.V()->P()+pi.VFlip()->P())/2.f; Point3<ScalarType> mp = (pi.V()->P()+pi.VFlip()->P())/2.f;
// if (ff.size() == 4) // if (ff.size() == 4)
// { // {
// //avoid collapsing if creases don't allow to // //avoid collapsing if creases don't allow to
//// continue; //// continue;
// if (!chooseBestCrossCollapse(pi, bp, ff)) // if (!chooseBestCrossCollapse(pi, bp, ff))
// continue; // continue;
// } // }
// else //tricuspidis // else //tricuspidis
// { // {
// bool collapse = true; // bool collapse = true;
// for (int i = 0; i < ff.size(); ++i) // for (int i = 0; i < ff.size(); ++i)
// { // {
// PosType pp(ff[i], pi.V()); // PosType pp(ff[i], pi.V());
// if (pp.IsFaceS()) // if (pp.IsFaceS())
// collapse = false; // collapse = false;
// pp.FlipE(); // pp.FlipE();
// if (pp.IsFaceS()) // if (pp.IsFaceS())
// collapse = false; // collapse = false;
// } // }
// if (!collapse) // if (!collapse)
// continue; // continue;
// else bp = VertexPair(pi.V(), pi.VFlip()); // else bp = VertexPair(pi.V(), pi.VFlip());
// } // }
//// VertexPair bp = (ff.size() == 4) ? chooseBestCrossCollapse(pi, ff) : VertexPair(pi.V(), pi.VFlip()); //// VertexPair bp = (ff.size() == 4) ? chooseBestCrossCollapse(pi, ff) : VertexPair(pi.V(), pi.VFlip());
// Point3<ScalarType> mp = bp.V(1)->P(); // Point3<ScalarType> mp = bp.V(1)->P();
// //todo: think about if you should try doing the other collapse if test or link fails for this one // //todo: think about if you should try doing the other collapse if test or link fails for this one
// if(testCrossCollapse(pi, ff, vi, mp, params) && Collapser::LinkConditions(bp)) // if(testCrossCollapse(pi, ff, vi, mp, params) && Collapser::LinkConditions(bp))
if(testCollapse1(pi, mp, 0, 0, params) && Collapser::LinkConditions(bp)) if(testCollapse1(pi, mp, 0, 0, params) && Collapser::LinkConditions(bp))
{ {
Collapser::Do(m, bp, mp, true); Collapser::Do(m, bp, mp, true);
@ -1111,7 +1120,7 @@ private:
{ {
int count = 0; int count = 0;
ForEachFacePos(m, [&](PosType &p){ ForEachFacePos(m, [&](PosType &p){
if(((p.FFlip() > p.F()) || p.IsBorder()) && p.IsEdgeS()/*testCreaseEdge(p, creaseThr)*/) if(p.IsBorder() || p.IsEdgeS()/*testCreaseEdge(p, creaseThr)*/)
{ {
p.V()->SetS(); p.V()->SetS();
p.VFlip()->SetS(); p.VFlip()->SetS();
@ -1135,7 +1144,7 @@ private:
//this aspect ratio check doesn't work on cadish meshes (long thin triangles spanning whole mesh) //this aspect ratio check doesn't work on cadish meshes (long thin triangles spanning whole mesh)
ForEachFace(m, [&] (FaceType & f) { ForEachFace(m, [&] (FaceType & f) {
if (vcg::QualityRadii(f.cP(0), f.cP(1), f.cP(2)) < params.aspectRatioThr) if (vcg::Quality(f.cP(0), f.cP(1), f.cP(2)) < params.aspectRatioThr)
{ {
if (creaseVerts[vcg::tri::Index(m, f.V(0))] == 0) if (creaseVerts[vcg::tri::Index(m, f.V(0))] == 0)
f.V(0)->SetS(); f.V(0)->SetS();
@ -1171,14 +1180,18 @@ private:
return 0; return 0;
} }
static void FoldRelax(MeshType &m, Params params, const int step)
static void FoldRelax(MeshType &m, Params params, const int step, const bool strict = true)
{ {
typename vcg::tri::Smooth<MeshType>::LaplacianInfo lpz(CoordType(0, 0, 0), 0); typename vcg::tri::Smooth<MeshType>::LaplacianInfo lpz(CoordType(0, 0, 0), 0);
SimpleTempData<typename MeshType::VertContainer, typename vcg::tri::Smooth<MeshType>::LaplacianInfo> TD(m.vert, lpz); SimpleTempData<typename MeshType::VertContainer, typename vcg::tri::Smooth<MeshType>::LaplacianInfo> TD(m.vert, lpz);
const ScalarType maxDist = (strict) ? params.maxSurfDist / 1000. : params.maxSurfDist;
for (int i = 0; i < step; ++i) for (int i = 0; i < step; ++i)
{ {
TD.Init(lpz); TD.Init(lpz);
vcg::tri::Smooth<MeshType>::AccumulateLaplacianInfo(m, TD, true); vcg::tri::Smooth<MeshType>::AccumulateLaplacianInfo(m, TD, false);
for (auto fi = m.face.begin(); fi != m.face.end(); ++fi) for (auto fi = m.face.begin(); fi != m.face.end(); ++fi)
{ {
@ -1200,8 +1213,11 @@ private:
if (moving) if (moving)
{ {
// const CoordType oldN = vcg::NormalizedTriangleNormal(*fi);
// const CoordType newN = vcg::Normal(newPos[0], newPos[1], newPos[2]).Normalize();
newPos[3] = (newPos[0] + newPos[1] + newPos[2]) / 3.; newPos[3] = (newPos[0] + newPos[1] + newPos[2]) / 3.;
if (!params.surfDistCheck || testHausdorff(*params.mProject, params.grid, newPos, params.maxSurfDist)) if (/*(strict || oldN * newN > 0.99) &&*/ (!params.surfDistCheck || testHausdorff(*params.mProject, params.grid, newPos, maxDist)))
{ {
for (int j = 0; j < 3; ++j) for (int j = 0; j < 3; ++j)
fi->V(j)->P() = newPos[j]; fi->V(j)->P() = newPos[j];
@ -1235,12 +1251,15 @@ private:
if(params.selectedOnly) { if(params.selectedOnly) {
ss.popAnd(); ss.popAnd();
} }
tri::Smooth<MeshType>::VertexCoordPlanarLaplacian(m, 1, math::ToRad(1.0), true); // FoldRelax(m, params, 1, false);
// tri::Smooth<MeshType>::VertexCoordLaplacian(m, 1, true);
tri::Smooth<MeshType>::VertexCoordPlanarLaplacian(m, 1, math::ToRad(1.0), true);
tri::UpdateSelection<MeshType>::VertexClear(m); tri::UpdateSelection<MeshType>::VertexClear(m);
selectVertexFromFold(m, params); selectVertexFromFold(m, params);
FoldRelax(m, params, 3); FoldRelax(m, params, 2);
tri::UpdateSelection<MeshType>::VertexClear(m); tri::UpdateSelection<MeshType>::VertexClear(m);