From eb6db70c6bdf3f4bc7cd47f3c5cc8c31beb27e01 Mon Sep 17 00:00:00 2001 From: cignoni Date: Thu, 31 Dec 2015 11:47:13 +0000 Subject: [PATCH] heavy restructuring now start to really work --- vcg/complex/algorithms/curve_on_manifold.h | 587 ++++++++++++++++----- 1 file changed, 455 insertions(+), 132 deletions(-) diff --git a/vcg/complex/algorithms/curve_on_manifold.h b/vcg/complex/algorithms/curve_on_manifold.h index 73e061b0..6e9b1a43 100644 --- a/vcg/complex/algorithms/curve_on_manifold.h +++ b/vcg/complex/algorithms/curve_on_manifold.h @@ -37,6 +37,7 @@ #include #include #include +#include namespace vcg { namespace tri { @@ -74,23 +75,28 @@ public: ScalarType minRefEdgeLen; // Minimal admitted Edge Lenght (used in refine: never make edge shorther than this value) ScalarType maxSimpEdgeLen; // Minimal admitted Edge Lenght (used in simplify: never make edges longer than this value) ScalarType maxSmoothDelta; // The maximum movement that is admitted during smoothing. + ScalarType maxSnapThr; // The maximum distance allowed when snapping a vertex of the polyline onto a mesh vertex + ScalarType gridBailout; // The maximum distance bailout used in grid sampling Param(MeshType &m) { Default(m);} void Default(MeshType &m) { - surfDistThr = m.bbox.Diag()/10000.0; + surfDistThr = m.bbox.Diag()/50000.0; polyDistThr = m.bbox.Diag()/1000.0; - minRefEdgeLen = m.bbox.Diag()/2000.0; - maxSimpEdgeLen = m.bbox.Diag()/1000.0; - maxSmoothDelta = m.bbox.Diag()/100.0; + minRefEdgeLen = m.bbox.Diag()/16000.0; + maxSimpEdgeLen = m.bbox.Diag()/10000.0; + maxSmoothDelta = m.bbox.Diag()/100.0; + maxSnapThr = m.bbox.Diag()/10000.0; + gridBailout = m.bbox.Diag()/20.0; } void Dump() const { - printf("surfDistThr = %6.3f\n",surfDistThr ); - printf("polyDistThr = %6.3f\n",polyDistThr ); - printf("minEdgeLen = %6.3f\n",minRefEdgeLen ); - printf("maxSmoothDelta = %6.3f\n",maxSmoothDelta); + printf("surfDistThr = %6.4f\n",surfDistThr ); + printf("polyDistThr = %6.4f\n",polyDistThr ); + printf("minRefEdgeLen = %6.4f\n",minRefEdgeLen ); + printf("maxSimpEdgeLen = %6.4f\n",maxSimpEdgeLen ); + printf("maxSmoothDelta = %6.4f\n",maxSmoothDelta); } }; @@ -216,12 +222,20 @@ public: Retract(dualMesh); } + + float MinDistOnEdge(Point3f samplePnt, EdgeGrid &edgeGrid, MeshType &poly, Point3f &closestPoint) + { + float polyDist; + EdgeType *cep = vcg::tri::GetClosestEdgeBase(poly,edgeGrid,samplePnt,par.gridBailout,polyDist,closestPoint); + return polyDist; + } + // Given an edge of a mesh, supposedly intersecting the polyline, // we search on it the closest point to the polyline static float MinDistOnEdge(VertexType *v0,VertexType *v1, EdgeGrid &edgeGrid, MeshType &poly, Point3f &closestPoint) { float minPolyDist = std::numeric_limits::max(); - const float sampleNum = 10; + const float sampleNum = 50; const float maxDist = poly.bbox.Diag()/10.0; for(float k = 0;k ep) const - { - VertexType *v0 = ep.V(); - VertexType *v1 = ep.VFlip(); - if(v0->Q() * v1->Q() < 0) - { - //Point3f pp = CoS::QLerp(v0,v1); - Point3f closestP; - float minDist = MinDistOnEdge(v0,v1,edgeGrid,poly,closestP); - if(minDist < par.polyDistThr) return true; - } - return false; - } - }; + for(int i=0;iP()*w0 + v1->P()*w1; } + class QualitySign + { + public: + EdgeGrid &edgeGrid; + MeshType &poly; + CoM &com; + QualitySign(EdgeGrid &_e,MeshType &_poly, CoM &_com):edgeGrid(_e),poly(_poly),com(_com) {}; + bool operator()(face::Pos ep) const + { + VertexType *v0 = ep.V(); + VertexType *v1 = ep.VFlip(); + if(v0->Q() * v1->Q() < 0) + { + Point3f pp = QLerp(v0,v1); + Point3f closestP; + if(com.MinDistOnEdge(pp,edgeGrid,poly,closestP) , Point3f> { EdgeGrid &edgeGrid; MeshType &poly; - Param ∥ - QualitySignSplit(EdgeGrid &_e,MeshType &_p, Param &_par):edgeGrid(_e),poly(_p),par(_par) {}; + CoM &com; + vector &newVertVec; + + QualitySignSplit(EdgeGrid &_e,MeshType &_p, CoM &_com, vector &_vec):edgeGrid(_e),poly(_p),com(_com),newVertVec(_vec) {}; void operator()(VertexType &nv, face::Pos ep) { VertexType *v0 = ep.V(); VertexType *v1 = ep.VFlip(); + Point3f pp = QLerp(v0,v1); Point3f closestP; - float minDist = MinDistOnEdge(v0,v1,edgeGrid,poly,closestP); + com.MinDistOnEdge(pp,edgeGrid,poly,closestP); + +// float minDist = MinDistOnEdge(v0,v1,edgeGrid,poly,closestP); nv.P()=closestP; + nv.Q()=0; + newVertVec.push_back(tri::Index(com.base,&nv)); // nv.P() = CoS::QLerp(v0,v1); } Color4b WedgeInterp(Color4b &c0, Color4b &c1) @@ -302,7 +363,7 @@ public: } }; - void DumpPlanes(MeshType &poly, std::vector &planeVec) + void DumpPlaneMesh(MeshType &poly, std::vector &planeVec, int i =0) { MeshType full; for(int i=0;i::Mesh(full,t); } - tri::io::ExporterPLY::Save(full,"planes.ply"); + char buf[100]; + sprintf(buf,"planes%03i.ply",i); + tri::io::ExporterPLY::Save(full,buf); } Plane3f ComputeEdgePlane(VertexType *v0, VertexType *v1) @@ -327,7 +390,8 @@ public: return pl; } - void ComputePlaneField(MeshType &poly, EdgeGrid &edgeGrid) + + void ComputePlaneField(MeshType &poly, EdgeGrid &edgeGrid, int ind) { // First Compute per-edge planes std::vector planeVec(poly.en); @@ -336,18 +400,16 @@ public: planeVec[i] = ComputeEdgePlane(poly.edge[i].V(0), poly.edge[i].V(1)); } - DumpPlanes(poly,planeVec); + DumpPlaneMesh(poly,planeVec,ind); edgeGrid.Set(poly.edge.begin(), poly.edge.end()); - const float maxDist= base.bbox.Diag()/10.0; - UpdateSelection::VertexClear(base); for(VertexIterator vi=base.vert.begin();vi!=base.vert.end();++vi) { Point3 p = vi->P(); - float minDist=maxDist; + float minDist=par.gridBailout; Point3f closestP; - EdgeType *cep = vcg::tri::GetClosestEdgeBase(poly,edgeGrid,p,maxDist,minDist,closestP); + EdgeType *cep = vcg::tri::GetClosestEdgeBase(poly,edgeGrid,p,par.gridBailout,minDist,closestP); if(cep) { int ind = tri::Index(poly,cep); @@ -362,24 +424,214 @@ public: } else { vi->Q() =1; - vi->SetS(); } } } - - void CutAlongPolyLineUsingField(MeshType &poly,EdgeGrid &edgeGrid) -{ - QualitySign qsPred(edgeGrid,poly,par); - QualitySignSplit qsSplit(edgeGrid,poly,par); - tri::UpdateTopology::FaceFace(base); - tri::RefineE(base,qsSplit,qsPred); - } - - + void CutAlongPolyLineUsingField(MeshType &poly,EdgeGrid &edgeGrid,std::vector &newVertVec) +{ + QualitySign qsPred(edgeGrid,poly,*this); + QualitySignSplit qsSplit(edgeGrid,poly,*this,newVertVec); + tri::UpdateTopology::FaceFace(base); + tri::RefineE(base,qsSplit,qsPred); + tri::UpdateTopology::FaceFace(base); + + + for(int i=0;iIsD()) + { + for(int j=0;j<3;++j) + { + if(Distance(fp->P0(j),fp->P1(j)) < par.polyDistThr) + { + if(face::FFLinkCondition(*fp,j)) + { +// if(fp->V0(j)->Q()==0) fp->V1(j)->Q()=0; +// face::FFEdgeCollapse(base,*fp,j); + break; + } + } + } + } + } + tri::Allocator::CompactEveryVector(base); + + for(int i=0;iV(0)->Q()==0) && + (fp->V(1)->Q()==0) && + (fp->V(2)->Q()==0) ) + { + ScalarType maxDist = 0; + int maxInd = -1; + for(int j=0;j<3;++j) + { + Point3f closestPt; + ScalarType d = MinDistOnEdge(fp->P(j),edgeGrid,poly,closestPt); + if(d>maxDist) + { + maxDist= d; + maxInd=j; + } + } +// assert(maxInd!=-1); +// if(maxInd>=0 && maxDist > par.surfDistThr) +// fp->V(maxInd)->Q() = maxDist; + } + } + + for(int i=0;iV(0)->Q()>=0) && + (fp->V(1)->Q()>=0) && + (fp->V(2)->Q()>=0) ) + fp->C() = Color4b::Blue; + if( (fp->V(0)->Q()<=0) && + (fp->V(1)->Q()<=0) && + (fp->V(2)->Q()<=0) ) + fp->C() = Color4b::Red; + if( (fp->V(0)->Q()==0) && + (fp->V(1)->Q()==0) && + (fp->V(2)->Q()==0) ) + fp->C() = Color4b::Green; + + if( (fp->V(0)->Q()>0) && + (fp->V(1)->Q()>0) && + (fp->V(2)->Q()>0) ) + fp->C() = Color4b::White; + if( (fp->V(0)->Q()<0) && + (fp->V(1)->Q()<0) && + (fp->V(2)->Q()<0) ) + fp->C() = Color4b::White; + } + tri::AttributeSeam::SplitVertex(base, ExtractVertex, CompareVertex); + + } + + void WalkAlongPolyLine(MeshType &poly, std::vector &ptVec) + { + // Search a starting vertex + VertexType *startVert; + for(int i=0;iP()) < par.polyDistThr) + { + startVert = &base.vert[i]; + break; + } + } + tri::UpdateTopology::VertexFace(base); + tri::UpdateTopology::FaceFace(base); + + + + } + + + + +// } +// } + +/** + * + * + */ - + void CutWithPolyLine(MeshType &poly) + { + std::vector newVertVec; + SnapPolyline(poly, &newVertVec); + tri::io::ExporterPLY::Save(poly,"poly_snapped.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); + + DecomposeNonManifoldPolyline(poly); + tri::io::ExporterPLY::Save(poly,"poly_manif.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); + std::vector< std::vector< int> > ccVec; + BuildConnectedComponentVectors(poly,ccVec); + printf("PolyLine of %i edges decomposed into %i manifold components\n",poly.en,ccVec.size()); + Reorient(poly,ccVec); + char buf[1024]; + for(int i=0;i ptVec; + FindTerminalPoints(subPoly,ptVec); + printf("Component %i (%i edges) has %i terminal points\n",i,subPoly.en, ptVec.size());fflush(stdout); + SplitMeshWithPoints(base,ptVec,newVertVec); +// sprintf(buf,"CuttingPoly%02i.ply",i); +// tri::io::ExporterPLY::Save(subPoly, buf,tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); + EdgeGrid edgeGrid; + ComputePlaneField(subPoly, edgeGrid,i); + sprintf(buf,"PlaneField%02i.ply",i); + tri::io::ExporterPLY::Save(base,buf,tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY ); + CutAlongPolyLineUsingField(subPoly,edgeGrid,newVertVec); + sprintf(buf,"PlaneCut%02i.ply",i); + tri::io::ExporterPLY::Save(base,buf,tri::io::Mask::IOM_FACECOLOR + tri::io::Mask::IOM_VERTQUALITY ); + } + +// printf("Added %i vertices\n",newVertVec.size()); +// for(int i=0;i::Save(base,"base_cut.ply",tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY ); + } + + + void SnapPolyline(MeshType &poly, std::vector *newVertVec) + { + const float maxDist = base.bbox.Diag()/100.0; + const ScalarType interpEps = 0.0001; + int vertSnapCnt=0; + int edgeSnapCnt=0; + for(VertexIterator vi=poly.vert.begin(); vi!=poly.vert.end();++vi) + { + float closestDist; + Point3f closestP,closestN,ip; + FaceType *f = vcg::tri::GetClosestFaceBase(base,uniformGrid,vi->P(),maxDist, closestDist, closestP, closestN,ip); + assert(f); + VertexType *closestVp=0; + int indIp = -1; + ScalarType minDist = std::numeric_limits::max(); + ScalarType minIp = minDist; + for(int i=0;i<3;++i) + { + if(Distance(vi->P(),f->P(i))P(),f->P(i)); + closestVp = f->V(i); + } + if(minIp > ip[i]) + { + indIp = i; + minIp=ip[i]; + } + } + assert(closestVp && (indIp!=-1)); + + + if(minDist < par.maxSnapThr) { // First Case: Snap to vertex; + vi->P() = closestVp->P(); + vertSnapCnt++; + if(newVertVec) + newVertVec->push_back(tri::Index(base,closestVp)); + } else { + if(minIp < interpEps) { // Second Case: Snap to edge; + ScalarType T1 = ip[(indIp+1)%3]; + ScalarType T2 = ip[(indIp+2)%3]; + vi->P() = (f->V1(indIp)->P() * T1 + f->V2(indIp)->P() * T2)/(T1+T2); + edgeSnapCnt++; + } + } + } + printf("Snapped %i onto vert and %i onto edges\n",vertSnapCnt, edgeSnapCnt); + } @@ -388,21 +640,24 @@ public: * vertexes that have more than two incident edges * * It performs the split in three steps. - * First it collects and counts the vertices to be splitten. - * Then it adds the vertices to the mesh and lastly it updates the poly with the newly added vertices. - * - * singSplitFlag allow to ubersplit each singularity in a number of vertex of the same order of its degreee. + * - First it collects and counts the vertices to be splitten. + * - Then it adds the vertices to the mesh and + * - lastly it updates the poly with the newly added vertices. * + * singSplitFlag allows to ubersplit each singularity in a number of vertex of the same order of its degree. + * This is not really necessary but helps the management of sharp turns in the poly mesh. + * \todo add corner detection and split. */ - void DecomposeNonManifoldTree(MeshType &poly, bool singSplitFlag = true) + void DecomposeNonManifoldPolyline(MeshType &poly, bool singSplitFlag = true) { - std::vector degreeVec(poly.vn); + tri::Allocator::CompactEveryVector(poly); + std::vector degreeVec(poly.vn, 0); tri::UpdateTopology::VertexEdge(poly); int neededVert=0; int delta; if(singSplitFlag) delta = 1; - else delta =2; + else delta = 2; for(VertexIterator vi=poly.vert.begin(); vi!=poly.vert.end();++vi) { @@ -412,9 +667,9 @@ public: if(starVec.size()>2) neededVert += starVec.size()-delta; } - + printf("DecomposeNonManifold Adding %i vert to a polyline of %i vert\n",neededVert,poly.vn); VertexIterator firstVi = tri::Allocator::AddVertices(poly,neededVert); - + for(size_t i=0;i2) @@ -436,6 +691,7 @@ public: } } } + assert(firstVi == poly.vert.end()); } /* @@ -451,15 +707,63 @@ public: } } - // This function will decompose the input edge mesh into a set of // connected components. // the vector will contain, for each connected component, a vector with all the edge indexes. void BuildConnectedComponentVectors(MeshType &poly, std::vector< std::vector< int> > &ccVec) { - tri::UpdateFlags::EdgeClearV(poly); + UpdateTopology::VertexEdge(poly); + for(size_t i=0;i(&(poly.vert[i])) <=2); + } + tri::UpdateTopology::EdgeEdge(poly); + tri::UpdateFlags::EdgeClearV(poly); + + int visitedEdgeNum=0 ; + int ccCnt=0; + EdgeIterator eIt = poly.edge.begin(); + + while(visitedEdgeNum < poly.en) + { + ccVec.resize(ccVec.size()+1); + while(eIt->IsV()) ++eIt; +// printf("Starting component from edge %i\n",tri::Index(poly,&*eIt)); + assert(eIt != poly.edge.end()); + edge::Pos startPos(&*eIt,0); + edge::Pos curPos(&*eIt,0); + do + { +// printf("(%i %i %i)-",tri::Index(poly,curPos.VFlip()), tri::Index(poly,curPos.E()) ,tri::Index(poly,curPos.V())); + curPos.NextE(); + } + while(curPos!=startPos && !curPos.IsBorder()) ; + + curPos.FlipV(); + assert(!curPos.IsBorder()); + do + { +// printf("<%i %i %i>-",tri::Index(poly,curPos.VFlip()), tri::Index(poly,curPos.E()) ,tri::Index(poly,curPos.V())); + curPos.E()->SetV(); + visitedEdgeNum++; + ccVec[ccCnt].push_back(tri::Index(poly,curPos.E())); + curPos.NextE(); + } while(!curPos.E()->IsV()); + printf("Completed component %i of %i edges\n",ccCnt, ccVec[ccCnt].size()); + ccCnt++; + } + } + // This function will decompose the input edge mesh into a set of + // connected components. + // the vector will contain, for each connected component, a vector with all the edge indexes. + void BuildConnectedComponentVectorsOld(MeshType &poly, std::vector< std::vector< int> > &ccVec) + { + tri::UpdateTopology::EdgeEdge(poly); + tri::UpdateTopology::VertexEdge(poly); + tri::UpdateFlags::EdgeClearV(poly); + int visitedEdgeNum=0 ; int ccCnt=0; @@ -467,12 +771,12 @@ public: while(visitedEdgeNum < poly.en) { ccVec.resize(ccVec.size()+1); - while(eIt->IsV()) ++eIt; + while((eIt != poly.edge.end()) && eIt->IsV()) ++eIt; EdgeType *startE = &*eIt; EdgeType *curEp = &*eIt; int curEi = 0; -// printf("Starting Visit of connected Component %i from edge %i\n",ccCnt,tri::Index(m,*eIt)); + printf("Starting Visit of connected Component %i from edge %i\n",ccCnt,tri::Index(poly,*eIt)); while( (curEp->EEp(curEi) != startE) && (curEp->EEp(curEi) != curEp) ) { @@ -499,9 +803,11 @@ public: visitedEdgeNum++; } } + printf("Completed visit of component of size %i\n",ccVec[ccCnt].size()); ccCnt++; } printf("en %i - VisitedEdgeNum = %i\n",poly.en, visitedEdgeNum); + } void ExtractSubMesh(MeshType &poly, std::vector &ind, MeshType &subPoly) @@ -526,10 +832,18 @@ public: } } + // It takes a vector of vector of connected components and cohorently reorient each one of them. + // it usese the EE adjacency and requires that the input edgemesh is 1manifold. void Reorient(MeshType &poly, std::vector< std::vector< int> > &ccVec) { - UpdateTopology::EdgeEdge(poly); + UpdateTopology::VertexEdge(poly); + for(size_t i=0;i(&(poly.vert[i])) <=2); + } + UpdateTopology::EdgeEdge(poly); + for(size_t i=0;i toFlipVec(ccVec[i].size(),false); @@ -538,13 +852,19 @@ public: { EdgeType *cur = & poly.edge[ccVec[i][j]]; EdgeType *prev; - if(j==0) prev = cur; - else prev = & poly.edge[ccVec[i][j-1]]; + if(j==0) + { + if(cur->EEp(0) == cur) + prev = cur; // boundary + else + prev = & poly.edge[ccVec[i].back()]; // cc is a loop + } + else prev = & poly.edge[ccVec[i][j-1]]; if(cur->EEp(0) != prev) { toFlipVec[j] = true; - assert(cur->EEp(1) == prev); + assert(cur->EEp(1) == prev || j==0); } } for(int j=0;j &vec) + void SplitMeshWithPoints(MeshType &m, std::vector &vec, std::vector &newVertVec) { - printf("Splitting with %i vertices\n",vec.size()); int faceToAdd=0; int vertToAdd=0; - + // For each splitting point we save the index of the face to be splitten and the "kind" of split to do: // 3 -> means classical 1 to 3 face split // 2 -> means edge split. // 0 -> means no need of a split (e.g. the point is coincident with a vertex) - + std::vector< std::pair > toSplitVec(vec.size(), std::make_pair(0,0)); MeshGrid uniformGrid; uniformGrid.Set(m.face.begin(), m.face.end()); - const float eps=0.01f; - const float maxDist = m.bbox.Diag()/10.0; - + for(size_t i =0; iP(); - float minDist; - Point3f closestP,ip; - FaceType *f = vcg::tri::GetClosestFaceBase(m,uniformGrid,newP,maxDist, minDist, closestP); + float closestDist; + Point3f closestP; + FaceType *f = vcg::tri::GetClosestFaceBase(m,uniformGrid,newP,par.gridBailout, closestDist, closestP); assert(f); - - // if(ip[0]::max(); + for(int i=0;i<3;++i) { + if(Distance(newP,f->P(i))P(i)); + closestVp = f->V(i); + } + } + assert(closestVp); + if(minDist < par.maxSnapThr) { + vec[i]->P() = closestVp->P(); + } + else { toSplitVec[i].first = tri::Index(m,f); toSplitVec[i].second = 3; @@ -599,37 +924,36 @@ public: vertToAdd += 1; } } - printf("adding %i faces and %i vertices\n",faceToAdd,vertToAdd); +// printf("Splitting with %i points: adding %i faces and %i vertices\n",vec.size(), faceToAdd,vertToAdd); FaceIterator newFi = tri::Allocator::AddFaces(m,faceToAdd); VertexIterator newVi = tri::Allocator::AddVertices(m,vertToAdd); - + tri::UpdateColor::PerFaceConstant(m,Color4b::White); - + for(size_t i =0; iP() = vec[i]->P(); - VertexType *vp0 = fp0->V(0); - VertexType *vp1 = fp0->V(1); - VertexType *vp2 = fp0->V(2); - - fp0->V(0) = vp0; fp0->V(1) = vp1; fp0->V(2) = vp; - fp1->V(0) = vp1; fp1->V(1) = vp2; fp1->V(2) = vp; - fp2->V(0) = vp2; fp2->V(1) = vp0; fp2->V(2) = vp; - - fp0->C() = Color4b::Green; - fp1->C() = Color4b::Green; - fp2->C() = Color4b::Green; + { + FaceType *fp0 = &m.face[toSplitVec[i].first]; + FaceType *fp1 = &*newFi; newFi++; + FaceType *fp2 = &*newFi; newFi++; + VertexType *vp = &*(newVi++); + newVertVec.push_back(tri::Index(base,vp)); + vp->P() = vec[i]->P(); + VertexType *vp0 = fp0->V(0); + VertexType *vp1 = fp0->V(1); + VertexType *vp2 = fp0->V(2); + + fp0->V(0) = vp0; fp0->V(1) = vp1; fp0->V(2) = vp; + fp1->V(0) = vp1; fp1->V(1) = vp2; fp1->V(2) = vp; + fp2->V(0) = vp2; fp2->V(1) = vp0; fp2->V(2) = vp; + + fp0->C() = Color4b::Green; + fp1->C() = Color4b::Green; + fp2->C() = Color4b::Green; } } - - } + } void Init() @@ -641,28 +965,6 @@ public: uniformGrid.Set(base.face.begin(), base.face.end()); } - - -// Point3f GeodesicFlatten(PosType &p) -// { -// Point3f N0 = p.F()->N(); -// Point3f N1 = p.FFlip()->N(); -// PosType t=p; -// t.FlipF(); -// t.FlipE(); -// t.FlipV(); -// // Now rotate the other point around the edge so that we get the two triangles on the same plane -// Eigen::Vector3f otherPoint,sharedEdgeDir; -// t.P().ToEigenVector(otherPoint); -// (p.V().P() - p.VFlip()->P()).Normalize().ToEigenVector(sharedEdgeDir); -// ScalarType dihedralAngleRad = vcg::face::DihedralAngleRad(*p.F(),t.F()); -// Eigen::Matrix3f mRot = Eigen::AngleAxisf(dihedralAngleRad,sharedEdgeDir).matrix(); -// Point3f otherPointRot; -// otherPointRot.FromEigenVector(mRot*otherPoint); -// Plane3f facePlane; facePlane.Init(p->F()->P0(),p->F()->P1(),p->F()->P2()); -// float dist = SignedDistancePlanePoint(facePlane,otherPointRot); -// } - void Simplify( MeshType &poly) { @@ -716,6 +1018,8 @@ public: } tri::UpdateColor::PerVertexQualityRamp(poly,0,dist.Max()); } + + // 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) { @@ -764,6 +1068,23 @@ public: printf("Refine %i -> %i\n",startEdgeSize,poly.en);fflush(stdout); } + + + + /** + * @brief SmoothProject + * @param poly + * @param iterNum + * @param smoothWeight [0..1] range; + * @param projectWeight [0..1] range; + * + * The very important function to adapt a polyline onto the base mesh + * The projection process must be done slowly to guarantee some empirical convergence... + * For each iteration it choose a new position of each vertex of the polyline. + * The new position is a blend between the smoothed position, the closest point on the surface and the original position. + * You need a good balance... + * after each iteration the polyline is refined and simplified. + */ void SmoothProject(MeshType &poly, int iterNum, ScalarType smoothWeight, ScalarType projectWeight) { assert(poly.en>0 && base.fn>0); @@ -805,7 +1126,9 @@ public: Refine(poly); Refine(poly); - Simplify(poly); + Simplify(poly); +// SnapPolyline(poly,0); + Clean::RemoveDuplicateVertex(poly); } }