diff --git a/vcg/complex/algorithms/curve_on_manifold.h b/vcg/complex/algorithms/curve_on_manifold.h index 8d5115ed..2be2707e 100644 --- a/vcg/complex/algorithms/curve_on_manifold.h +++ b/vcg/complex/algorithms/curve_on_manifold.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace vcg { namespace tri { @@ -53,6 +54,7 @@ class CoM { public: typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexIterator VertexIterator; @@ -82,10 +84,10 @@ public: void Default(MeshType &m) { - surfDistThr = m.bbox.Diag()/50000.0; + surfDistThr = m.bbox.Diag()/1000.0; polyDistThr = m.bbox.Diag()/5000.0; minRefEdgeLen = m.bbox.Diag()/16000.0; - maxSimpEdgeLen = m.bbox.Diag()/10000.0; + maxSimpEdgeLen = m.bbox.Diag()/1000.0; maxSmoothDelta = m.bbox.Diag()/100.0; maxSnapThr = m.bbox.Diag()/10000.0; gridBailout = m.bbox.Diag()/20.0; @@ -106,6 +108,7 @@ public: MeshType &base; MeshGrid uniformGrid; + Param par; CoM(MeshType &_m) :base(_m),par(_m){} @@ -130,14 +133,74 @@ public: return cnt; } + // Given two points return true if on the base mesh there exist an edge with that two coords + // if return true the pos indicate the found edge. + bool ExistEdge(KdTree &kdtree, CoordType &p0, CoordType &p1, PosType &fpos) + { + ScalarType locEps = SquaredDistance(p0,p1)/100000.0; + + VertexType *v0=0,*v1=0; + unsigned int veInd; + ScalarType sqdist; + kdtree.doQueryClosest(p0,veInd,sqdist); + if(sqdist vfi(v0); + while(!vfi.End()) + { + if(vfi.V1()==v1) + { + fpos = PosType(vfi.F(),vfi.I(), v0); + return true; + } + if(vfi.V2()==v1) + { + fpos = PosType(vfi.F(),(vfi.I()+1)%3, v1); + return true; + } + ++vfi; + } + } + return false; + } + + bool OptimizeTree(MeshType &t) + { + tri::Allocator::CompactEveryVector(t); + tri::UpdateTopology::VertexEdge(t); + tri::UpdateTopology::VertexFace(base); + VertexConstDataWrapper vdw(base); + KdTree kdtree(vdw); + + // First simple loop that search for 2->1 moves. + for(VertexIterator vi=t.vert.begin();vi!=t.vert.end();++vi) + { + std::vector starVec; + edge::VVStarVE(&*vi,starVec); + if(starVec.size()==2) + { + PosType pos; + if(ExistEdge(kdtree,starVec[0]->P(),starVec[1]->P(),pos)) + edge::VEEdgeCollapse(t,&*vi); + } + } + return (t.en < t.edge.size()); + } + void Retract(MeshType &t) { tri::Clean::RemoveDuplicateVertex(t); - printf("Retracting a mesh of %i edges and %i vertices\n",t.en,t.vn); + printf("Retracting a tree of %i edges and %i vertices\n",t.en,t.vn); tri::UpdateTopology::VertexEdge(t); std::stack vertStack; + // Put on the stack all the vertex with just a single incident edge. for(VertexIterator vi=t.vert.begin();vi!=t.vert.end();++vi) { std::vector starVec; @@ -148,8 +211,9 @@ public: tri::UpdateFlags::EdgeClearV(t); tri::UpdateFlags::VertexClearV(t); - - while(!vertStack.empty()) + + int unvisitedEdgeNum = t.en; + while((!vertStack.empty()) && (unvisitedEdgeNum > 2) ) { VertexType *vp = vertStack.top(); vertStack.pop(); @@ -161,24 +225,25 @@ public: { assert(!ep->IsV()); ep->SetV(); + --unvisitedEdgeNum; VertexType *otherVertP; if(ep->V(0)==vp) otherVertP = ep->V(1); else otherVertP = ep->V(0); vertStack.push(otherVertP); } } + assert(unvisitedEdgeNum >0); for(size_t i =0; i::DeleteEdge(t,t.edge[i]); - + assert(t.en >0); tri::Clean::RemoveUnreferencedVertex(t); tri::Allocator::CompactEveryVector(t); } void CleanSpuriousDanglingEdges(MeshType &poly) - { - + { EdgeGrid edgeGrid; edgeGrid.Set(poly.edge.begin(), poly.edge.end()); std::vector< std::pair > mergeVec; @@ -249,10 +314,17 @@ public: } Allocator::CompactEveryVector(base); - - } - // + + + // \brief This function build a cut tree. + // + // First we make a bread first FF face visit. + // Each time that we encounter a visited face we cut add to the tree the edge + // that brings to the already visited face. + // this structure build a dense graph and we retract this graph retracting each + // leaf until we remains with just the loops that cuts the object. + void BuildVisitTree(MeshType &dualMesh) { tri::UpdateTopology::FaceFace(base); @@ -295,7 +367,84 @@ public: assert(cnt==base.fn); Retract(dualMesh); -} +} + + /* + * Given a mesh and a polyline whose edges are a subset of edges of m + * This function marks the edges of m as non-faux when they coincide with the polyline ones. + * + * Use this function toghether with the CutMeshAlongCrease function to actually cut the mesh. + */ + + void MarkFauxEdgeWithPolyLine(MeshType &m, MeshType &e) + { + tri::UpdateFlags::FaceSetF(m); + tri::UpdateTopology::VertexEdge(e); + VertexConstDataWrapper vdw(e); + KdTree edgeTree(vdw); + + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + for(int i=0;i<3;++i) + { + ScalarType locEps = SquaredDistance(fi->P0(i), fi->P1(i))/100000.0; + unsigned int veInd; + ScalarType sqdist; + edgeTree.doQueryClosest(fi->P(i),veInd,sqdist); + if(sqdist starVecVp; + edge::VVStarVE(&(e.vert[veInd]),starVecVp); + for(size_t j=0;jP(),fi->P1(i))< locEps) + fi->ClearF(i); + } + } + } + } + + } + + + + + void SnapPolyline(MeshType &t) + { + printf("Selected vert num %i\n",tri::UpdateSelection::VertexCount(t)); + + tri::UpdateFlags::VertexClearS(base); + tri::UpdateFlags::VertexClearS(t); + tri::Allocator::CompactEveryVector(t); + VertexConstDataWrapper vdw(base); + KdTree kdtree(vdw); + + for(VertexIterator vi=t.vert.begin();vi!=t.vert.end();++vi) + { + unsigned int veInd; + ScalarType sqdist; + kdtree.doQueryClosest(vi->P(),veInd,sqdist); + VertexPointer vp = &base.vert[veInd]; + if(!vp->IsS()) + { + ScalarType dist = sqrt(sqdist); + std::vector starVecVp; + face::VVStarVF(vp,starVecVp); + ScalarType minEdgeLen = std::numeric_limits::max(); + for(int i=0;iP(),starVecVp[i]->P()),minEdgeLen); + if(dist < minEdgeLen/3.0) + { + vi->P() = vp->P(); + vi->SetS(); + vp->SetS(); + } + } + } + printf("Selected vert num %i\n",tri::UpdateSelection::VertexCount(t)); + } + + float MinDistOnEdge(Point3f samplePnt, EdgeGrid &edgeGrid, MeshType &poly, Point3f &closestPoint) @@ -331,16 +480,6 @@ public: } - // never ended - void TransferPatchInfo(MeshType &patchMesh) - { - for(int i=0;i &kdtree; + + EdgePointPred(CoM &_com, KdTree &_kdtree):com(_com),kdtree(_kdtree) {}; + bool operator()(face::Pos ep) const + { + CoordType p0 = ep.V()->P(); + CoordType p1 = ep.VFlip()->P(); + float stepNum=100.0; + float locEps = Distance(p0,p1)/stepNum; + for(float j=0;j , Point3f> + { + CoM &com; + KdTree &kdtree; + MeshType &poly; + + EdgePointSplit(CoM &_com, KdTree &_kdtree, MeshType &_poly):com(_com),kdtree(_kdtree),poly(_poly) {}; + void operator()(VertexType &nv, face::Pos ep) + { + CoordType p0 = ep.V()->P(); + CoordType p1 = ep.VFlip()->P(); + float stepNum=100.0; + float locEps = Distance(p0,p1)/stepNum; + for(float j=0;j &planeVec, int i =0) { MeshType full; @@ -660,7 +867,9 @@ public: } - + + + void SnapPolyline(MeshType &poly, std::vector *newVertVec) { const float maxDist = base.bbox.Diag()/100.0; @@ -1055,8 +1264,8 @@ public: for(int i =0; i starVecVp; - edge::VVStarVE(&(poly.vert[i]),starVecVp); - if(starVecVp.size()==2) + edge::VVStarVE(&(poly.vert[i]),starVecVp); + if( (starVecVp.size()==2) && (!poly.vert[i].IsS())) { float newSegLen = Distance(starVecVp[0]->P(), starVecVp[1]->P()); Segment3f seg(starVecVp[0]->P(),starVecVp[1]->P()); @@ -1069,11 +1278,14 @@ public: if(maxSurfDist < par.surfDistThr && (newSegLen < par.maxSimpEdgeLen) ) { edge::VEEdgeCollapse(poly,&(poly.vert[i])); + } } } + tri::UpdateTopology::TestVertexEdge(poly); tri::Allocator::CompactEveryVector(poly); - printf("Simplify %i -> %i\n",startEn,poly.en); + tri::UpdateTopology::TestVertexEdge(poly); + printf("Simplify %5i -> %5i (total len %5.2f)\n",startEn,poly.en,hist.Sum()); } void EvaluateHausdorffDistance(MeshType &poly, Distribution &dist) @@ -1097,6 +1309,7 @@ public: } + // Given a segment find the maximum distance from it to the original surface. float MaxSegDist(VertexType *v0, VertexType *v1, Point3f &farthestPointOnSurf, Point3f &farthestN, Distribution *dist=0) { @@ -1122,30 +1335,86 @@ public: return maxSurfDist; } - void Refine( MeshType &poly) + void Refine(MeshType &poly, bool uniformFlag = false) { tri::Allocator::CompactEveryVector(poly); int startEdgeSize = poly.en; for(int i =0; ipar.minRefEdgeLen) + EdgeType &ei = poly.edge[i]; + if(edge::Length(ei)>par.minRefEdgeLen) { Point3f farthestP, farthestN; - float maxDist = MaxSegDist(poly.edge[i].V(0),poly.edge[i].V(1),farthestP, farthestN); + float maxDist = MaxSegDist(ei.V(0),ei.V(1),farthestP, farthestN); if(maxDist > par.surfDistThr) { - VertexIterator vi = Allocator::AddVertex(poly,farthestP, farthestN); - Allocator::AddEdge(poly,poly.edge[i].V(0),&*vi); - Allocator::AddEdge(poly,&*vi,poly.edge[i].V(1)); - Allocator::DeleteEdge(poly,poly.edge[i]); + edge::VEEdgeSplit(poly, &ei, farthestP, farthestN); + } + else if(uniformFlag) + { + edge::VEEdgeSplit(poly,&ei,(ei.P(0)+ei.P(1))/2.0,(ei.V(0)->N()+ei.V(1)->N())/2.0); } } } - tri::Allocator::CompactEveryVector(poly); +// tri::Allocator::CompactEveryVector(poly); printf("Refine %i -> %i\n",startEdgeSize,poly.en);fflush(stdout); } - + // Take a poly and find the position of edge -edge crossing. + void RefineBaseMesh(MeshType &poly) + { + std::vector newPtVec; + for(int i=0;iFFp(ei) == lastFace) + { + Point3f ps0,ps1; + float segDist; + bool par; + Segment3f faceSeg(fp->P0(ei),fp->P1(ei)); + float angDeg = fabs(math::ToDeg(Angle(faceSeg.Direction(),seg.Direction()))); + + SegmentSegmentDistance(seg,faceSeg,segDist,par,ps0,ps1); + if(!par && (angDeg > 5 && angDeg<175)) newPtVec.push_back(ps1); + } + } + } + lastFace=fp; + lastqp = qp; + } + } + } + MeshType meshPt; tri::BuildMeshFromCoordVector(meshPt,newPtVec); + tri::io::ExporterPLY::Save(meshPt,"newPoints.ply"); + + VertexConstDataWrapper vdw(meshPt); + KdTree kdtree(vdw); + + EdgePointPred epPred(*this,kdtree); + EdgePointSplit epSplit(*this,kdtree,meshPt); + tri::UpdateTopology::FaceFace(base); + tri::RefineE(base,epSplit,epPred); + tri::UpdateTopology::FaceFace(base); + tri::io::ExporterPLY::Save(base,"newbase.ply"); + } /** @@ -1164,6 +1433,9 @@ public: */ void SmoothProject(MeshType &poly, int iterNum, ScalarType smoothWeight, ScalarType projectWeight) { + tri::RequireCompactness(poly); + tri::UpdateTopology::VertexEdge(poly); + printf("SmoothProject: Selected vert num %i\n",tri::UpdateSelection::VertexCount(poly)); assert(poly.en>0 && base.fn>0); for(int k=0;k par.maxSmoothDelta) + if(!poly.vert[i].IsS()) { - newP = poly.vert[i].P() + ( delta / delta.Norm()) * maxDist*0.5; + Point3f smoothPos = (poly.vert[i].P() + posVec[i])/float(cntVec[i]+1); + + Point3f newP = poly.vert[i].P()*(1.0-smoothWeight) + smoothPos *smoothWeight; + + Point3f delta = newP - poly.vert[i].P(); + if(delta.Norm() > par.maxSmoothDelta) + { + newP = poly.vert[i].P() + ( delta / delta.Norm()) * maxDist*0.5; + } + + float minDist; + Point3f closestP; + FaceType *f = vcg::tri::GetClosestFaceBase(base,uniformGrid,newP,maxDist, minDist, closestP); + assert(f); + poly.vert[i].P() = newP*(1.0-projectWeight) +closestP*projectWeight; + poly.vert[i].N() = f->N(); } - - float minDist; - Point3f closestP; - FaceType *f = vcg::tri::GetClosestFaceBase(base,uniformGrid,newP,maxDist, minDist, closestP); - assert(f); - poly.vert[i].P() = newP*(1.0-projectWeight) +closestP*projectWeight; - poly.vert[i].N() = f->N(); - } - Refine(poly); - Refine(poly); - Simplify(poly); -// SnapPolyline(poly,0); - Clean::RemoveDuplicateVertex(poly); +// Refine(poly); + tri::UpdateTopology::TestVertexEdge(poly); + Refine(poly); + tri::UpdateTopology::TestVertexEdge(poly); + Simplify(poly); + tri::UpdateTopology::TestVertexEdge(poly); + int dupVertNum = Clean::RemoveDuplicateVertex(poly); + if(dupVertNum) { + printf("****REMOVED %i Duplicated\n",dupVertNum); + tri::Allocator::CompactEveryVector(poly); + tri::UpdateTopology::VertexEdge(poly); + } } }