heavy restructuring now start to really work
This commit is contained in:
parent
399e4b204d
commit
eb6db70c6b
|
@ -37,6 +37,7 @@
|
|||
#include <vcg/math/histogram.h>
|
||||
#include<vcg/space/distance3.h>
|
||||
#include<eigenlib/Eigen/Core>
|
||||
#include <vcg/complex/algorithms/attribute_seam.h>
|
||||
|
||||
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<ScalarType>::max();
|
||||
const float sampleNum = 10;
|
||||
const float sampleNum = 50;
|
||||
const float maxDist = poly.bbox.Diag()/10.0;
|
||||
for(float k = 0;k<sampleNum+1;++k)
|
||||
{
|
||||
|
@ -234,33 +248,50 @@ public:
|
|||
if(polyDist < minPolyDist)
|
||||
{
|
||||
minPolyDist = polyDist;
|
||||
closestPoint = closestPPoly;
|
||||
closestPoint = samplePnt;
|
||||
// closestPoint = closestPPoly;
|
||||
}
|
||||
}
|
||||
return minPolyDist;
|
||||
}
|
||||
|
||||
class QualitySign
|
||||
|
||||
// never ended
|
||||
void TransferPatchInfo(MeshType &patchMesh)
|
||||
{
|
||||
public:
|
||||
EdgeGrid &edgeGrid;
|
||||
MeshType &poly;
|
||||
Param ∥
|
||||
QualitySign(EdgeGrid &_e,MeshType &_poly, Param &_par):edgeGrid(_e),poly(_poly),par(_par) {};
|
||||
bool operator()(face::Pos<FaceType> 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;i<patchMesh.fn;++i )
|
||||
{
|
||||
Point3f bary= Barycenter(patchMesh.face[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief ExtractVertex
|
||||
* must extract an unambiguous representation of a vertex
|
||||
* to be used with attribute_seam.h
|
||||
*
|
||||
*/
|
||||
static inline void ExtractVertex(const MeshType & srcMesh, const FaceType & f, int whichWedge, const MeshType & dstMesh, VertexType & v)
|
||||
{
|
||||
(void)srcMesh;
|
||||
(void)dstMesh;
|
||||
// This is done to preserve every single perVertex property
|
||||
// perVextex Texture Coordinate is instead obtained from perWedge one.
|
||||
v.ImportData(*f.cV(whichWedge));
|
||||
v.C() = f.cC();
|
||||
}
|
||||
|
||||
static inline bool CompareVertex(const MeshType & m, const VertexType & vA, const VertexType & vB)
|
||||
{
|
||||
(void)m;
|
||||
|
||||
if(vA.C() == Color4b(Color4b::Red) && vB.C() == Color4b(Color4b::Blue) ) return false;
|
||||
if(vA.C() == Color4b(Color4b::Blue) && vB.C() == Color4b(Color4b::Red) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Point3f QLerp(VertexType *v0, VertexType *v1)
|
||||
{
|
||||
|
@ -271,19 +302,49 @@ public:
|
|||
return v0->P()*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<FaceType> 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)<com.par.polyDistThr) return true;
|
||||
float minDist = com.MinDistOnEdge(v0,v1,edgeGrid,poly,closestP);
|
||||
if(minDist < com.par.polyDistThr) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct QualitySignSplit : public std::unary_function<face::Pos<FaceType> , Point3f>
|
||||
{
|
||||
EdgeGrid &edgeGrid;
|
||||
MeshType &poly;
|
||||
Param ∥
|
||||
QualitySignSplit(EdgeGrid &_e,MeshType &_p, Param &_par):edgeGrid(_e),poly(_p),par(_par) {};
|
||||
CoM &com;
|
||||
vector<int> &newVertVec;
|
||||
|
||||
QualitySignSplit(EdgeGrid &_e,MeshType &_p, CoM &_com, vector<int> &_vec):edgeGrid(_e),poly(_p),com(_com),newVertVec(_vec) {};
|
||||
void operator()(VertexType &nv, face::Pos<FaceType> 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<Plane3f> &planeVec)
|
||||
void DumpPlaneMesh(MeshType &poly, std::vector<Plane3f> &planeVec, int i =0)
|
||||
{
|
||||
MeshType full;
|
||||
for(int i=0;i<planeVec.size();++i)
|
||||
|
@ -312,7 +373,9 @@ public:
|
|||
OrientedDisk(t,16,edge::Center(poly.edge[i]),planeVec[i].Direction(),radius);
|
||||
tri::Append<MeshType,MeshType>::Mesh(full,t);
|
||||
}
|
||||
tri::io::ExporterPLY<MeshType>::Save(full,"planes.ply");
|
||||
char buf[100];
|
||||
sprintf(buf,"planes%03i.ply",i);
|
||||
tri::io::ExporterPLY<MeshType>::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<Plane3f> 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<MeshType>::VertexClear(base);
|
||||
|
||||
for(VertexIterator vi=base.vert.begin();vi!=base.vert.end();++vi)
|
||||
{
|
||||
Point3<ScalarType> 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<MeshType>::FaceFace(base);
|
||||
tri::RefineE(base,qsSplit,qsPred);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CutAlongPolyLineUsingField(MeshType &poly,EdgeGrid &edgeGrid,std::vector<int> &newVertVec)
|
||||
{
|
||||
QualitySign qsPred(edgeGrid,poly,*this);
|
||||
QualitySignSplit qsSplit(edgeGrid,poly,*this,newVertVec);
|
||||
tri::UpdateTopology<MeshType>::FaceFace(base);
|
||||
tri::RefineE(base,qsSplit,qsPred);
|
||||
tri::UpdateTopology<MeshType>::FaceFace(base);
|
||||
|
||||
|
||||
for(int i=0;i<base.fn;++i)
|
||||
{
|
||||
FaceType *fp = &base.face[i];
|
||||
if(!fp->IsD())
|
||||
{
|
||||
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<MeshType>::CompactEveryVector(base);
|
||||
|
||||
for(int i=0;i<base.fn;++i)
|
||||
{
|
||||
FaceType *fp = &base.face[i];
|
||||
if( (fp->V(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;i<base.fn;++i)
|
||||
{
|
||||
FaceType *fp = &base.face[i];
|
||||
if( (fp->V(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<VertexType *> &ptVec)
|
||||
{
|
||||
// Search a starting vertex
|
||||
VertexType *startVert;
|
||||
for(int i=0;i<base.vn;++i)
|
||||
{
|
||||
if(Distance(base.vert[i].P(),ptVec[0]->P()) < par.polyDistThr)
|
||||
{
|
||||
startVert = &base.vert[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
tri::UpdateTopology<MeshType>::VertexFace(base);
|
||||
tri::UpdateTopology<MeshType>::FaceFace(base);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void CutWithPolyLine(MeshType &poly)
|
||||
{
|
||||
std::vector<int> newVertVec;
|
||||
SnapPolyline(poly, &newVertVec);
|
||||
tri::io::ExporterPLY<MeshType>::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<MeshType>::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<ccVec.size();++i)
|
||||
// for(int i=0;i<10;++i)
|
||||
{
|
||||
MeshType subPoly;
|
||||
ExtractSubMesh(poly,ccVec[i],subPoly);
|
||||
std::vector< VertexType *> 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<MeshType>::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<MeshType>::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<MeshType>::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<newVertVec.size();++i)
|
||||
// base.vert[newVertVec[i]].C()=Color4b::Red;
|
||||
|
||||
tri::io::ExporterPLY<MeshType>::Save(base,"base_cut.ply",tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY );
|
||||
}
|
||||
|
||||
|
||||
void SnapPolyline(MeshType &poly, std::vector<int> *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<ScalarType>::max();
|
||||
ScalarType minIp = minDist;
|
||||
for(int i=0;i<3;++i)
|
||||
{
|
||||
if(Distance(vi->P(),f->P(i))<minDist)
|
||||
{
|
||||
minDist = Distance(vi->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<int> degreeVec(poly.vn);
|
||||
tri::Allocator<MeshType>::CompactEveryVector(poly);
|
||||
std::vector<int> degreeVec(poly.vn, 0);
|
||||
tri::UpdateTopology<MeshType>::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<MeshType>::AddVertices(poly,neededVert);
|
||||
|
||||
|
||||
for(size_t i=0;i<degreeVec.size();++i)
|
||||
{
|
||||
if(degreeVec[i]>2)
|
||||
|
@ -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<MeshType>::EdgeClearV(poly);
|
||||
UpdateTopology<MeshType>::VertexEdge(poly);
|
||||
for(size_t i=0;i<poly.vn;++i)
|
||||
{
|
||||
assert(edge::VEDegree<EdgeType>(&(poly.vert[i])) <=2);
|
||||
}
|
||||
|
||||
tri::UpdateTopology<MeshType>::EdgeEdge(poly);
|
||||
tri::UpdateFlags<MeshType>::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<EdgeType> startPos(&*eIt,0);
|
||||
edge::Pos<EdgeType> 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<MeshType>::EdgeEdge(poly);
|
||||
tri::UpdateTopology<MeshType>::VertexEdge(poly);
|
||||
tri::UpdateFlags<MeshType>::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<int> &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<MeshType>::EdgeEdge(poly);
|
||||
UpdateTopology<MeshType>::VertexEdge(poly);
|
||||
for(size_t i=0;i<poly.vn;++i)
|
||||
{
|
||||
assert(edge::VEDegree<EdgeType>(&(poly.vert[i])) <=2);
|
||||
}
|
||||
UpdateTopology<MeshType>::EdgeEdge(poly);
|
||||
|
||||
for(size_t i=0;i<ccVec.size();++i)
|
||||
{
|
||||
std::vector<bool> 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<ccVec[i].size();++j)
|
||||
|
@ -562,36 +882,41 @@ public:
|
|||
* (this is the reason for having a vector of vertex pointers instead just a vector of points)
|
||||
*
|
||||
*/
|
||||
void SplitMeshWithPoints(MeshType &m, std::vector<VertexType *> &vec)
|
||||
void SplitMeshWithPoints(MeshType &m, std::vector<VertexType *> &vec, std::vector<int> &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<int,int> > 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; i<vec.size();++i)
|
||||
{
|
||||
Point3f newP = vec[i]->P();
|
||||
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]<eps || ip[1]<eps || ip[2]<eps)
|
||||
// {
|
||||
// // TODO
|
||||
// }
|
||||
// else
|
||||
VertexType *closestVp=0;
|
||||
ScalarType minDist = std::numeric_limits<ScalarType>::max();
|
||||
for(int i=0;i<3;++i) {
|
||||
if(Distance(newP,f->P(i))<minDist)
|
||||
{
|
||||
minDist = Distance(newP,f->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<MeshType>::AddFaces(m,faceToAdd);
|
||||
VertexIterator newVi = tri::Allocator<MeshType>::AddVertices(m,vertToAdd);
|
||||
|
||||
|
||||
tri::UpdateColor<MeshType>::PerFaceConstant(m,Color4b::White);
|
||||
|
||||
|
||||
for(size_t i =0; i<vec.size();++i)
|
||||
{
|
||||
if(toSplitVec[i].second==3)
|
||||
{
|
||||
FaceType *fp0,*fp1,*fp2;
|
||||
fp0 = &m.face[toSplitVec[i].first];
|
||||
fp1 = &*newFi; newFi++;
|
||||
fp2 = &*newFi; newFi++;
|
||||
VertexType *vp = &*(newVi++);
|
||||
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;
|
||||
{
|
||||
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<MeshType>::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<ScalarType> *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<MeshType>::RemoveDuplicateVertex(poly);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue