complete rework of the crease preserving strategy for isotropic_remeshing & removed manifoldness constraint.
Small patch in edge_collapse adding a parameter to do (default=false) for crease information preservation after collapse Added refineMidpoint in refine to perform midpoint refinement without manifoldness constraints
This commit is contained in:
parent
1b1023179f
commit
795f5473d6
|
|
@ -209,16 +209,38 @@ public:
|
||||||
// Main Collapsing Function: the one that actually performs the collapse of the edge denoted by the VertexPair c
|
// Main Collapsing Function: the one that actually performs the collapse of the edge denoted by the VertexPair c
|
||||||
// Remember that v[0] will be deleted and v[1] will survive with the position indicated by p
|
// Remember that v[0] will be deleted and v[1] will survive with the position indicated by p
|
||||||
// To do a collapse onto a vertex simply pass p as the position of the surviving vertex
|
// 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)
|
static int Do(TriMeshType &m, VertexPair & c, const Point3<ScalarType> &p, const bool preserveFaceEdgeS = false)
|
||||||
{
|
{
|
||||||
EdgeSet es;
|
EdgeSet es;
|
||||||
FindSets(c,es);
|
FindSets(c,es);
|
||||||
|
|
||||||
int n_face_del=0 ;
|
int n_face_del=0 ;
|
||||||
|
|
||||||
|
static int VtoE[3][3] = { -1, 0, 2,
|
||||||
|
0, -1, 1,
|
||||||
|
2, 1, -1 };
|
||||||
|
|
||||||
|
// bool toSel = false;
|
||||||
|
|
||||||
|
VertexType* top[2];
|
||||||
|
std::map <VertexPointer, bool> toSel;
|
||||||
|
|
||||||
|
std::vector<VertexPointer> v2s; v2s.reserve(2);
|
||||||
|
|
||||||
for(auto i=es.AV01().begin();i!=es.AV01().end();++i)
|
for(auto i=es.AV01().begin();i!=es.AV01().end();++i)
|
||||||
{
|
{
|
||||||
FaceType & f = *((*i).f);
|
FaceType & f = *((*i).f);
|
||||||
assert(f.V((*i).z) == c.V(0));
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
vcg::face::VFDetach(f,((*i).z+1)%3);
|
vcg::face::VFDetach(f,((*i).z+1)%3);
|
||||||
vcg::face::VFDetach(f,((*i).z+2)%3);
|
vcg::face::VFDetach(f,((*i).z+2)%3);
|
||||||
Allocator<TriMeshType>::DeleteFace(m,f);
|
Allocator<TriMeshType>::DeleteFace(m,f);
|
||||||
|
|
@ -231,11 +253,30 @@ public:
|
||||||
// - we prepend that face to the list of the faces incident on 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)
|
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->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->VFp((*i).z) = c.V(1)->VFp();
|
||||||
(*i).f->VFi((*i).z) = c.V(1)->VFi();
|
(*i).f->VFi((*i).z) = c.V(1)->VFi();
|
||||||
c.V(1)->VFp() = (*i).f;
|
c.V(1)->VFp() = (*i).f;
|
||||||
c.V(1)->VFi() = (*i).z;
|
c.V(1)->VFi() = (*i).z;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator<TriMeshType>::DeleteVertex(m,*(c.V(0)));
|
Allocator<TriMeshType>::DeleteVertex(m,*(c.V(0)));
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1049,6 +1049,234 @@ void TrivialMidPointRefine(MeshType & m)
|
||||||
Allocator<MeshType>::CompactEveryVector(m);
|
Allocator<MeshType>::CompactEveryVector(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class MESH_TYPE, class EDGEPRED>
|
||||||
|
bool RefineMidpoint(MESH_TYPE &m, EDGEPRED &ep, bool RefineSelected=false, CallBackPos *cb = 0)
|
||||||
|
{
|
||||||
|
// common typenames
|
||||||
|
typedef typename MESH_TYPE::VertexIterator VertexIterator;
|
||||||
|
typedef typename MESH_TYPE::FaceIterator FaceIterator;
|
||||||
|
typedef typename MESH_TYPE::VertexPointer VertexPointer;
|
||||||
|
typedef typename MESH_TYPE::FacePointer FacePointer;
|
||||||
|
typedef typename MESH_TYPE::FaceType FaceType;
|
||||||
|
typedef typename MESH_TYPE::FaceType::TexCoordType TexCoordType;
|
||||||
|
|
||||||
|
assert(tri::HasFFAdjacency(m));
|
||||||
|
tri::UpdateFlags<MESH_TYPE>::FaceBorderFromFF(m);
|
||||||
|
typedef face::Pos<FaceType> PosType;
|
||||||
|
|
||||||
|
int j,NewVertNum=0,NewFaceNum=0;
|
||||||
|
|
||||||
|
typedef RefinedFaceData<VertexPointer> RFD;
|
||||||
|
typedef typename MESH_TYPE :: template PerFaceAttributeHandle<RFD> HandleType;
|
||||||
|
HandleType RD = tri::Allocator<MESH_TYPE>:: template AddPerFaceAttribute<RFD> (m,std::string("RefineData"));
|
||||||
|
|
||||||
|
MidPoint<MESH_TYPE> mid(&m);
|
||||||
|
// Callback stuff
|
||||||
|
int step=0;
|
||||||
|
int PercStep=std::max(1,m.fn/33);
|
||||||
|
|
||||||
|
// First Loop: We analyze the mesh to compute the number of the new faces and new vertices
|
||||||
|
FaceIterator fi;
|
||||||
|
for(fi=m.face.begin(),j=0;fi!=m.face.end();++fi) if(!(*fi).IsD())
|
||||||
|
{
|
||||||
|
if(cb && (++step%PercStep)==0) (*cb)(step/PercStep,"Refining...");
|
||||||
|
// skip unselected faces if necessary
|
||||||
|
if(RefineSelected && !(*fi).IsS()) continue;
|
||||||
|
|
||||||
|
for(j=0;j<3;j++)
|
||||||
|
{
|
||||||
|
if(RD[fi].ep[j]) continue;
|
||||||
|
|
||||||
|
PosType edgeCur(&*fi,j);
|
||||||
|
if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue;
|
||||||
|
if(!ep(edgeCur)) continue;
|
||||||
|
|
||||||
|
RD[edgeCur.F()].ep[edgeCur.E()]=true;
|
||||||
|
++NewFaceNum;
|
||||||
|
++NewVertNum;
|
||||||
|
PosType start = edgeCur;
|
||||||
|
if (!edgeCur.IsBorder())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
edgeCur.NextF();
|
||||||
|
edgeCur.F()->SetV();
|
||||||
|
RD[edgeCur.F()].ep[edgeCur.E()] = true;
|
||||||
|
++NewFaceNum;
|
||||||
|
} while (edgeCur != start);
|
||||||
|
--NewFaceNum; //start is counted twice (could remove the first increment above)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end face loop
|
||||||
|
|
||||||
|
if(NewVertNum ==0 )
|
||||||
|
{
|
||||||
|
tri::Allocator<MESH_TYPE> :: template DeletePerFaceAttribute<RefinedFaceData<VertexPointer> > (m,RD);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
VertexIterator lastv = tri::Allocator<MESH_TYPE>::AddVertices(m,NewVertNum);
|
||||||
|
|
||||||
|
// Secondo loop: We initialize a edge->vertex map
|
||||||
|
|
||||||
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
||||||
|
{
|
||||||
|
if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining...");
|
||||||
|
for(j=0;j<3;j++)
|
||||||
|
{
|
||||||
|
// skip unselected faces if necessary
|
||||||
|
if(RefineSelected && !(*fi).IsS()) continue;
|
||||||
|
for(j=0;j<3;j++)
|
||||||
|
{
|
||||||
|
PosType edgeCur(&*fi,j);
|
||||||
|
if(RefineSelected && ! edgeCur.FFlip()->IsS()) continue;
|
||||||
|
|
||||||
|
if( RD[edgeCur.F()].ep[edgeCur.E()] && RD[edgeCur.F()].vp[edgeCur.E()] ==0 )
|
||||||
|
{
|
||||||
|
RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv;
|
||||||
|
mid(*lastv,edgeCur);
|
||||||
|
PosType start = edgeCur;
|
||||||
|
if (!edgeCur.IsBorder())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
edgeCur.NextF();
|
||||||
|
assert(RD[edgeCur.F()].ep[edgeCur.E()]);
|
||||||
|
RD[edgeCur.F()].vp[edgeCur.E()] = &*lastv;
|
||||||
|
} while (edgeCur != start);
|
||||||
|
}
|
||||||
|
++lastv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(lastv==m.vert.end()); // critical assert: we MUST have used all the vertex that we forecasted we need
|
||||||
|
|
||||||
|
FaceIterator lastf = tri::Allocator<MESH_TYPE>::AddFaces(m,NewFaceNum);
|
||||||
|
FaceIterator oldendf = lastf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* v0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* f0
|
||||||
|
*
|
||||||
|
* mp01 f3 mp02
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* f1 f2
|
||||||
|
*
|
||||||
|
*v1 mp12 v2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
VertexPointer vv[6]; // The six vertices that arise in the single triangle splitting
|
||||||
|
// 0..2 Original triangle vertices
|
||||||
|
// 3..5 mp01, mp12, mp20 midpoints of the three edges
|
||||||
|
FacePointer nf[4]; // The (up to) four faces that are created.
|
||||||
|
|
||||||
|
TexCoordType wtt[6]; // per ogni faccia sono al piu' tre i nuovi valori
|
||||||
|
// di texture per wedge (uno per ogni edge)
|
||||||
|
|
||||||
|
int fca=0;
|
||||||
|
for(fi=m.face.begin();fi!=oldendf;++fi) if(!(*fi).IsD())
|
||||||
|
{
|
||||||
|
if(cb && (++step%PercStep)==0)
|
||||||
|
(*cb)(step/PercStep,"Refining...");
|
||||||
|
vv[0]=(*fi).V(0);
|
||||||
|
vv[1]=(*fi).V(1);
|
||||||
|
vv[2]=(*fi).V(2);
|
||||||
|
vv[3] = RD[fi].vp[0];
|
||||||
|
vv[4] = RD[fi].vp[1];
|
||||||
|
vv[5] = RD[fi].vp[2];
|
||||||
|
|
||||||
|
int ind = ((vv[3] != NULL) ? 1 : 0) + ((vv[4] != NULL) ? 2 : 0) + ((vv[5] != NULL) ? 4 : 0);
|
||||||
|
|
||||||
|
nf[0]=&*fi;
|
||||||
|
int i;
|
||||||
|
for(i=1;i<SplitTab[ind].TriNum;++i){
|
||||||
|
nf[i]=&*lastf; ++lastf; fca++;
|
||||||
|
if(RefineSelected || (*fi).IsS()) (*nf[i]).SetS();
|
||||||
|
nf[i]->ImportData(*fi);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(tri::HasPerWedgeTexCoord(m))
|
||||||
|
for(i=0;i<3;++i)
|
||||||
|
{
|
||||||
|
wtt[i]=(*fi).WT(i);
|
||||||
|
wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3));
|
||||||
|
}
|
||||||
|
|
||||||
|
int orgflag = (*fi).Flags();
|
||||||
|
for (i=0; i<SplitTab[ind].TriNum; ++i)
|
||||||
|
for(j=0;j<3;++j)
|
||||||
|
{
|
||||||
|
(*nf[i]).V(j)=&*vv[SplitTab[ind].TV[i][j]];
|
||||||
|
|
||||||
|
if(tri::HasPerWedgeTexCoord(m)) //analogo ai vertici...
|
||||||
|
(*nf[i]).WT(j) = wtt[SplitTab[ind].TV[i][j]];
|
||||||
|
|
||||||
|
assert((*nf[i]).V(j)!=0);
|
||||||
|
if(SplitTab[ind].TE[i][j]!=3)
|
||||||
|
{
|
||||||
|
if(orgflag & (MESH_TYPE::FaceType::BORDER0<<(SplitTab[ind].TE[i][j])))
|
||||||
|
(*nf[i]).SetB(j);
|
||||||
|
else
|
||||||
|
(*nf[i]).ClearB(j);
|
||||||
|
|
||||||
|
if(orgflag & (MESH_TYPE::FaceType::FACEEDGESEL0<<(SplitTab[ind].TE[i][j])))
|
||||||
|
(*nf[i]).SetFaceEdgeS(j);
|
||||||
|
else
|
||||||
|
(*nf[i]).ClearFaceEdgeS(j);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*nf[i]).ClearB(j);
|
||||||
|
(*nf[i]).ClearFaceEdgeS(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SplitTab[ind].TriNum==3 &&
|
||||||
|
SquaredDistance(vv[SplitTab[ind].swap[0][0]]->P(),vv[SplitTab[ind].swap[0][1]]->P()) <
|
||||||
|
SquaredDistance(vv[SplitTab[ind].swap[1][0]]->P(),vv[SplitTab[ind].swap[1][1]]->P()) )
|
||||||
|
{ // swap the last two triangles
|
||||||
|
(*nf[2]).V(1)=(*nf[1]).V(0);
|
||||||
|
(*nf[1]).V(1)=(*nf[2]).V(0);
|
||||||
|
if(tri::HasPerWedgeTexCoord(m)){ //swap also textures coordinates
|
||||||
|
(*nf[2]).WT(1)=(*nf[1]).WT(0);
|
||||||
|
(*nf[1]).WT(1)=(*nf[2]).WT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*nf[1]).IsB(0)) (*nf[2]).SetB(1); else (*nf[2]).ClearB(1);
|
||||||
|
if((*nf[2]).IsB(0)) (*nf[1]).SetB(1); else (*nf[1]).ClearB(1);
|
||||||
|
(*nf[1]).ClearB(0);
|
||||||
|
(*nf[2]).ClearB(0);
|
||||||
|
|
||||||
|
if((*nf[1]).IsFaceEdgeS(0)) (*nf[2]).SetFaceEdgeS(1); else (*nf[2]).ClearFaceEdgeS(1);
|
||||||
|
if((*nf[2]).IsFaceEdgeS(0)) (*nf[1]).SetFaceEdgeS(1); else (*nf[1]).ClearFaceEdgeS(1);
|
||||||
|
(*nf[1]).ClearFaceEdgeS(0);
|
||||||
|
(*nf[2]).ClearFaceEdgeS(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(lastf==m.face.end()); // critical assert: we MUST have used all the faces that we forecasted we need and that we previously allocated.
|
||||||
|
assert(!m.vert.empty());
|
||||||
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()){
|
||||||
|
assert((*fi).V(0)>=&*m.vert.begin() && (*fi).V(0)<=&m.vert.back() );
|
||||||
|
assert((*fi).V(1)>=&*m.vert.begin() && (*fi).V(1)<=&m.vert.back() );
|
||||||
|
assert((*fi).V(2)>=&*m.vert.begin() && (*fi).V(2)<=&m.vert.back() );
|
||||||
|
}
|
||||||
|
tri::UpdateTopology<MESH_TYPE>::FaceFace(m);
|
||||||
|
|
||||||
|
tri::Allocator<MESH_TYPE> :: template DeletePerFaceAttribute<RefinedFaceData<VertexPointer> > (m,RD);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tri
|
} // namespace tri
|
||||||
} // namespace vcg
|
} // namespace vcg
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue