bug fix on isotropic remeshing collapse strategy

This commit is contained in:
korialis 2020-11-13 15:30:38 +01:00
parent a65010f34d
commit 527953434d
2 changed files with 132 additions and 87 deletions

View File

@ -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<ScalarType> &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 <VertexPointer, bool> toSel;
static int VtoE[3][3] = { -1, 0, 2,
0, -1, 1,
2, 1, -1 };
std::vector<VertexPointer> v2s; v2s.reserve(2);
std::vector<VertexPointer> topVertices; topVertices.reserve(2);
std::vector<VertexPointer> fan1V2S; fan1V2S.reserve(2);
std::vector<VertexPointer> v2s; v2s.reserve(2);
std::map <VertexPointer, bool> 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 " <<std::endl;
if (f.V(((*i).z+1)%3) == c.V(1))
v2s.push_back(f.V(((*i).z+2)%3));
else
v2s.push_back(f.V(((*i).z+1)%3));
}
for(auto i=es.AV01().begin();i!=es.AV01().end();++i)
{
FaceType & f = *((*i).f);
assert(f.V((*i).z) == c.V(0));
vcg::face::VFDetach(f,((*i).z+1)%3);
vcg::face::VFDetach(f,((*i).z+2)%3);
Allocator<TriMeshType>::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<TriMeshType>::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<TriMeshType>::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<TriMeshType>::DeleteVertex(m,*(c.V(0)));
c.V(1)->P()=p;
return n_face_del;
}
};

View File

@ -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<CoordType> 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<CoordType> points(3);
std::vector<CoordType> 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<ScalarType> &mp, Params &params, bool relaxed)
static bool checkCollapseFacesAroundVert1(PosType &p, VertexPair & pair, Point3<ScalarType> &mp, Params &params, 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<ScalarType> &mp, ScalarType minQ, ScalarType maxQ, Params &params, bool relaxed = false)
static bool testCollapse1(PosType &p, VertexPair & pair, Point3<ScalarType> &mp, ScalarType minQ, ScalarType maxQ, Params &params, 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<ScalarType> 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<ScalarType> 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;