Cleaned up the CoM (curve on manifold) class and revised the sample using it
This commit is contained in:
parent
18e424b7c0
commit
c627b31e59
|
@ -39,57 +39,63 @@ struct MyUsedTypes : public UsedTypes<Use<MyVertex>::AsVertexType, Use<MyEdge>::
|
||||||
|
|
||||||
class MyVertex : public Vertex< MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::Qualityf, vertex::Color4b, vertex::VEAdj, vertex::VFAdj,vertex::BitFlags >{};
|
class MyVertex : public Vertex< MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::Qualityf, vertex::Color4b, vertex::VEAdj, vertex::VFAdj,vertex::BitFlags >{};
|
||||||
class MyEdge : public Edge< MyUsedTypes, edge::VertexRef, edge::VEAdj, edge::EEAdj, edge::BitFlags> {};
|
class MyEdge : public Edge< MyUsedTypes, edge::VertexRef, edge::VEAdj, edge::EEAdj, edge::BitFlags> {};
|
||||||
class MyFace : public Face < MyUsedTypes, face::VertexRef, face::Normal3f, face::VFAdj, face::FFAdj, face::Mark, face::Color4b, face::BitFlags > {};
|
class MyFace : public Face < MyUsedTypes, face::VertexRef, face::Normal3f, face::Qualityf, face::Color4b, face::VFAdj, face::FFAdj, face::Mark, face::Color4b, face::BitFlags > {};
|
||||||
class MyMesh : public tri::TriMesh< std::vector<MyVertex>, std::vector<MyEdge>, std::vector<MyFace> >{};
|
class MyMesh : public tri::TriMesh< std::vector<MyVertex>, std::vector<MyEdge>, std::vector<MyFace> >{};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In this sample we take a torus we compute a poly line on it that open it into a disk and we open it.
|
||||||
|
* Then using the COM (Curve On Manifold) framework we smooth this polyline keeping
|
||||||
|
* it on the surface of the torus and then first we refine the torus surface with this
|
||||||
|
* smooth polyline and then we open it along these new edges.
|
||||||
|
*
|
||||||
|
* Optionally you can use your own mesh and polyline by passing them as parameters.
|
||||||
|
*/
|
||||||
int main(int argc,char ** argv )
|
int main(int argc,char ** argv )
|
||||||
{
|
{
|
||||||
MyMesh base, basecopy, poly;
|
MyMesh base, basecopy, poly;
|
||||||
int ret0 = tri::io::Importer<MyMesh>::Open(base,argv[1]);
|
int ret0=0, ret1=0;
|
||||||
int ret1 = 0;
|
if(argc>1) ret0 = tri::io::Importer<MyMesh>::Open(base,argv[1]);
|
||||||
if(argc>2) ret1 = tri::io::Importer<MyMesh>::Open(poly,argv[2]);
|
|
||||||
if(ret0 != 0 || ret1 != 0)
|
|
||||||
{
|
|
||||||
printf("Failed Loading\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(base.FN() == 0) Torus(base,10,4,48,24);
|
||||||
|
|
||||||
|
if(argc>2) ret1 = tri::io::Importer<MyMesh>::Open(poly,argv[2]);
|
||||||
tri::UpdateBounding<MyMesh>::Box(base);
|
tri::UpdateBounding<MyMesh>::Box(base);
|
||||||
printf( "Mesh %s has %i vert and %i faces\n", argv[1], base.VN(), base.FN() );
|
printf( "Mesh %s has %i vert and %i faces\n", argv[1], base.VN(), base.FN() );
|
||||||
printf( "Poly %s has %i vert and %i edges\n", argv[2], poly.VN(), poly.EN() );
|
printf( "Poly %s has %i vert and %i edges\n", argv[2], poly.VN(), poly.EN() );
|
||||||
if(poly.EN()==0) {
|
if(poly.EN() == 0) {
|
||||||
srand(time(0));
|
srand(time(nullptr));
|
||||||
tri::CutTree<MyMesh> ct(base);
|
tri::CutTree<MyMesh> ct(base);
|
||||||
ct.BuildVisitTree(poly,rand()%base.fn);
|
ct.Build(poly,rand()%base.fn);
|
||||||
}
|
}
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(poly,"0_cut_tree.ply",tri::io::Mask::IOM_EDGEINDEX);
|
tri::io::ExporterPLY<MyMesh>::Save(poly,"0_cut_tree.ply",tri::io::Mask::IOM_EDGEINDEX);
|
||||||
|
|
||||||
tri::CoM<MyMesh> cc(base);
|
tri::CoM<MyMesh> cc(base);
|
||||||
cc.Init();
|
cc.Init();
|
||||||
cc.MarkFauxEdgeWithPolyLine(poly);
|
bool ret = cc.TagFaceEdgeSelWithPolyLine(poly);
|
||||||
tri::Append<MyMesh,MyMesh>::MeshCopy(basecopy,base);
|
if(ret)
|
||||||
tri::UpdateTopology<MyMesh>::FaceFace(basecopy);
|
{
|
||||||
tri::CutMeshAlongNonFauxEdges<MyMesh>(basecopy);
|
tri::Append<MyMesh,MyMesh>::MeshCopy(basecopy,base);
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(basecopy,"base_cut_with_tree.ply");
|
tri::UpdateTopology<MyMesh>::FaceFace(basecopy);
|
||||||
|
tri::CutMeshAlongSelectedFaceEdges<MyMesh>(basecopy);
|
||||||
|
tri::io::ExporterPLY<MyMesh>::Save(basecopy,"base_cut_with_tree.ply");
|
||||||
|
}
|
||||||
// Selected vertices are 'locked' during the smoothing.
|
// Selected vertices are 'locked' during the smoothing.
|
||||||
cc.SelectBoundaryVertex(poly);
|
cc.SelectBoundaryVertex(poly);
|
||||||
cc.SelectUniformlyDistributed(poly,20); // lock some vertices uniformly just for fun
|
// cc.SelectUniformlyDistributed(poly,10); // lock some vertices uniformly just for fun
|
||||||
|
|
||||||
// Two smoothing runs,
|
// Two smoothing runs,
|
||||||
// the first that allows fast movement over the surface (long edges that can skim surface details)
|
// the first that allows fast movement over the surface (long edges that can skim surface details)
|
||||||
cc.par.surfDistThr = base.bbox.Diag()/100.0;
|
cc.par.surfDistThr = base.bbox.Diag()/100.0f;
|
||||||
cc.par.maxSimpEdgeLen = base.bbox.Diag()/50.0;
|
cc.par.maxSimpEdgeLen = base.bbox.Diag()/50.0f;
|
||||||
cc.par.minRefEdgeLen = base.bbox.Diag()/100.0;
|
cc.par.minRefEdgeLen = base.bbox.Diag()/100.0f;
|
||||||
cc.SmoothProject(poly,10,0.7,.3);
|
cc.SmoothProject(poly,30,0.7f,.3f);
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(poly,"1_poly_smooth.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
tri::io::ExporterPLY<MyMesh>::Save(poly,"1_poly_smooth.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
||||||
|
|
||||||
// The second smooting run more accurate to adapt to the surface
|
// The second smooting run more accurate to adapt to the surface
|
||||||
cc.par.surfDistThr = base.bbox.Diag()/1000.0;
|
cc.par.surfDistThr = base.bbox.Diag()/1000.0f;
|
||||||
cc.par.maxSimpEdgeLen = base.bbox.Diag()/1000.0;
|
cc.par.maxSimpEdgeLen = base.bbox.Diag()/1000.0f;
|
||||||
cc.par.minRefEdgeLen = base.bbox.Diag()/2000.0;
|
cc.par.minRefEdgeLen = base.bbox.Diag()/2000.0f;
|
||||||
cc.SmoothProject(poly,10,0.01,.99);
|
cc.SmoothProject(poly,10,0.01f,.99f);
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(poly,"2_poly_smooth.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
tri::io::ExporterPLY<MyMesh>::Save(poly,"2_poly_smooth.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
||||||
|
|
||||||
Distribution<float> dist;
|
Distribution<float> dist;
|
||||||
|
@ -102,8 +108,8 @@ int main(int argc,char ** argv )
|
||||||
cc.SplitMeshWithPolyline(poly);
|
cc.SplitMeshWithPolyline(poly);
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(base,"3_mesh_refined.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
tri::io::ExporterPLY<MyMesh>::Save(base,"3_mesh_refined.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
||||||
// Now the two meshes should have coincident edges
|
// Now the two meshes should have coincident edges
|
||||||
cc.MarkFauxEdgeWithPolyLine(poly);
|
cc.TagFaceEdgeSelWithPolyLine(poly);
|
||||||
CutMeshAlongNonFauxEdges(base);
|
CutMeshAlongSelectedFaceEdges(base);
|
||||||
tri::io::ExporterPLY<MyMesh>::Save(base,"4_mesh_cut.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
tri::io::ExporterPLY<MyMesh>::Save(base,"4_mesh_cut.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -184,9 +184,9 @@ public:
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool MarkFauxEdgeWithPolyLine(MeshType &poly,bool markFlag=true)
|
bool TagFaceEdgeSelWithPolyLine(MeshType &poly,bool markFlag=true)
|
||||||
{
|
{
|
||||||
if(markFlag) tri::UpdateFlags<MeshType>::FaceSetF(base);
|
if(markFlag) tri::UpdateFlags<MeshType>::FaceClearFaceEdgeS(base);
|
||||||
tri::UpdateTopology<MeshType>::VertexFace(base);
|
tri::UpdateTopology<MeshType>::VertexFace(base);
|
||||||
tri::UpdateTopology<MeshType>::FaceFace(base);
|
tri::UpdateTopology<MeshType>::FaceFace(base);
|
||||||
|
|
||||||
|
@ -210,8 +210,8 @@ public:
|
||||||
if(ret){
|
if(ret){
|
||||||
assert(ret);
|
assert(ret);
|
||||||
assert(ff0->V(e0)==v0 || ff0->V(e0)==v1);
|
assert(ff0->V(e0)==v0 || ff0->V(e0)==v1);
|
||||||
ff0->ClearF(e0);
|
ff0->SetFaceEdgeS(e0);
|
||||||
ff1->ClearF(e1);
|
ff1->SetFaceEdgeS(e1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
#ifndef CUT_TREE_H
|
#ifndef CUT_TREE_H
|
||||||
#define CUT_TREE_H
|
#define CUT_TREE_H
|
||||||
|
|
||||||
|
#include<vcg/complex/complex.h>
|
||||||
|
#include <vcg/space/index/kdtree/kdtree.h>
|
||||||
|
#include<vcg/complex/algorithms/update/quality.h>
|
||||||
|
#include<vcg/complex/algorithms/update/color.h>
|
||||||
|
|
||||||
namespace vcg {
|
namespace vcg {
|
||||||
namespace tri {
|
namespace tri {
|
||||||
|
|
||||||
|
@ -40,19 +45,18 @@ public:
|
||||||
typedef typename MeshType::FaceType FaceType;
|
typedef typename MeshType::FaceType FaceType;
|
||||||
typedef typename MeshType::FacePointer FacePointer;
|
typedef typename MeshType::FacePointer FacePointer;
|
||||||
typedef typename MeshType::FaceIterator FaceIterator;
|
typedef typename MeshType::FaceIterator FaceIterator;
|
||||||
typedef Box3 <ScalarType> Box3Type;
|
typedef Box3<ScalarType> Box3Type;
|
||||||
typedef typename vcg::GridStaticPtr<FaceType, ScalarType> MeshGrid;
|
|
||||||
typedef typename vcg::GridStaticPtr<EdgeType, ScalarType> EdgeGrid;
|
|
||||||
typedef typename face::Pos<FaceType> PosType;
|
typedef typename face::Pos<FaceType> PosType;
|
||||||
typedef typename tri::UpdateTopology<MeshType>::PEdge PEdge;
|
typedef typename tri::UpdateTopology<MeshType>::PEdge PEdge;
|
||||||
|
|
||||||
MeshType &base;
|
MeshType &base;
|
||||||
// MeshGrid uniformGrid;
|
|
||||||
|
|
||||||
// Param par;
|
|
||||||
CutTree(MeshType &_m) :base(_m){}
|
CutTree(MeshType &_m) :base(_m){}
|
||||||
|
|
||||||
|
|
||||||
|
// Perform a simple optimization of the three applying simple shortcuts:
|
||||||
|
// if the endpoints of two consecutive edges are connected by an edge existing on base mesh just use that edges
|
||||||
|
|
||||||
void OptimizeTree(KdTree<ScalarType> &kdtree, MeshType &t)
|
void OptimizeTree(KdTree<ScalarType> &kdtree, MeshType &t)
|
||||||
{
|
{
|
||||||
tri::Allocator<MeshType>::CompactEveryVector(t);
|
tri::Allocator<MeshType>::CompactEveryVector(t);
|
||||||
|
@ -67,7 +71,7 @@ void OptimizeTree(KdTree<ScalarType> &kdtree, MeshType &t)
|
||||||
{
|
{
|
||||||
std::vector<VertexType *> starVec;
|
std::vector<VertexType *> starVec;
|
||||||
edge::VVStarVE(&*vi,starVec);
|
edge::VVStarVE(&*vi,starVec);
|
||||||
if(starVec.size()==2)
|
if(starVec.size()==2) // middle vertex has to be 1-manifold
|
||||||
{
|
{
|
||||||
PosType pos;
|
PosType pos;
|
||||||
if(ExistEdge(kdtree,starVec[0]->P(),starVec[1]->P(),pos))
|
if(ExistEdge(kdtree,starVec[0]->P(),starVec[1]->P(),pos))
|
||||||
|
@ -181,10 +185,10 @@ void Retract(KdTree<ScalarType> &kdtree, MeshType &t)
|
||||||
if(fpos.IsBorder()) {
|
if(fpos.IsBorder()) {
|
||||||
t.edge[i].SetV();
|
t.edge[i].SetV();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else assert(0);
|
else assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the boundary edges are in the initial tree so the clean boundary loops chains remains as irreducible loops
|
// All the boundary edges are in the initial tree so the clean boundary loops chains remains as irreducible loops
|
||||||
// We delete them (leaving dangling edges with a vertex on the boundary)
|
// We delete them (leaving dangling edges with a vertex on the boundary)
|
||||||
for(size_t i =0; i<t.edge.size();++i){
|
for(size_t i =0; i<t.edge.size();++i){
|
||||||
|
@ -196,6 +200,143 @@ void Retract(KdTree<ScalarType> &kdtree, MeshType &t)
|
||||||
tri::Allocator<MeshType>::CompactEveryVector(t);
|
tri::Allocator<MeshType>::CompactEveryVector(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Main function
|
||||||
|
*
|
||||||
|
* It builds a cut tree that open the mesh into a topological disk
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Build(MeshType &dualMesh, int startingFaceInd=0)
|
||||||
|
{
|
||||||
|
tri::UpdateTopology<MeshType>::FaceFace(base);
|
||||||
|
tri::UpdateTopology<MeshType>::VertexFace(base);
|
||||||
|
|
||||||
|
BuildVisitTree(dualMesh,startingFaceInd);
|
||||||
|
// BuildDijkstraVisitTree(dualMesh,startingFaceInd);
|
||||||
|
|
||||||
|
VertexConstDataWrapper<MeshType > vdw(base);
|
||||||
|
KdTree<ScalarType> kdtree(vdw);
|
||||||
|
Retract(kdtree,dualMesh);
|
||||||
|
OptimizeTree(kdtree, dualMesh);
|
||||||
|
tri::UpdateBounding<MeshType>::Box(dualMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auxiliary class for keeping the heap of vertices to visit and their estimated distance */
|
||||||
|
struct FaceDist{
|
||||||
|
FaceDist(FacePointer _f):f(_f),dist(_f->Q()){}
|
||||||
|
FacePointer f;
|
||||||
|
ScalarType dist;
|
||||||
|
bool operator < (const FaceDist &o) const
|
||||||
|
{
|
||||||
|
if( dist != o.dist)
|
||||||
|
return dist > o.dist;
|
||||||
|
return f<o.f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void BuildDijkstraVisitTree(MeshType &dualMesh, int startingFaceInd=0, ScalarType maxDistanceThr=std::numeric_limits<ScalarType>::max())
|
||||||
|
{
|
||||||
|
tri::RequireFFAdjacency(base);
|
||||||
|
tri::RequirePerFaceMark(base);
|
||||||
|
tri::RequirePerFaceQuality(base);
|
||||||
|
typename MeshType::template PerFaceAttributeHandle<FacePointer> parentHandle
|
||||||
|
= tri::Allocator<MeshType>::template GetPerFaceAttribute<FacePointer>(base, "parent");
|
||||||
|
|
||||||
|
std::vector<FacePointer> seedVec;
|
||||||
|
seedVec.push_back(&base.face[startingFaceInd]);
|
||||||
|
|
||||||
|
std::vector<FaceDist> Heap;
|
||||||
|
tri::UnMarkAll(base);
|
||||||
|
tri::UpdateQuality<MeshType>::FaceConstant(base,0);
|
||||||
|
ForEachVertex(base, [&](VertexType &v){
|
||||||
|
tri::Allocator<MeshType>::AddVertex(dualMesh,v.cP());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize the face heap;
|
||||||
|
// All faces in the heap are already marked; Q() store the distance from the source faces;
|
||||||
|
for(size_t i=0;i<seedVec.size();++i)
|
||||||
|
{
|
||||||
|
seedVec[i]->Q()=0;
|
||||||
|
Heap.push_back(FaceDist(seedVec[i]));
|
||||||
|
}
|
||||||
|
// Main Loop
|
||||||
|
int boundary=0;
|
||||||
|
std::make_heap(Heap.begin(),Heap.end());
|
||||||
|
|
||||||
|
int vCnt=0;
|
||||||
|
int eCnt=0;
|
||||||
|
int fCnt=0;
|
||||||
|
|
||||||
|
// The main idea is that in the heap we maintain all the faces to be visited.
|
||||||
|
int nonDiskCnt=0;
|
||||||
|
while(!Heap.empty() && nonDiskCnt<10)
|
||||||
|
{
|
||||||
|
int eulerChi= vCnt-eCnt+fCnt;
|
||||||
|
if(eulerChi==1) nonDiskCnt=0;
|
||||||
|
else ++nonDiskCnt;
|
||||||
|
// printf("HeapSize %i: %i - %i + %i = %i\n",Heap.size(), vCnt,eCnt,fCnt,eulerChi);
|
||||||
|
pop_heap(Heap.begin(),Heap.end());
|
||||||
|
FacePointer currFp = (Heap.back()).f;
|
||||||
|
if(tri::IsMarked(base,currFp))
|
||||||
|
{
|
||||||
|
// printf("Found an already visited face %f %f \n",Heap.back().dist, Heap.back().f->Q());
|
||||||
|
//assert(Heap.back().dist != currFp->Q());
|
||||||
|
|
||||||
|
Heap.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Heap.pop_back();
|
||||||
|
++fCnt;
|
||||||
|
eCnt+=3;
|
||||||
|
tri::Mark(base,currFp);
|
||||||
|
|
||||||
|
// printf("pop face %i \n", tri::Index(base,currFp));
|
||||||
|
for(int i=0;i<3;++i)
|
||||||
|
{
|
||||||
|
if(!currFp->V(i)->IsV()) {++vCnt; currFp->V(i)->SetV();}
|
||||||
|
|
||||||
|
FacePointer nextFp = currFp->FFp(i);
|
||||||
|
if( tri::IsMarked(base,nextFp) )
|
||||||
|
{
|
||||||
|
eCnt-=1;
|
||||||
|
printf("is marked\n");
|
||||||
|
if(nextFp != parentHandle[currFp] )
|
||||||
|
{
|
||||||
|
if(currFp>nextFp){
|
||||||
|
tri::Allocator<MeshType>::AddEdge(dualMesh,tri::Index(base,currFp->V0(i)), tri::Index(base,currFp->V1(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // add it to the heap;
|
||||||
|
{
|
||||||
|
// printf("is NOT marked\n");
|
||||||
|
parentHandle[nextFp] = currFp;
|
||||||
|
ScalarType nextDist = currFp->Q() + Distance(Barycenter(*currFp),Barycenter(*nextFp));
|
||||||
|
int adjMarkedNum=0;
|
||||||
|
for(int k=0;k<3;++k) if(tri::IsMarked(base,nextFp->FFp(k))) ++adjMarkedNum;
|
||||||
|
if(nextDist < maxDistanceThr || adjMarkedNum>1)
|
||||||
|
{
|
||||||
|
nextFp->Q() = nextDist;
|
||||||
|
Heap.push_back(FaceDist(nextFp));
|
||||||
|
push_heap(Heap.begin(),Heap.end());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// printf("boundary %i\n",++boundary);
|
||||||
|
tri::Allocator<MeshType>::AddEdge(dualMesh,tri::Index(base,currFp->V0(i)), tri::Index(base,currFp->V1(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End while
|
||||||
|
printf("fulltree %i vn %i en \n",dualMesh.vn, dualMesh.en);
|
||||||
|
int dupVert=tri::Clean<MeshType>::RemoveDuplicateVertex(dualMesh,false); printf("Removed %i dup vert\n",dupVert);
|
||||||
|
int dupEdge=tri::Clean<MeshType>::RemoveDuplicateEdge(dualMesh); printf("Removed %i dup edges %i\n",dupEdge,dualMesh.EN());
|
||||||
|
tri::Clean<MeshType>::RemoveUnreferencedVertex(dualMesh);
|
||||||
|
|
||||||
|
tri::io::ExporterPLY<MeshType>::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX);
|
||||||
|
tri::UpdateColor<MeshType>::PerFaceQualityRamp(base);
|
||||||
|
tri::io::ExporterPLY<MeshType>::Save(base,"colored_Bydistance.ply",tri::io::Mask::IOM_FACECOLOR);
|
||||||
|
}
|
||||||
|
|
||||||
// \brief This function build a cut tree.
|
// \brief This function build a cut tree.
|
||||||
//
|
//
|
||||||
|
@ -207,9 +348,6 @@ void Retract(KdTree<ScalarType> &kdtree, MeshType &t)
|
||||||
|
|
||||||
void BuildVisitTree(MeshType &dualMesh, int startingFaceInd=0)
|
void BuildVisitTree(MeshType &dualMesh, int startingFaceInd=0)
|
||||||
{
|
{
|
||||||
tri::UpdateTopology<MeshType>::FaceFace(base);
|
|
||||||
tri::UpdateTopology<MeshType>::VertexFace(base);
|
|
||||||
|
|
||||||
tri::UpdateFlags<MeshType>::FaceClearV(base);
|
tri::UpdateFlags<MeshType>::FaceClearV(base);
|
||||||
tri::UpdateFlags<MeshType>::VertexBorderFromFaceAdj(base);
|
tri::UpdateFlags<MeshType>::VertexBorderFromFaceAdj(base);
|
||||||
std::vector<face::Pos<FaceType> > visitStack; // the stack contain the pos on the 'starting' face.
|
std::vector<face::Pos<FaceType> > visitStack; // the stack contain the pos on the 'starting' face.
|
||||||
|
@ -243,16 +381,9 @@ void BuildVisitTree(MeshType &dualMesh, int startingFaceInd=0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(cnt==base.fn);
|
assert(cnt==base.fn);
|
||||||
|
|
||||||
VertexConstDataWrapper<MeshType > vdw(base);
|
|
||||||
KdTree<ScalarType> kdtree(vdw);
|
|
||||||
|
|
||||||
tri::Clean<MeshType>::RemoveDuplicateVertex(dualMesh);
|
tri::Clean<MeshType>::RemoveDuplicateVertex(dualMesh);
|
||||||
// tri::io::ExporterPLY<MeshType>::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX);
|
tri::io::ExporterPLY<MeshType>::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX);
|
||||||
|
|
||||||
Retract(kdtree,dualMesh);
|
|
||||||
OptimizeTree(kdtree, dualMesh);
|
|
||||||
tri::UpdateBounding<MeshType>::Box(dualMesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue