This commit is contained in:
T.Alderighi 2018-05-11 11:01:21 +02:00
commit 386dba9f64
24 changed files with 589 additions and 278 deletions

View File

@ -89,7 +89,7 @@ int main( int argc, char **argv )
tri::TrivialSampler<MyMesh> mps(sampleVec); tri::TrivialSampler<MyMesh> mps(sampleVec);
tri::UpdateTopology<MyMesh>::FaceFace(m); tri::UpdateTopology<MyMesh>::FaceFace(m);
tri::UpdateNormal<MyMesh>::PerFace(m); tri::UpdateNormal<MyMesh>::PerFace(m);
tri::UpdateFlags<MyMesh>::FaceFauxCrease(m,math::ToRad(40.0f)); tri::UpdateFlags<MyMesh>::FaceEdgeSelCrease(m,math::ToRad(40.0f));
tri::SurfaceSampling<MyMesh,tri::TrivialSampler<MyMesh> >::EdgeMontecarlo(m,mps,10000,false); tri::SurfaceSampling<MyMesh,tri::TrivialSampler<MyMesh> >::EdgeMontecarlo(m,mps,10000,false);
tri::BuildMeshFromCoordVector(MontecarloEdgeMesh,sampleVec); tri::BuildMeshFromCoordVector(MontecarloEdgeMesh,sampleVec);
tri::io::ExporterOFF<MyMesh>::Save(MontecarloEdgeMesh,"MontecarloEdgeMesh.off"); tri::io::ExporterOFF<MyMesh>::Save(MontecarloEdgeMesh,"MontecarloEdgeMesh.off");

View File

@ -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;

View File

@ -35,8 +35,8 @@ namespace tri {
template<class MESH_TYPE> template<class MESH_TYPE>
void CreaseCut(MESH_TYPE &m, float angleRad) void CreaseCut(MESH_TYPE &m, float angleRad)
{ {
tri::UpdateFlags<MESH_TYPE>::FaceFauxSignedCrease(m, -angleRad, angleRad); tri::UpdateFlags<MESH_TYPE>::FaceEdgeSelSignedCrease(m, -angleRad, angleRad);
CutMeshAlongNonFauxEdges(m); CutMeshAlongSelectedFaceEdges(m);
} }
/** /**
@ -48,7 +48,7 @@ void CreaseCut(MESH_TYPE &m, float angleRad)
* *
*/ */
template<class MESH_TYPE> template<class MESH_TYPE>
void CutMeshAlongNonFauxEdges(MESH_TYPE &m) void CutMeshAlongSelectedFaceEdges(MESH_TYPE &m)
{ {
typedef typename MESH_TYPE::FaceIterator FaceIterator; typedef typename MESH_TYPE::FaceIterator FaceIterator;
typedef typename MESH_TYPE::FaceType FaceType; typedef typename MESH_TYPE::FaceType FaceType;
@ -86,7 +86,7 @@ void CutMeshAlongNonFauxEdges(MESH_TYPE &m)
{ {
do { do {
curPos.FlipF();curPos.FlipE(); curPos.FlipF();curPos.FlipE();
if(!curPos.IsFaux()) if(curPos.IsEdgeS())
break; break;
} while(curPos!=startPos); } while(curPos!=startPos);
startPos=curPos; startPos=curPos;
@ -100,7 +100,7 @@ void CutMeshAlongNonFauxEdges(MESH_TYPE &m)
size_t faceInd = Index(m,curPos.F()); size_t faceInd = Index(m,curPos.F());
indVec[faceInd*3+ curPos.VInd()] = curVertexCounter; indVec[faceInd*3+ curPos.VInd()] = curVertexCounter;
curPos.FlipE(); curPos.FlipE();
if(!curPos.IsFaux()) if(curPos.IsEdgeS())
{ //qDebug(" Crease FOUND"); { //qDebug(" Crease FOUND");
++locCreaseCounter; ++locCreaseCounter;
curVertexCounter=newVertexCounter; curVertexCounter=newVertexCounter;

View File

@ -768,11 +768,11 @@ void BuildMeshFromCoordVector( MeshType & in, const V & v)
template <class TriMeshType,class EdgeMeshType > template <class TriMeshType,class EdgeMeshType >
void BuildFromNonFaux(TriMeshType &in, EdgeMeshType &out) void BuildFromFaceEdgeSel(TriMeshType &in, EdgeMeshType &out)
{ {
tri::RequireCompactness(in); tri::RequireCompactness(in);
std::vector<typename tri::UpdateTopology<TriMeshType>::PEdge> edgevec; std::vector<typename tri::UpdateTopology<TriMeshType>::PEdge> edgevec;
tri::UpdateTopology<TriMeshType>::FillUniqueEdgeVector(in, edgevec, false); tri::UpdateTopology<TriMeshType>::FillSelectedFaceEdgeVector(in, edgevec);
out.Clear(); out.Clear();
for(size_t i=0;i<in.vert.size();++i) for(size_t i=0;i<in.vert.size();++i)
tri::Allocator<EdgeMeshType>::AddVertex(out, in.vert[i].P()); tri::Allocator<EdgeMeshType>::AddVertex(out, in.vert[i].P());

View File

@ -184,47 +184,50 @@ 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::UpdateTopology<MeshType>::VertexFace(base); tri::UpdateFlags<MeshType>::FaceClearFaceEdgeS(base);
tri::UpdateTopology<MeshType>::FaceFace(base);
for(EdgeIterator ei=poly.edge.begin(); ei!=poly.edge.end();++ei)
{
CoordType ip0,ip1;
FaceType *f0 = GetClosestFaceIP(ei->cP(0),ip0);
FaceType *f1 = GetClosestFaceIP(ei->cP(1),ip1);
if(BarycentricSnap(ip0) && BarycentricSnap(ip1))
{
VertexPointer v0 = FindVertexSnap(f0,ip0);
VertexPointer v1 = FindVertexSnap(f1,ip1);
if(v0==0 || v1==0) return false; tri::UpdateTopology<MeshType>::VertexFace(base);
if(v0==v1) return false; tri::UpdateTopology<MeshType>::FaceFace(base);
FacePointer ff0,ff1; for(EdgeIterator ei=poly.edge.begin(); ei!=poly.edge.end();++ei)
int e0,e1; {
bool ret=face::FindSharedFaces<FaceType>(v0,v1,ff0,ff1,e0,e1); CoordType ip0,ip1;
if(ret){ FaceType *f0 = GetClosestFaceIP(ei->cP(0),ip0);
assert(ret); FaceType *f1 = GetClosestFaceIP(ei->cP(1),ip1);
assert(ff0->V(e0)==v0 || ff0->V(e0)==v1);
ff0->ClearF(e0); if(BarycentricSnap(ip0) && BarycentricSnap(ip1))
ff1->ClearF(e1); {
} VertexPointer v0 = FindVertexSnap(f0,ip0);
else { VertexPointer v1 = FindVertexSnap(f1,ip1);
return false;
} if(v0==0 || v1==0)
} return false;
else { if(v0==v1)
return false; return false;
}
} FacePointer ff0,ff1;
return true; int e0,e1;
} bool ret=face::FindSharedFaces<FaceType>(v0,v1,ff0,ff1,e0,e1);
if(ret)
{
assert(ret);
assert(ff0->V(e0)==v0 || ff0->V(e0)==v1);
ff0->SetFaceEdgeS(e0);
ff1->SetFaceEdgeS(e1);
} else {
return false;
}
}
else {
return false;
}
}
return true;
}
ScalarType MinDistOnEdge(CoordType samplePnt, EdgeGrid &edgeGrid, MeshType &poly, CoordType &closestPoint) ScalarType MinDistOnEdge(CoordType samplePnt, EdgeGrid &edgeGrid, MeshType &poly, CoordType &closestPoint)
{ {
ScalarType polyDist; ScalarType polyDist;

View File

@ -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);
} }
}; };

View File

@ -475,14 +475,14 @@ private:
tri::UpdateFlags<MeshType>::VertexBorderFromNone(m); tri::UpdateFlags<MeshType>::VertexBorderFromNone(m);
for(auto fi=m.face.begin(); fi!=m.face.end(); ++fi) for(auto fi=m.face.begin(); fi!=m.face.end(); ++fi)
if(!(*fi).IsD()) if(!(*fi).IsD() && (params.selectedOnly == false || fi->IsS()))
{ {
for(auto i=0; i<3; ++i) for(auto i=0; i<3; ++i)
{ {
PosType pi(&*fi, i); PosType pi(&*fi, i);
++candidates; ++candidates;
VertexPair bp = VertexPair(pi.V(), pi.VFlip()); VertexPair bp = VertexPair(pi.V(), pi.VFlip());
Point3<ScalarType> mp = (pi.V()->P()+pi.VFlip()->P())/2.f;; Point3<ScalarType> mp = (pi.V()->P()+pi.VFlip()->P())/2.f;
bool boundary = false; bool boundary = false;
if(pi.V()->IsB() == pi.VFlip()->IsB()) if(pi.V()->IsB() == pi.VFlip()->IsB())
@ -581,7 +581,7 @@ private:
int count = 0; int count = 0;
for(auto fi=m.face.begin(); fi!=m.face.end(); ++fi) for(auto fi=m.face.begin(); fi!=m.face.end(); ++fi)
if(!(*fi).IsD()) if(!(*fi).IsD() && (params.selectedOnly == false || fi->IsS()))
{ {
for(auto i=0; i<3; ++i) for(auto i=0; i<3; ++i)
{ {

View File

@ -759,7 +759,7 @@ static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum)
/// ///
/// It assumes that the mesh is 1-manifold. /// It assumes that the mesh is 1-manifold.
/// each connected component is sampled in a independent way. /// each connected component is sampled in a independent way.
/// For each component of lenght <L> we place on it floor(L/radius)+1 samples. /// For each component of length <L> we place on it floor(L/radius)+1 samples.
/// (if conservative argument is false we place ceil(L/radius)+1 samples) /// (if conservative argument is false we place ceil(L/radius)+1 samples)
/// ///
static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, bool conservative = true) static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, bool conservative = true)

View File

@ -1113,6 +1113,33 @@ public:
} }
} }
static ScalarType InitQualityFaceTorsion(PolyMeshType &poly_m)
{
UpdateFaceNormalByFitting(poly_m);
vcg::tri::UpdateNormal<PolyMeshType>::PerVertexFromCurrentFaceNormal(poly_m);
ScalarType MaxA=0;
for (size_t i=0;i<poly_m.face.size();i++)
{
poly_m.face[i].Q()=PolygonTorsion(poly_m.face[i]);
MaxA=std::max(MaxA,poly_m.face[i].Q());
}
return MaxA;
}
static ScalarType InitQualityFaceBending(PolyMeshType &poly_m)
{
UpdateFaceNormalByFitting(poly_m);
vcg::tri::UpdateNormal<PolyMeshType>::PerVertexFromCurrentFaceNormal(poly_m);
ScalarType MaxA=0;
for (size_t i=0;i<poly_m.face.size();i++)
{
poly_m.face[i].Q()=PolygonBending(poly_m.face[i]);
MaxA=std::max(MaxA,poly_m.face[i].Q());
}
return MaxA;
}
static void InitQualityVertEdgeLenght(PolyMeshType &poly_m) static void InitQualityVertEdgeLenght(PolyMeshType &poly_m)
{ {
for (size_t i=0;i<poly_m.vert.size();i++) for (size_t i=0;i<poly_m.vert.size();i++)

View File

@ -316,8 +316,8 @@ class RefinedFaceData
{ {
public: public:
RefinedFaceData(){ RefinedFaceData(){
ep[0]=0;ep[1]=0;ep[2]=0; ep[0] = ep[1] = ep[2] = false;
vp[0]=0;vp[1]=0;vp[2]=0; vp[0] = vp[1] = vp[2] = NULL;
} }
bool ep[3]; bool ep[3];
VertexPointer vp[3]; VertexPointer vp[3];
@ -443,11 +443,11 @@ bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false
TexCoordType wtt[6]; // per ogni faccia sono al piu' tre i nuovi valori TexCoordType wtt[6]; // per ogni faccia sono al piu' tre i nuovi valori
// di texture per wedge (uno per ogni edge) // di texture per wedge (uno per ogni edge)
int fca=0,fcn =0; int fca=0;
for(fi=m.face.begin();fi!=oldendf;++fi) if(!(*fi).IsD()) for(fi=m.face.begin();fi!=oldendf;++fi) if(!(*fi).IsD())
{ {
if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining..."); if(cb && (++step%PercStep)==0)
fcn++; (*cb)(step/PercStep,"Refining...");
vv[0]=(*fi).V(0); vv[0]=(*fi).V(0);
vv[1]=(*fi).V(1); vv[1]=(*fi).V(1);
vv[2]=(*fi).V(2); vv[2]=(*fi).V(2);
@ -455,7 +455,7 @@ bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false
vv[4] = RD[fi].vp[1]; vv[4] = RD[fi].vp[1];
vv[5] = RD[fi].vp[2]; vv[5] = RD[fi].vp[2];
int ind=((&*vv[3])?1:0)+((&*vv[4])?2:0)+((&*vv[5])?4:0); int ind = ((vv[3] != NULL) ? 1 : 0) + ((vv[4] != NULL) ? 2 : 0) + ((vv[5] != NULL) ? 4 : 0);
nf[0]=&*fi; nf[0]=&*fi;
int i; int i;
@ -468,29 +468,41 @@ bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false
} }
if(tri::HasPerWedgeTexCoord(m)) if(tri::HasPerWedgeTexCoord(m))
for(i=0;i<3;++i) { for(i=0;i<3;++i)
wtt[i]=(*fi).WT(i); {
wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3)); wtt[i]=(*fi).WT(i);
} wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3));
}
int orgflag= (*fi).Flags(); int orgflag = (*fi).Flags();
for(i=0;i<SplitTab[ind].TriNum;++i) for (i=0; i<SplitTab[ind].TriNum; ++i)
for(j=0;j<3;++j){ for(j=0;j<3;++j)
(*nf[i]).V(j)=&*vv[SplitTab[ind].TV[i][j]]; {
(*nf[i]).V(j)=&*vv[SplitTab[ind].TV[i][j]];
if(tri::HasPerWedgeTexCoord(m)) //analogo ai vertici... if(tri::HasPerWedgeTexCoord(m)) //analogo ai vertici...
(*nf[i]).WT(j)=wtt[SplitTab[ind].TV[i][j]]; (*nf[i]).WT(j) = wtt[SplitTab[ind].TV[i][j]];
assert((*nf[i]).V(j)!=0); assert((*nf[i]).V(j)!=0);
if(SplitTab[ind].TE[i][j]!=3){ if(SplitTab[ind].TE[i][j]!=3)
if(orgflag & (MESH_TYPE::FaceType::BORDER0<<(SplitTab[ind].TE[i][j]))) {
(*nf[i]).SetB(j); if(orgflag & (MESH_TYPE::FaceType::BORDER0<<(SplitTab[ind].TE[i][j])))
else (*nf[i]).SetB(j);
(*nf[i]).ClearB(j); else
} (*nf[i]).ClearB(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 && 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[0][0]]->P(),vv[SplitTab[ind].swap[0][1]]->P()) <
@ -507,6 +519,11 @@ bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false
if((*nf[2]).IsB(0)) (*nf[1]).SetB(1); else (*nf[1]).ClearB(1); if((*nf[2]).IsB(0)) (*nf[1]).SetB(1); else (*nf[1]).ClearB(1);
(*nf[1]).ClearB(0); (*nf[1]).ClearB(0);
(*nf[2]).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);
} }
} }

View File

@ -144,10 +144,7 @@ public:
static void FaceClearB(MeshType &m) { FaceClear(m,FaceType::BORDER012);} static void FaceClearB(MeshType &m) { FaceClear(m,FaceType::BORDER012);}
static void FaceClearS(MeshType &m) {FaceClear(m,FaceType::SELECTED);} static void FaceClearS(MeshType &m) {FaceClear(m,FaceType::SELECTED);}
static void FaceClearF(MeshType &m) { FaceClear(m,FaceType::FAUX012);} static void FaceClearF(MeshType &m) { FaceClear(m,FaceType::FAUX012);}
static void FaceClearCreases(MeshType &m) { FaceClear(m,FaceType::CREASE0); static void FaceClearFaceEdgeS(MeshType &m) { FaceClear(m,FaceType::FACEEDGESEL012 ); }
FaceClear(m,FaceType::CREASE1);
FaceClear(m,FaceType::CREASE2);
}
static void EdgeSetV(MeshType &m) { EdgeSet(m,EdgeType::VISITED);} static void EdgeSetV(MeshType &m) { EdgeSet(m,EdgeType::VISITED);}
static void VertexSetV(MeshType &m) { VertexSet(m,VertexType::VISITED);} static void VertexSetV(MeshType &m) { VertexSet(m,VertexType::VISITED);}
@ -423,20 +420,20 @@ public:
/// \brief Marks feature edges according to two signed dihedral angles. /// \brief Marks feature edges according to two signed dihedral angles.
/// Actually it marks as fauxedges all the non feature edges, /// Actually it uses the face_edge selection bit on faces,
/// e.g. the edges where the signed dihedral angle between the normal of two incident faces , /// we select the edges where the signed dihedral angle between the normal of two incident faces ,
/// is between the two given thresholds. /// is outside the two given thresholds.
/// In this way all the edges that are almost planar are marked as Faux Edges (e.g. edges to be ignored) /// In this way all the edges that are almost planar are marked as non selected (e.g. edges to be ignored)
/// Note that it uses the signed dihedral angle convention (negative for concave edges and positive for convex ones); /// Note that it uses the signed dihedral angle convention (negative for concave edges and positive for convex ones);
/// ///
/// Optionally it can also mark as feature edges also the boundary edges. /// Optionally it can also mark as feature edges also the boundary edges.
/// ///
static void FaceFauxSignedCrease(MeshType &m, float AngleRadNeg, float AngleRadPos, bool MarkBorderFlag = false ) static void FaceEdgeSelSignedCrease(MeshType &m, float AngleRadNeg, float AngleRadPos, bool MarkBorderFlag = false )
{ {
RequirePerFaceFlags(m); RequirePerFaceFlags(m);
RequireFFAdjacency(m); RequireFFAdjacency(m);
//initially Nothing is faux (e.g all crease) //initially Nothing is faux (e.g all crease)
FaceClearF(m); FaceClearFaceEdgeS(m);
// Then mark faux only if the signed angle is the range. // Then mark faux only if the signed angle is the range.
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{ {
@ -445,12 +442,12 @@ public:
if(!face::IsBorder(*fi,z) ) if(!face::IsBorder(*fi,z) )
{ {
ScalarType angle = DihedralAngleRad(*fi,z); ScalarType angle = DihedralAngleRad(*fi,z);
if(angle>AngleRadNeg && angle<AngleRadPos) if(angle<AngleRadNeg || angle>AngleRadPos)
(*fi).SetF(z); (*fi).SetFaceEdgeS(z);
} }
else else
{ {
if(MarkBorderFlag) (*fi).SetF(z); if(MarkBorderFlag) (*fi).SetFaceEdgeS(z);
} }
} }
} }
@ -459,29 +456,30 @@ public:
/// \brief Marks feature edges according to border flag. /// \brief Marks feature edges according to border flag.
/// Actually it marks as fauxedges all the non border edges, /// Actually it marks as fauxedges all the non border edges,
/// ///
static void FaceFauxBorder(MeshType &m) static void FaceEdgeSelBorder(MeshType &m)
{ {
RequirePerFaceFlags(m); RequirePerFaceFlags(m);
RequireFFAdjacency(m); RequireFFAdjacency(m);
//initially Nothing is faux (e.g all crease) //initially Nothing is faux (e.g all crease)
FaceClearF(m); FaceClearFaceEdgeS(m);
// Then mark faux only if the signed angle is the range. // Then mark faux only if the signed angle is the range.
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{ {
for(int z=0;z<(*fi).VN();++z) for(int z=0;z<(*fi).VN();++z)
{ {
if(!face::IsBorder(*fi,z) ) (*fi).SetF(z); if(!face::IsBorder(*fi,z) ) (*fi).SetFaceEdgeS(z);
} }
} }
} }
/// \brief Marks feature edges according to a given angle /// \brief Marks feature edges according to a given angle
/// Actually it marks as fauxedges all the non feature edges, /// Actually it uses the face_edge selection bit on faces,
/// e.g. the edge such that the angle between the normal of two faces sharing it is less than the given threshold. /// we select the edges where the dihedral angle between the normal of two incident faces is larger than ,
/// In this way all the near planar edges are marked as Faux Edges (e.g. edges to be ignored) /// the given thresholds.
static void FaceFauxCrease(MeshType &m,float AngleRad) /// In this way all the near planar edges are marked remains not selected (e.g. edges to be ignored)
static void FaceEdgeSelCrease(MeshType &m,float AngleRad)
{ {
FaceFauxSignedCrease(m,-AngleRad,AngleRad); FaceEdgeSelSignedCrease(m,-AngleRad,AngleRad);
} }

View File

@ -220,6 +220,20 @@ static void FillUniqueEdgeVector(MeshType &m, std::vector<PEdge> &edgeVec, bool
edgeVec.resize(newEnd-edgeVec.begin()); // redundant! remove? edgeVec.resize(newEnd-edgeVec.begin()); // redundant! remove?
} }
static void FillSelectedFaceEdgeVector(MeshType &m, std::vector<PEdge> &edgeVec)
{
edgeVec.reserve(m.fn*3);
ForEachFace(m, [&](FaceType &f){
for(int j=0;j<f.VN();++j)
if(f.IsFaceEdgeS(j))
edgeVec.push_back(PEdge(&f,j));
});
sort(edgeVec.begin(), edgeVec.end()); // oredering by vertex
edgeVec.erase(std::unique(edgeVec.begin(), edgeVec.end()),edgeVec.end());
}
/*! \brief Initialize the edge vector all the edges that can be inferred from current face vector, setting up all the current adjacency relations /*! \brief Initialize the edge vector all the edges that can be inferred from current face vector, setting up all the current adjacency relations
* *
@ -591,7 +605,6 @@ static void TestVertexEdge(MeshType &m)
int cnt =0; int cnt =0;
for(edge::VEIterator<EdgeType> vei(&*vi);!vei.End();++vei) for(edge::VEIterator<EdgeType> vei(&*vi);!vei.End();++vei)
cnt++; cnt++;
EdgeType *vep = vi->VEp();
assert((numVertex[tri::Index(m,*vi)] == 0) == (vi->VEp()==0) ); assert((numVertex[tri::Index(m,*vi)] == 0) == (vi->VEp()==0) );
assert(cnt==numVertex[tri::Index(m,*vi)]); assert(cnt==numVertex[tri::Index(m,*vi)]);
} }

View File

@ -110,10 +110,11 @@ public:
NORMX = 0x00000200, NORMX = 0x00000200,
NORMY = 0x00000400, NORMY = 0x00000400,
NORMZ = 0x00000800, NORMZ = 0x00000800,
// Crease _flags, it is assumed that CREASEi = CREASE0<<i // Face-Edge Selection Flags
CREASE0 = 0x00008000, FACEEDGESEL0 = 0x00008000,
CREASE1 = 0x00010000, FACEEDGESEL1 = 0x00010000,
CREASE2 = 0x00020000, FACEEDGESEL2 = 0x00020000,
FACEEDGESEL012 = FACEEDGESEL0 | FACEEDGESEL1 | FACEEDGESEL2 ,
// Faux edges. (semantics: when a mesh is polygonal, edges which are inside a polygonal face are "faux" // Faux edges. (semantics: when a mesh is polygonal, edges which are inside a polygonal face are "faux"
FAUX0 = 0x00040000, FAUX0 = 0x00040000,
FAUX1 = 0x00080000, FAUX1 = 0x00080000,
@ -175,12 +176,12 @@ public:
/// This funcion execute the inverse operation of SetS() /// This funcion execute the inverse operation of SetS()
void ClearB(int i) {this->Flags() &= (~(BORDER0<<i));} void ClearB(int i) {this->Flags() &= (~(BORDER0<<i));}
/// This function checks if the face is selected /// This function checks if the i-th face-edge is selected
bool IsCrease(int i) const {return (this->cFlags() & (CREASE0<<i)) != 0;} bool IsFaceEdgeS(int i) const {return (this->cFlags() & (FACEEDGESEL0<<i)) != 0;}
/// This function select the face /// This function select the i-th face-edge
void SetCrease(int i){this->Flags() |=(CREASE0<<i);} void SetFaceEdgeS(int i){this->Flags() |=(FACEEDGESEL0<<i);}
/// This funcion execute the inverse operation of SetS() /// This function de-select the i-th face-edge
void ClearCrease(int i) {this->Flags() &= (~(CREASE0<<i));} void ClearFaceEdgeS(int i) {this->Flags() &= (~(FACEEDGESEL0<<i));}
/// This function checks if a given side of the face is a feature/internal edge /// This function checks if a given side of the face is a feature/internal edge
/// it is used by some importer to mark internal /// it is used by some importer to mark internal

View File

@ -289,40 +289,12 @@ public:
//assert(f->FFp(z)==f); // f is border along j //assert(f->FFp(z)==f); // f is border along j
} }
/// Finds the next Crease half-edge border
/// TODO change crease flag with something more generic (per edge)
void NextCrease( )
{
assert(f->V(f->Prev(z))!=v && (f->V(f->Next(z))==v || f->V(z)==v));
assert(IsCrease()); // f is border along j
// Si deve cambiare faccia intorno allo stesso vertice v
//finche' non si trova una faccia di bordo.
do
{
FlipE();
if (!IsCrease()) FlipF();
}
while(!IsCrease());
// L'edge j e' di bordo e deve contenere v
assert(IsCrease() &&( f->V(z)==v || f->V(f->Next(z))==v ));
FlipV();
assert(f->V(f->Prev(z))!=v && (f->V(f->Next(z))==v || f->V(z)==v));
}
/// Checks if the half-edge is of border /// Checks if the half-edge is of border
bool IsBorder()const bool IsBorder()const
{ {
return face::IsBorder(*f,z); return face::IsBorder(*f,z);
} }
/// Checks if the half-edge is of crease
bool IsCrease() const
{
return f->IsCrease(z);
}
bool IsFaux() const bool IsFaux() const
{ {
return (f->IsF(z)); return (f->IsF(z));
@ -333,6 +305,10 @@ public:
return face::IsManifold(*f,z); return face::IsManifold(*f,z);
} }
bool IsFaceS() const { return f->IsS();}
bool IsEdgeS() const { return f->IsFaceEdgeS(z);}
bool IsVertS() const { return v->IsS();}
/*! /*!
* Returns the angle (in radiant) between the two edges incident on V. * Returns the angle (in radiant) between the two edges incident on V.
*/ */

View File

@ -564,5 +564,116 @@ vcg::Box3<typename PolygonType::ScalarType> PolygonBox(const PolygonType &F)
bb.Add(F.V(j)->P()); bb.Add(F.V(j)->P());
return bb; return bb;
} }
template<class PolygonType>
typename PolygonType::ScalarType PolygonTorsion(const PolygonType &F,int side)
{
typedef typename PolygonType::CoordType CoordType;
typedef typename PolygonType::ScalarType ScalarType;
assert(side>=0);
assert(side<2);
assert(F.VN()==4);
//get firts two edges directions
CoordType Dir0,Dir1;
if (side==0)
{
Dir0=F.cP(1)-F.cP(0);
Dir1=F.cP(2)-F.cP(3);
}
else
{
Dir0=F.cP(2)-F.cP(1);
Dir1=F.cP(3)-F.cP(0);
}
Dir0.Normalize();
Dir1.Normalize();
//then make them lying on face's Normal
CoordType DirPlane0=Dir0*0.5+Dir1*0.5;
CoordType DirPlane1=F.cN();
CoordType NormPlane=DirPlane0^DirPlane1;
NormPlane.Normalize();
CoordType subV0=NormPlane*(NormPlane*Dir0);
CoordType subV1=NormPlane*(NormPlane*Dir1);
Dir0-=subV0;
Dir1-=subV1;
Dir0.Normalize();
Dir1.Normalize();
ScalarType AngleVal=vcg::Angle(Dir0,Dir1);
return AngleVal;
}
template<class PolygonType>
typename PolygonType::ScalarType PolygonBending(const PolygonType &F,int side)
{
typedef typename PolygonType::CoordType CoordType;
typedef typename PolygonType::ScalarType ScalarType;
assert(side>=0);
assert(side<2);
assert(F.VN()==4);
//get firts two edges directions
CoordType Norm0,Norm1;
CoordType Avg0,Avg1;
if (side==0)
{
Norm0=F.V(0)->N()*0.5+F.V(1)->N()*0.5;
Avg0=F.cP(0)*0.5+F.cP(1)*0.5;
Norm1=F.V(2)->N()*0.5+F.V(3)->N()*0.5;
Avg1=F.cP(2)*0.5+F.cP(3)*0.5;
}
else
{
Norm0=F.V(2)->N()*0.5+F.V(1)->N()*0.5;
Avg0=F.cP(2)*0.5+F.cP(1)*0.5;
Norm1=F.V(3)->N()*0.5+F.V(0)->N()*0.5;
Avg1=F.cP(3)*0.5+F.cP(0)*0.5;
}
Norm0.Normalize();
Norm1.Normalize();
//then make them lying on face's Normal
CoordType DirPlane0=Avg0-Avg1;
DirPlane0.Normalize();
CoordType DirPlane1=F.cN();
CoordType NormPlane=DirPlane0^DirPlane1;
NormPlane.Normalize();
CoordType subV0=NormPlane*(NormPlane*Norm0);
CoordType subV1=NormPlane*(NormPlane*Norm1);
Norm0-=subV0;
Norm1-=subV1;
Norm0.Normalize();
Norm1.Normalize();
ScalarType AngleVal=vcg::Angle(Norm0,Norm1);
return AngleVal;
}
template<class PolygonType>
typename PolygonType::ScalarType PolygonBending(const PolygonType &F)
{
typedef typename PolygonType::ScalarType ScalarType;
ScalarType Bend0=PolygonBending(F,0);
ScalarType Bend1=PolygonBending(F,1);
assert(Bend0>=0);
assert(Bend1>=0);
return (std::max(Bend0,Bend1));
}
template<class PolygonType>
typename PolygonType::ScalarType PolygonTorsion(const PolygonType &F)
{
typedef typename PolygonType::ScalarType ScalarType;
ScalarType Torsion0=PolygonTorsion(F,0);
ScalarType Torsion1=PolygonTorsion(F,1);
assert(Torsion0>=0);
assert(Torsion1>=0);
return (std::max(Torsion0,Torsion1));
}
} }
#endif // POLYGON_H #endif // POLYGON_H

View File

@ -86,22 +86,26 @@ public:
fprintf(o,"ENDSEC\n"); fprintf(o,"ENDSEC\n");
fprintf(o,"0\n"); fprintf(o,"0\n");
fprintf(o,"EOF\n"); fprintf(o,"EOF\n");
fclose(o);
return 0; int result = 0;
if (ferror(o)) result = 2;
fclose(o);
return result;
} }
/// Standard call for knowing the meaning of an error code /// Standard call for knowing the meaning of an error code
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
{ {
static std::vector<std::string> dxf_error_msg; static std::vector<std::string> dxf_error_msg;
if(dxf_error_msg.empty()) if (dxf_error_msg.empty())
{ {
dxf_error_msg.resize(2 ); dxf_error_msg.resize(3);
dxf_error_msg[0]="No errors"; dxf_error_msg[0] = "No errors";
dxf_error_msg[1]="Can't open file"; dxf_error_msg[1] = "Can't open file";
} dxf_error_msg[2] = "Output Stream Error";
}
if(error>1 || error<0) return "Unknown error"; if (error>2 || error<0) return "Unknown error";
else return dxf_error_msg[error].c_str(); else return dxf_error_msg[error].c_str();
} }

View File

@ -173,22 +173,27 @@ namespace vcg {
for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi) for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi)
(*vi).Flags()=FlagV[j++]; (*vi).Flags()=FlagV[j++];
return 0;
int result = 0;
if (stream.status() != QTextStream::Ok) result = 3;
stream.flush();
return result;
} }
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
{ {
static std::vector<std::string> off_error_msg; static std::vector<std::string> off_error_msg;
if(off_error_msg.empty()) if (off_error_msg.empty())
{ {
off_error_msg.resize(2 ); off_error_msg.resize(4);
off_error_msg[0]="No errors"; off_error_msg[0] = "No errors";
off_error_msg[1]="Can't open file"; off_error_msg[1] = "Can't open file";
off_error_msg[2]="Internal error"; off_error_msg[2] = "Internal error";
} off_error_msg[3] = "Otput Stream Error";
}
if(error>2 || error<0) return "Unknown error"; if (error>3 || error<0) return "Unknown error";
else return off_error_msg[error].c_str(); else return off_error_msg[error].c_str();
} }
/* /*
returns mask of capability one define with what are the saveable information of the format. returns mask of capability one define with what are the saveable information of the format.

View File

@ -54,15 +54,16 @@ public:
*/ */
enum SaveError enum SaveError
{ {
E_NOERROR, // 0 E_NOERROR, // 0
E_CANTOPENFILE, // 1 E_CANTOPENFILE, // 1
E_CANTCLOSEFILE, // 2 E_CANTCLOSEFILE, // 2
E_UNESPECTEDEOF, // 3 E_UNESPECTEDEOF, // 3
E_ABORTED, // 4 E_ABORTED, // 4
E_NOTDEFINITION, // 5 E_NOTDEFINITION, // 5
E_NO_VERTICES, // 6 E_NO_VERTICES, // 6
E_NOTFACESVALID, // 7 E_NOTFACESVALID, // 7
E_NO_VALID_MATERIAL E_NO_VALID_MATERIAL, // 8
E_STREAMERROR // 9
}; };
/* /*
@ -72,18 +73,19 @@ public:
{ {
static const char* obj_error_msg[] = static const char* obj_error_msg[] =
{ {
"No errors", // 0 "No errors", // 0
"Can't open file", // 1 "Can't open file", // 1
"can't close file", // 2 "can't close file", // 2
"Premature End of file", // 3 "Premature End of file", // 3
"File saving aborted", // 4 "File saving aborted", // 4
"Function not defined", // 5 "Function not defined", // 5
"Vertices not valid", // 6 "Vertices not valid", // 6
"Faces not valid", // 7 "Faces not valid", // 7
"The mesh has not a attribute containing the vector of materials" // 8 "The mesh has not a attribute containing the vector of materials", // 8
"Output Stream Error" //9
}; };
if(error>7 || error<0) return "Unknown error"; if(error>9 || error<0) return "Unknown error";
else return obj_error_msg[error]; else return obj_error_msg[error];
}; };
@ -277,7 +279,6 @@ public:
fprintf(fp,"# %d faces, %d coords texture\n\n",m.fn,int(CoordIndexTexture.size())); fprintf(fp,"# %d faces, %d coords texture\n\n",m.fn,int(CoordIndexTexture.size()));
fprintf(fp,"# End of File\n"); fprintf(fp,"# End of File\n");
fclose(fp);
int errCode = E_NOERROR; int errCode = E_NOERROR;
if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) ) if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) )
@ -286,9 +287,13 @@ public:
else errCode = WriteMaterials(materialVec, filename,cb); else errCode = WriteMaterials(materialVec, filename,cb);
} }
if(errCode!= E_NOERROR) int result = E_NOERROR;
return errCode; if (errCode != E_NOERROR)
return E_NOERROR; result = errCode;
else if (ferror(fp))
result = E_STREAMERROR;
fclose(fp);
return result;
} }
/* /*

View File

@ -139,28 +139,30 @@ public:
} }
} }
fclose(fpout);
// Recupera i flag originali // Recupera i flag originali
j=0; j=0;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
(*vi).Flags()=FlagV[j++]; (*vi).Flags()=FlagV[j++];
return 0; int result = 0;
if (ferror(fpout)) result = 2;
fclose(fpout);
return result;
} }
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
{ {
static std::vector<std::string> off_error_msg; static std::vector<std::string> off_error_msg;
if(off_error_msg.empty()) if (off_error_msg.empty())
{ {
off_error_msg.resize(2 ); off_error_msg.resize(3);
off_error_msg[0]="No errors"; off_error_msg[0] = "No errors";
off_error_msg[1]="Can't open file"; off_error_msg[1] = "Can't open file";
} off_error_msg[1] = "Output Stream error";
}
if(error>1 || error<0) return "Unknown error"; if (error>2 || error<0) return "Unknown error";
else return off_error_msg[error].c_str(); else return off_error_msg[error].c_str();
} }
/* /*
returns mask of capability one define with what are the saveable information of the format. returns mask of capability one define with what are the saveable information of the format.

View File

@ -756,8 +756,10 @@ namespace vcg {
} }
assert(ecnt==m.en); assert(ecnt==m.en);
} }
int result = 0;
if (ferror(fpout)) result = ply::E_STREAMERROR;
fclose(fpout); fclose(fpout);
return 0; return result;
} }
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
@ -766,19 +768,21 @@ namespace vcg {
if(ply_error_msg.empty()) if(ply_error_msg.empty())
{ {
ply_error_msg.resize(PlyInfo::E_MAXPLYINFOERRORS ); ply_error_msg.resize(PlyInfo::E_MAXPLYINFOERRORS );
ply_error_msg[ply::E_NOERROR ]="No errors"; ply_error_msg[ply::E_NOERROR ]="No errors";
ply_error_msg[ply::E_CANTOPEN ]="Can't open file"; ply_error_msg[ply::E_CANTOPEN ]="Can't open file";
ply_error_msg[ply::E_NOTHEADER ]="Header not found"; ply_error_msg[ply::E_NOTHEADER ]="Header not found";
ply_error_msg[ply::E_UNESPECTEDEOF ]="Eof in header"; ply_error_msg[ply::E_UNESPECTEDEOF ]="Eof in header";
ply_error_msg[ply::E_NOFORMAT ]="Format not found"; ply_error_msg[ply::E_NOFORMAT ]="Format not found";
ply_error_msg[ply::E_SYNTAX ]="Syntax error on header"; ply_error_msg[ply::E_SYNTAX ]="Syntax error on header";
ply_error_msg[ply::E_PROPOUTOFELEMENT]="Property without element"; ply_error_msg[ply::E_PROPOUTOFELEMENT ]="Property without element";
ply_error_msg[ply::E_BADTYPENAME ]="Bad type name"; ply_error_msg[ply::E_BADTYPENAME ]="Bad type name";
ply_error_msg[ply::E_ELEMNOTFOUND ]="Element not found"; ply_error_msg[ply::E_ELEMNOTFOUND ]="Element not found";
ply_error_msg[ply::E_PROPNOTFOUND ]="Property not found"; ply_error_msg[ply::E_PROPNOTFOUND ]="Property not found";
ply_error_msg[ply::E_BADTYPE ]="Bad type on addtoread"; ply_error_msg[ply::E_BADTYPE ]="Bad type on addtoread";
ply_error_msg[ply::E_INCOMPATIBLETYPE]="Incompatible type"; ply_error_msg[ply::E_INCOMPATIBLETYPE ]="Incompatible type";
ply_error_msg[ply::E_BADCAST ]="Bad cast"; ply_error_msg[ply::E_BADCAST ]="Bad cast";
ply_error_msg[ply::E_STREAMERROR ] = "Output Stream Error";
ply_error_msg[PlyInfo::E_NO_VERTEX ]="No vertex field found"; ply_error_msg[PlyInfo::E_NO_VERTEX ]="No vertex field found";
ply_error_msg[PlyInfo::E_NO_FACE ]="No face field found"; ply_error_msg[PlyInfo::E_NO_FACE ]="No face field found";

View File

@ -150,21 +150,24 @@ static int Save(SaveMeshType &m, const char * filename , bool binary =true, int
} }
fprintf(fp,"endsolid vcg\n"); fprintf(fp,"endsolid vcg\n");
} }
int result = 0;
if (ferror(fp)) result = 2;
fclose(fp); fclose(fp);
return 0; return result;
} }
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
{ {
static std::vector<std::string> stl_error_msg; static std::vector<std::string> stl_error_msg;
if(stl_error_msg.empty()) if (stl_error_msg.empty())
{ {
stl_error_msg.resize(2 ); stl_error_msg.resize(3);
stl_error_msg[0]="No errors"; stl_error_msg[0] = "No errors";
stl_error_msg[1]="Can't open file"; stl_error_msg[1] = "Can't open file";
} stl_error_msg[2] = "Output Stream error";
}
if(error>1 || error<0) return "Unknown error"; if (error>2 || error<0) return "Unknown error";
else return stl_error_msg[error].c_str(); else return stl_error_msg[error].c_str();
}; };
/* /*

View File

@ -281,8 +281,10 @@ namespace vcg {
" ]\n" " ]\n"
"}\n" "}\n"
); );
int result = 0;
if (ferror(fp)) result = 2;
fclose(fp); fclose(fp);
return 0; return result;
} }
///Returns mask of capability one define with what are the saveable information of the format. ///Returns mask of capability one define with what are the saveable information of the format.
static int GetExportMaskCapability() static int GetExportMaskCapability()
@ -305,11 +307,12 @@ namespace vcg {
static std::vector<std::string> wrl_error_msg; static std::vector<std::string> wrl_error_msg;
if(wrl_error_msg.empty()) if(wrl_error_msg.empty())
{ {
wrl_error_msg.resize(2 ); wrl_error_msg.resize(3);
wrl_error_msg[0]="No errors"; wrl_error_msg[0] = "No errors";
wrl_error_msg[1]="Can't open file"; wrl_error_msg[1] = "Can't open file";
wrl_error_msg[1] = "Output Stream error";
} }
if(error>1 || error<0) return "Unknown error"; if(error>2 || error<0) return "Unknown error";
else return wrl_error_msg[error].c_str(); else return wrl_error_msg[error].c_str();
} }

View File

@ -152,15 +152,15 @@ public:
enum Error enum Error
{ {
// Funzioni superiori // Funzioni superiori
E_NO_VERTEX = ply::E_MAXPLYERRORS+1, // 14 E_NO_VERTEX = ply::E_MAXPLYERRORS+1, // 15
E_NO_FACE = ply::E_MAXPLYERRORS+2, // 15 E_NO_FACE = ply::E_MAXPLYERRORS+2, // 16
E_SHORTFILE = ply::E_MAXPLYERRORS+3, // 16 E_SHORTFILE = ply::E_MAXPLYERRORS+3, // 17
E_NO_3VERTINFACE = ply::E_MAXPLYERRORS+4, // 17 E_NO_3VERTINFACE = ply::E_MAXPLYERRORS+4, // 18
E_BAD_VERT_INDEX = ply::E_MAXPLYERRORS+5, // 18 E_BAD_VERT_INDEX = ply::E_MAXPLYERRORS+5, // 19
E_NO_6TCOORD = ply::E_MAXPLYERRORS+6, // 19 E_NO_6TCOORD = ply::E_MAXPLYERRORS+6, // 20
E_DIFFER_COLORS = ply::E_MAXPLYERRORS+7, E_DIFFER_COLORS = ply::E_MAXPLYERRORS+7, // 21
E_BAD_VERT_INDEX_EDGE = ply::E_MAXPLYERRORS+8, // 18 E_BAD_VERT_INDEX_EDGE = ply::E_MAXPLYERRORS+8, // 22
E_MAXPLYINFOERRORS= ply::E_MAXPLYERRORS+9// 20 E_MAXPLYINFOERRORS= ply::E_MAXPLYERRORS+9 // 23
}; };
}; // end class }; // end class

View File

@ -91,6 +91,8 @@ enum PlyError {
E_BADTYPE, // 10 E_BADTYPE, // 10
E_INCOMPATIBLETYPE, // 11 E_INCOMPATIBLETYPE, // 11
E_BADCAST, // 12 E_BADCAST, // 12
//saving error
E_STREAMERROR, // 13
E_MAXPLYERRORS E_MAXPLYERRORS
}; };