From 8bb8e592186bcbca165b3bb91d9c863407478a10 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Sat, 5 May 2018 00:32:26 +0200 Subject: [PATCH 01/12] Significant Change: FaceCrease bit removed and added FaceEdge Selection Bit The Crease bit was never seriously used and in many cases we mis-used the faux edge bit at its place. Now has a more significant name and can be used in practice to mark/select edges over a mesh (without explicitly storing them). --- vcg/simplex/face/base.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/vcg/simplex/face/base.h b/vcg/simplex/face/base.h index 5ffd8201..ed369f01 100644 --- a/vcg/simplex/face/base.h +++ b/vcg/simplex/face/base.h @@ -110,10 +110,11 @@ public: NORMX = 0x00000200, NORMY = 0x00000400, NORMZ = 0x00000800, - // Crease _flags, it is assumed that CREASEi = CREASE0<Flags() &= (~(BORDER0<cFlags() & (CREASE0<Flags() |=(CREASE0<Flags() &= (~(CREASE0<cFlags() & (FACEEDGESEL0<Flags() |=(FACEEDGESEL0<Flags() &= (~(FACEEDGESEL0< Date: Sat, 5 May 2018 00:33:38 +0200 Subject: [PATCH 02/12] Updated the pos to do not use crease stuff and added selection helpers for pos --- vcg/simplex/face/pos.h | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/vcg/simplex/face/pos.h b/vcg/simplex/face/pos.h index d6d0c735..e0212798 100644 --- a/vcg/simplex/face/pos.h +++ b/vcg/simplex/face/pos.h @@ -289,40 +289,12 @@ public: //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 bool IsBorder()const { return face::IsBorder(*f,z); } - /// Checks if the half-edge is of crease - bool IsCrease() const - { - return f->IsCrease(z); - } - bool IsFaux() const { return (f->IsF(z)); @@ -333,6 +305,10 @@ public: 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. */ From 884faa97c1460ba1fd9c57f3af7d44f30accec37 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Sat, 5 May 2018 00:36:43 +0200 Subject: [PATCH 03/12] Added FillSelectedFaceEdgeVector FaceEdgeSelCrease and BuildFromFaceEdgeSel function It is much more meaningful to create a poly mesh from selected edges instead abusing of the faux edges bit Similarly it much butter to select crease edges for subsuequent uses --- vcg/complex/algorithms/create/platonic.h | 4 +-- vcg/complex/algorithms/update/flag.h | 40 +++++++++++------------- vcg/complex/algorithms/update/topology.h | 15 ++++++++- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/vcg/complex/algorithms/create/platonic.h b/vcg/complex/algorithms/create/platonic.h index 24f9333e..8b4d906e 100644 --- a/vcg/complex/algorithms/create/platonic.h +++ b/vcg/complex/algorithms/create/platonic.h @@ -768,11 +768,11 @@ void BuildMeshFromCoordVector( MeshType & in, const V & v) template -void BuildFromNonFaux(TriMeshType &in, EdgeMeshType &out) +void BuildFromFaceEdgeSel(TriMeshType &in, EdgeMeshType &out) { tri::RequireCompactness(in); std::vector::PEdge> edgevec; - tri::UpdateTopology::FillUniqueEdgeVector(in, edgevec, false); + tri::UpdateTopology::FillSelectedFaceEdgeVector(in, edgevec); out.Clear(); for(size_t i=0;i::AddVertex(out, in.vert[i].P()); diff --git a/vcg/complex/algorithms/update/flag.h b/vcg/complex/algorithms/update/flag.h index 359d3256..8963342a 100644 --- a/vcg/complex/algorithms/update/flag.h +++ b/vcg/complex/algorithms/update/flag.h @@ -122,10 +122,7 @@ public: static void FaceClearB(MeshType &m) { FaceClear(m,FaceType::BORDER012);} static void FaceClearS(MeshType &m) {FaceClear(m,FaceType::SELECTED);} static void FaceClearF(MeshType &m) { FaceClear(m,FaceType::FAUX012);} - static void FaceClearCreases(MeshType &m) { FaceClear(m,FaceType::CREASE0); - FaceClear(m,FaceType::CREASE1); - FaceClear(m,FaceType::CREASE2); - } + static void FaceClearFaceEdgeS(MeshType &m) { FaceClear(m,FaceType::FACEEDGESEL012 ); } static void EdgeSetV(MeshType &m) { EdgeSet(m,EdgeType::VISITED);} static void VertexSetV(MeshType &m) { VertexSet(m,VertexType::VISITED);} @@ -380,20 +377,20 @@ public: /// \brief Marks feature edges according to two signed dihedral angles. - /// Actually it marks as fauxedges all the non feature edges, - /// e.g. the edges where the signed dihedral angle between the normal of two incident faces , - /// is between 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) + /// Actually it uses the face_edge selection bit on faces, + /// we select the edges where the signed dihedral angle between the normal of two incident faces , + /// is outside the two given thresholds. + /// 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); /// /// 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); RequireFFAdjacency(m); //initially Nothing is faux (e.g all crease) - FaceClearF(m); + FaceClearFaceEdgeS(m); // 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()) { @@ -402,12 +399,12 @@ public: if(!face::IsBorder(*fi,z) ) { ScalarType angle = DihedralAngleRad(*fi,z); - if(angle>AngleRadNeg && angleAngleRadPos) + (*fi).SetFaceEdgeS(z); } else { - if(MarkBorderFlag) (*fi).SetF(z); + if(MarkBorderFlag) (*fi).SetFaceEdgeS(z); } } } @@ -416,29 +413,30 @@ public: /// \brief Marks feature edges according to border flag. /// Actually it marks as fauxedges all the non border edges, /// - static void FaceFauxBorder(MeshType &m) + static void FaceEdgeSelBorder(MeshType &m) { RequirePerFaceFlags(m); RequireFFAdjacency(m); //initially Nothing is faux (e.g all crease) - FaceClearF(m); + FaceClearFaceEdgeS(m); // 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(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 - /// Actually it marks as fauxedges all the non feature edges, - /// e.g. the edge such that the angle between the normal of two faces sharing it is less than the given threshold. - /// In this way all the near planar edges are marked as Faux Edges (e.g. edges to be ignored) - static void FaceFauxCrease(MeshType &m,float AngleRad) + /// Actually it uses the face_edge selection bit on faces, + /// we select the edges where the dihedral angle between the normal of two incident faces is larger than , + /// the given thresholds. + /// 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); } diff --git a/vcg/complex/algorithms/update/topology.h b/vcg/complex/algorithms/update/topology.h index d37ddab5..3afd7168 100644 --- a/vcg/complex/algorithms/update/topology.h +++ b/vcg/complex/algorithms/update/topology.h @@ -138,6 +138,20 @@ static void FillUniqueEdgeVector(MeshType &m, std::vector &edgeVec, bool edgeVec.resize(newEnd-edgeVec.begin()); // redundant! remove? } +static void FillSelectedFaceEdgeVector(MeshType &m, std::vector &edgeVec) +{ + edgeVec.reserve(m.fn*3); + ForEachFace(m, [&](FaceType &f){ + for(int j=0;j vei(&*vi);!vei.End();++vei) cnt++; - EdgeType *vep = vi->VEp(); assert((numVertex[tri::Index(m,*vi)] == 0) == (vi->VEp()==0) ); assert(cnt==numVertex[tri::Index(m,*vi)]); } From 18e424b7c04a1ec2ce2a2bc7649f67f6fdcf1c8d Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Sat, 5 May 2018 00:37:33 +0200 Subject: [PATCH 04/12] Updated the functions that cuts along crease edges to use the new faceedge selections --- vcg/complex/algorithms/crease_cut.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vcg/complex/algorithms/crease_cut.h b/vcg/complex/algorithms/crease_cut.h index a33ea9ad..ea7f2a59 100644 --- a/vcg/complex/algorithms/crease_cut.h +++ b/vcg/complex/algorithms/crease_cut.h @@ -35,8 +35,8 @@ namespace tri { template void CreaseCut(MESH_TYPE &m, float angleRad) { - tri::UpdateFlags::FaceFauxSignedCrease(m, -angleRad, angleRad); - CutMeshAlongNonFauxEdges(m); + tri::UpdateFlags::FaceEdgeSelSignedCrease(m, -angleRad, angleRad); + CutMeshAlongSelectedFaceEdges(m); } /** @@ -48,7 +48,7 @@ void CreaseCut(MESH_TYPE &m, float angleRad) * */ template -void CutMeshAlongNonFauxEdges(MESH_TYPE &m) +void CutMeshAlongSelectedFaceEdges(MESH_TYPE &m) { typedef typename MESH_TYPE::FaceIterator FaceIterator; typedef typename MESH_TYPE::FaceType FaceType; @@ -86,7 +86,7 @@ void CutMeshAlongNonFauxEdges(MESH_TYPE &m) { do { curPos.FlipF();curPos.FlipE(); - if(!curPos.IsFaux()) + if(curPos.IsEdgeS()) break; } while(curPos!=startPos); startPos=curPos; @@ -100,7 +100,7 @@ void CutMeshAlongNonFauxEdges(MESH_TYPE &m) size_t faceInd = Index(m,curPos.F()); indVec[faceInd*3+ curPos.VInd()] = curVertexCounter; curPos.FlipE(); - if(!curPos.IsFaux()) + if(curPos.IsEdgeS()) { //qDebug(" Crease FOUND"); ++locCreaseCounter; curVertexCounter=newVertexCounter; From c627b31e59929ed4a9523a7cf08f910885c02214 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Sat, 5 May 2018 00:38:41 +0200 Subject: [PATCH 05/12] Cleaned up the CoM (curve on manifold) class and revised the sample using it --- .../trimesh_topological_cut.cpp | 68 +++---- vcg/complex/algorithms/curve_on_manifold.h | 8 +- vcg/complex/algorithms/cut_tree.h | 171 ++++++++++++++++-- 3 files changed, 192 insertions(+), 55 deletions(-) diff --git a/apps/sample/trimesh_topological_cut/trimesh_topological_cut.cpp b/apps/sample/trimesh_topological_cut/trimesh_topological_cut.cpp index 3bb5daac..8584e585 100644 --- a/apps/sample/trimesh_topological_cut/trimesh_topological_cut.cpp +++ b/apps/sample/trimesh_topological_cut/trimesh_topological_cut.cpp @@ -39,57 +39,63 @@ struct MyUsedTypes : public UsedTypes::AsVertexType, Use:: 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 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, std::vector, std::vector >{}; - +/** + * 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 ) { MyMesh base, basecopy, poly; - int ret0 = tri::io::Importer::Open(base,argv[1]); - int ret1 = 0; - if(argc>2) ret1 = tri::io::Importer::Open(poly,argv[2]); - if(ret0 != 0 || ret1 != 0) - { - printf("Failed Loading\n"); - exit(-1); - } + int ret0=0, ret1=0; + if(argc>1) ret0 = tri::io::Importer::Open(base,argv[1]); + if(base.FN() == 0) Torus(base,10,4,48,24); + + if(argc>2) ret1 = tri::io::Importer::Open(poly,argv[2]); tri::UpdateBounding::Box(base); 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() ); - if(poly.EN()==0) { - srand(time(0)); + if(poly.EN() == 0) { + srand(time(nullptr)); tri::CutTree ct(base); - ct.BuildVisitTree(poly,rand()%base.fn); + ct.Build(poly,rand()%base.fn); } tri::io::ExporterPLY::Save(poly,"0_cut_tree.ply",tri::io::Mask::IOM_EDGEINDEX); - + tri::CoM cc(base); cc.Init(); - cc.MarkFauxEdgeWithPolyLine(poly); - tri::Append::MeshCopy(basecopy,base); - tri::UpdateTopology::FaceFace(basecopy); - tri::CutMeshAlongNonFauxEdges(basecopy); - tri::io::ExporterPLY::Save(basecopy,"base_cut_with_tree.ply"); - + bool ret = cc.TagFaceEdgeSelWithPolyLine(poly); + if(ret) + { + tri::Append::MeshCopy(basecopy,base); + tri::UpdateTopology::FaceFace(basecopy); + tri::CutMeshAlongSelectedFaceEdges(basecopy); + tri::io::ExporterPLY::Save(basecopy,"base_cut_with_tree.ply"); + } // Selected vertices are 'locked' during the smoothing. 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, // 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.maxSimpEdgeLen = base.bbox.Diag()/50.0; - cc.par.minRefEdgeLen = base.bbox.Diag()/100.0; - cc.SmoothProject(poly,10,0.7,.3); + cc.par.surfDistThr = base.bbox.Diag()/100.0f; + cc.par.maxSimpEdgeLen = base.bbox.Diag()/50.0f; + cc.par.minRefEdgeLen = base.bbox.Diag()/100.0f; + cc.SmoothProject(poly,30,0.7f,.3f); tri::io::ExporterPLY::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 - cc.par.surfDistThr = base.bbox.Diag()/1000.0; - cc.par.maxSimpEdgeLen = base.bbox.Diag()/1000.0; - cc.par.minRefEdgeLen = base.bbox.Diag()/2000.0; - cc.SmoothProject(poly,10,0.01,.99); + cc.par.surfDistThr = base.bbox.Diag()/1000.0f; + cc.par.maxSimpEdgeLen = base.bbox.Diag()/1000.0f; + cc.par.minRefEdgeLen = base.bbox.Diag()/2000.0f; + cc.SmoothProject(poly,10,0.01f,.99f); tri::io::ExporterPLY::Save(poly,"2_poly_smooth.ply",tri::io::Mask::IOM_EDGEINDEX+tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); Distribution dist; @@ -102,8 +108,8 @@ int main(int argc,char ** argv ) cc.SplitMeshWithPolyline(poly); tri::io::ExporterPLY::Save(base,"3_mesh_refined.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); // Now the two meshes should have coincident edges - cc.MarkFauxEdgeWithPolyLine(poly); - CutMeshAlongNonFauxEdges(base); + cc.TagFaceEdgeSelWithPolyLine(poly); + CutMeshAlongSelectedFaceEdges(base); tri::io::ExporterPLY::Save(base,"4_mesh_cut.ply",tri::io::Mask::IOM_VERTCOLOR+tri::io::Mask::IOM_VERTQUALITY); return 0; diff --git a/vcg/complex/algorithms/curve_on_manifold.h b/vcg/complex/algorithms/curve_on_manifold.h index 9ea56889..1789b841 100644 --- a/vcg/complex/algorithms/curve_on_manifold.h +++ b/vcg/complex/algorithms/curve_on_manifold.h @@ -184,9 +184,9 @@ public: * */ - bool MarkFauxEdgeWithPolyLine(MeshType &poly,bool markFlag=true) + bool TagFaceEdgeSelWithPolyLine(MeshType &poly,bool markFlag=true) { - if(markFlag) tri::UpdateFlags::FaceSetF(base); + if(markFlag) tri::UpdateFlags::FaceClearFaceEdgeS(base); tri::UpdateTopology::VertexFace(base); tri::UpdateTopology::FaceFace(base); @@ -210,8 +210,8 @@ public: if(ret){ assert(ret); assert(ff0->V(e0)==v0 || ff0->V(e0)==v1); - ff0->ClearF(e0); - ff1->ClearF(e1); + ff0->SetFaceEdgeS(e0); + ff1->SetFaceEdgeS(e1); } else { return false; diff --git a/vcg/complex/algorithms/cut_tree.h b/vcg/complex/algorithms/cut_tree.h index 05c66e38..325e70a7 100644 --- a/vcg/complex/algorithms/cut_tree.h +++ b/vcg/complex/algorithms/cut_tree.h @@ -23,6 +23,11 @@ #ifndef CUT_TREE_H #define CUT_TREE_H +#include +#include +#include +#include + namespace vcg { namespace tri { @@ -40,19 +45,18 @@ public: typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; - typedef Box3 Box3Type; - typedef typename vcg::GridStaticPtr MeshGrid; - typedef typename vcg::GridStaticPtr EdgeGrid; + typedef Box3 Box3Type; typedef typename face::Pos PosType; typedef typename tri::UpdateTopology::PEdge PEdge; MeshType &base; -// MeshGrid uniformGrid; -// Param par; 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 &kdtree, MeshType &t) { tri::Allocator::CompactEveryVector(t); @@ -67,7 +71,7 @@ void OptimizeTree(KdTree &kdtree, MeshType &t) { std::vector starVec; edge::VVStarVE(&*vi,starVec); - if(starVec.size()==2) + if(starVec.size()==2) // middle vertex has to be 1-manifold { PosType pos; if(ExistEdge(kdtree,starVec[0]->P(),starVec[1]->P(),pos)) @@ -181,10 +185,10 @@ void Retract(KdTree &kdtree, MeshType &t) if(fpos.IsBorder()) { t.edge[i].SetV(); } - } + } else assert(0); } - + // 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) for(size_t i =0; i &kdtree, MeshType &t) tri::Allocator::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::FaceFace(base); + tri::UpdateTopology::VertexFace(base); + + BuildVisitTree(dualMesh,startingFaceInd); +// BuildDijkstraVisitTree(dualMesh,startingFaceInd); + + VertexConstDataWrapper vdw(base); + KdTree kdtree(vdw); + Retract(kdtree,dualMesh); + OptimizeTree(kdtree, dualMesh); + tri::UpdateBounding::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::max()) +{ + tri::RequireFFAdjacency(base); + tri::RequirePerFaceMark(base); + tri::RequirePerFaceQuality(base); + typename MeshType::template PerFaceAttributeHandle parentHandle + = tri::Allocator::template GetPerFaceAttribute(base, "parent"); + + std::vector seedVec; + seedVec.push_back(&base.face[startingFaceInd]); + + std::vector Heap; + tri::UnMarkAll(base); + tri::UpdateQuality::FaceConstant(base,0); + ForEachVertex(base, [&](VertexType &v){ + tri::Allocator::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;iQ()=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::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::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::RemoveDuplicateVertex(dualMesh,false); printf("Removed %i dup vert\n",dupVert); + int dupEdge=tri::Clean::RemoveDuplicateEdge(dualMesh); printf("Removed %i dup edges %i\n",dupEdge,dualMesh.EN()); + tri::Clean::RemoveUnreferencedVertex(dualMesh); + + tri::io::ExporterPLY::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX); + tri::UpdateColor::PerFaceQualityRamp(base); + tri::io::ExporterPLY::Save(base,"colored_Bydistance.ply",tri::io::Mask::IOM_FACECOLOR); +} // \brief This function build a cut tree. // @@ -207,9 +348,6 @@ void Retract(KdTree &kdtree, MeshType &t) void BuildVisitTree(MeshType &dualMesh, int startingFaceInd=0) { - tri::UpdateTopology::FaceFace(base); - tri::UpdateTopology::VertexFace(base); - tri::UpdateFlags::FaceClearV(base); tri::UpdateFlags::VertexBorderFromFaceAdj(base); std::vector > 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); - - VertexConstDataWrapper vdw(base); - KdTree kdtree(vdw); - + tri::Clean::RemoveDuplicateVertex(dualMesh); -// tri::io::ExporterPLY::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX); - - Retract(kdtree,dualMesh); - OptimizeTree(kdtree, dualMesh); - tri::UpdateBounding::Box(dualMesh); + tri::io::ExporterPLY::Save(dualMesh,"fulltree.ply",tri::io::Mask::IOM_EDGEINDEX); } }; From f8c3e2baef0ca333ac6f6e2d29fa913603d95793 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Sat, 5 May 2018 11:28:47 +0200 Subject: [PATCH 06/12] updating code according the Faux/Crease -> edgesel changes --- apps/sample/trimesh_sampling/trimesh_sampling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sample/trimesh_sampling/trimesh_sampling.cpp b/apps/sample/trimesh_sampling/trimesh_sampling.cpp index a7eed20c..3a065e90 100644 --- a/apps/sample/trimesh_sampling/trimesh_sampling.cpp +++ b/apps/sample/trimesh_sampling/trimesh_sampling.cpp @@ -89,7 +89,7 @@ int main( int argc, char **argv ) tri::TrivialSampler mps(sampleVec); tri::UpdateTopology::FaceFace(m); tri::UpdateNormal::PerFace(m); - tri::UpdateFlags::FaceFauxCrease(m,math::ToRad(40.0f)); + tri::UpdateFlags::FaceEdgeSelCrease(m,math::ToRad(40.0f)); tri::SurfaceSampling >::EdgeMontecarlo(m,mps,10000,false); tri::BuildMeshFromCoordVector(MontecarloEdgeMesh,sampleVec); tri::io::ExporterOFF::Save(MontecarloEdgeMesh,"MontecarloEdgeMesh.off"); From ad5183e567eb5f15f5457ea9a9daf98fc1731a86 Mon Sep 17 00:00:00 2001 From: Andrea Maggiordomo Date: Mon, 7 May 2018 10:14:00 +0200 Subject: [PATCH 07/12] isotropic remeshing: added early face selection check in collapse functions --- vcg/complex/algorithms/isotropic_remeshing.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vcg/complex/algorithms/isotropic_remeshing.h b/vcg/complex/algorithms/isotropic_remeshing.h index e988dc13..0622ce49 100644 --- a/vcg/complex/algorithms/isotropic_remeshing.h +++ b/vcg/complex/algorithms/isotropic_remeshing.h @@ -475,14 +475,14 @@ private: tri::UpdateFlags::VertexBorderFromNone(m); 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) { PosType pi(&*fi, i); ++candidates; VertexPair bp = VertexPair(pi.V(), pi.VFlip()); - Point3 mp = (pi.V()->P()+pi.VFlip()->P())/2.f;; + Point3 mp = (pi.V()->P()+pi.VFlip()->P())/2.f; bool boundary = false; if(pi.V()->IsB() == pi.VFlip()->IsB()) @@ -581,7 +581,7 @@ private: int count = 0; 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) { From 70a141db69ed9de490f5391a5085e19ac8f64f4b Mon Sep 17 00:00:00 2001 From: Luigi Malomo Date: Mon, 7 May 2018 20:24:39 +0200 Subject: [PATCH 08/12] indent and spelling fix --- vcg/complex/algorithms/curve_on_manifold.h | 79 +++++++++++----------- vcg/complex/algorithms/point_sampling.h | 2 +- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/vcg/complex/algorithms/curve_on_manifold.h b/vcg/complex/algorithms/curve_on_manifold.h index 1789b841..1bc35938 100644 --- a/vcg/complex/algorithms/curve_on_manifold.h +++ b/vcg/complex/algorithms/curve_on_manifold.h @@ -184,47 +184,50 @@ public: * */ - bool TagFaceEdgeSelWithPolyLine(MeshType &poly,bool markFlag=true) - { - if(markFlag) tri::UpdateFlags::FaceClearFaceEdgeS(base); - tri::UpdateTopology::VertexFace(base); - tri::UpdateTopology::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); +bool TagFaceEdgeSelWithPolyLine(MeshType &poly,bool markFlag=true) +{ + if (markFlag) + tri::UpdateFlags::FaceClearFaceEdgeS(base); - if(v0==0 || v1==0) return false; - if(v0==v1) return false; + tri::UpdateTopology::VertexFace(base); + tri::UpdateTopology::FaceFace(base); - FacePointer ff0,ff1; - int e0,e1; - bool ret=face::FindSharedFaces(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; - } + 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; + if(v0==v1) + return false; + + FacePointer ff0,ff1; + int e0,e1; + bool ret=face::FindSharedFaces(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 polyDist; diff --git a/vcg/complex/algorithms/point_sampling.h b/vcg/complex/algorithms/point_sampling.h index a0712c9e..6d610c5d 100644 --- a/vcg/complex/algorithms/point_sampling.h +++ b/vcg/complex/algorithms/point_sampling.h @@ -759,7 +759,7 @@ static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum) /// /// It assumes that the mesh is 1-manifold. /// each connected component is sampled in a independent way. -/// For each component of lenght we place on it floor(L/radius)+1 samples. +/// For each component of length we place on it floor(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) From 69d2abd146db7360776714c26ecbc64d0720728c Mon Sep 17 00:00:00 2001 From: Luigi Malomo Date: Mon, 7 May 2018 20:26:01 +0200 Subject: [PATCH 09/12] updated edge refine function to preserve FaceEdgeSelection flags --- vcg/complex/algorithms/refine.h | 69 ++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/vcg/complex/algorithms/refine.h b/vcg/complex/algorithms/refine.h index 8f3539af..da3fef7e 100644 --- a/vcg/complex/algorithms/refine.h +++ b/vcg/complex/algorithms/refine.h @@ -316,8 +316,8 @@ class RefinedFaceData { public: RefinedFaceData(){ - ep[0]=0;ep[1]=0;ep[2]=0; - vp[0]=0;vp[1]=0;vp[2]=0; + ep[0] = ep[1] = ep[2] = false; + vp[0] = vp[1] = vp[2] = NULL; } bool ep[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 // 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()) { - if(cb && (++step%PercStep)==0)(*cb)(step/PercStep,"Refining..."); - fcn++; + if(cb && (++step%PercStep)==0) + (*cb)(step/PercStep,"Refining..."); vv[0]=(*fi).V(0); vv[1]=(*fi).V(1); 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[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; int i; @@ -468,29 +468,41 @@ bool RefineE(MESH_TYPE &m, MIDPOINT &mid, EDGEPRED &ep,bool RefineSelected=false } - if(tri::HasPerWedgeTexCoord(m)) - for(i=0;i<3;++i) { - wtt[i]=(*fi).WT(i); - wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3)); - } + if(tri::HasPerWedgeTexCoord(m)) + for(i=0;i<3;++i) + { + wtt[i]=(*fi).WT(i); + wtt[3+i]=mid.WedgeInterp((*fi).WT(i),(*fi).WT((i+1)%3)); + } - int orgflag= (*fi).Flags(); - for(i=0;iP(),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); (*nf[1]).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); } } From 715fc36c0c80ad24ffb1305b7c5aa826457bd791 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 9 May 2018 22:02:25 +1000 Subject: [PATCH 10/12] added PolygonBending and PolygonTorsion functions --- vcg/space/polygon3.h | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/vcg/space/polygon3.h b/vcg/space/polygon3.h index 38e57f1e..2e02e6fc 100644 --- a/vcg/space/polygon3.h +++ b/vcg/space/polygon3.h @@ -564,5 +564,116 @@ vcg::Box3 PolygonBox(const PolygonType &F) bb.Add(F.V(j)->P()); return bb; } + +template +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 +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 +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 +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 From acdcb30360936f160b9d253772bfd58e5dc35324 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 9 May 2018 22:02:55 +1000 Subject: [PATCH 11/12] added InitQualityFaceTorsion and InitQualityFaceBending --- vcg/complex/algorithms/polygonal_algorithms.h | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/vcg/complex/algorithms/polygonal_algorithms.h b/vcg/complex/algorithms/polygonal_algorithms.h index a839af28..1bf179d6 100644 --- a/vcg/complex/algorithms/polygonal_algorithms.h +++ b/vcg/complex/algorithms/polygonal_algorithms.h @@ -1113,6 +1113,33 @@ public: } } + static ScalarType InitQualityFaceTorsion(PolyMeshType &poly_m) + { + UpdateFaceNormalByFitting(poly_m); + vcg::tri::UpdateNormal::PerVertexFromCurrentFaceNormal(poly_m); + ScalarType MaxA=0; + for (size_t i=0;i::PerVertexFromCurrentFaceNormal(poly_m); + ScalarType MaxA=0; + for (size_t i=0;i Date: Wed, 9 May 2018 14:06:32 +0200 Subject: [PATCH 12/12] added check for save errors --- wrap/io_trimesh/export_dxf.h | 26 ++++++++++-------- wrap/io_trimesh/export_gts.h | 27 +++++++++++-------- wrap/io_trimesh/export_obj.h | 51 +++++++++++++++++++---------------- wrap/io_trimesh/export_off.h | 26 +++++++++--------- wrap/io_trimesh/export_ply.h | 24 ++++++++++------- wrap/io_trimesh/export_stl.h | 23 +++++++++------- wrap/io_trimesh/export_vrml.h | 13 +++++---- wrap/io_trimesh/io_ply.h | 18 ++++++------- wrap/ply/plylib.h | 2 ++ 9 files changed, 119 insertions(+), 91 deletions(-) diff --git a/wrap/io_trimesh/export_dxf.h b/wrap/io_trimesh/export_dxf.h index 56e7323b..7f4e8557 100644 --- a/wrap/io_trimesh/export_dxf.h +++ b/wrap/io_trimesh/export_dxf.h @@ -86,22 +86,26 @@ public: fprintf(o,"ENDSEC\n"); fprintf(o,"0\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 static const char *ErrorMsg(int error) { - static std::vector dxf_error_msg; - if(dxf_error_msg.empty()) - { - dxf_error_msg.resize(2 ); - dxf_error_msg[0]="No errors"; - dxf_error_msg[1]="Can't open file"; - } + static std::vector dxf_error_msg; + if (dxf_error_msg.empty()) + { + dxf_error_msg.resize(3); + dxf_error_msg[0] = "No errors"; + dxf_error_msg[1] = "Can't open file"; + dxf_error_msg[2] = "Output Stream Error"; + } - if(error>1 || error<0) return "Unknown error"; - else return dxf_error_msg[error].c_str(); + if (error>2 || error<0) return "Unknown error"; + else return dxf_error_msg[error].c_str(); } diff --git a/wrap/io_trimesh/export_gts.h b/wrap/io_trimesh/export_gts.h index 83bf9cfe..4af571cb 100644 --- a/wrap/io_trimesh/export_gts.h +++ b/wrap/io_trimesh/export_gts.h @@ -173,22 +173,27 @@ namespace vcg { for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi) (*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 std::vector off_error_msg; - if(off_error_msg.empty()) - { - off_error_msg.resize(2 ); - off_error_msg[0]="No errors"; - off_error_msg[1]="Can't open file"; - off_error_msg[2]="Internal error"; - } + static std::vector off_error_msg; + if (off_error_msg.empty()) + { + off_error_msg.resize(4); + off_error_msg[0] = "No errors"; + off_error_msg[1] = "Can't open file"; + off_error_msg[2] = "Internal error"; + off_error_msg[3] = "Otput Stream Error"; + } - if(error>2 || error<0) return "Unknown error"; - else return off_error_msg[error].c_str(); + if (error>3 || error<0) return "Unknown error"; + else return off_error_msg[error].c_str(); } /* returns mask of capability one define with what are the saveable information of the format. diff --git a/wrap/io_trimesh/export_obj.h b/wrap/io_trimesh/export_obj.h index 0f96aeee..c34d4b80 100644 --- a/wrap/io_trimesh/export_obj.h +++ b/wrap/io_trimesh/export_obj.h @@ -54,15 +54,16 @@ public: */ enum SaveError { - E_NOERROR, // 0 - E_CANTOPENFILE, // 1 - E_CANTCLOSEFILE, // 2 - E_UNESPECTEDEOF, // 3 - E_ABORTED, // 4 - E_NOTDEFINITION, // 5 - E_NO_VERTICES, // 6 - E_NOTFACESVALID, // 7 - E_NO_VALID_MATERIAL + E_NOERROR, // 0 + E_CANTOPENFILE, // 1 + E_CANTCLOSEFILE, // 2 + E_UNESPECTEDEOF, // 3 + E_ABORTED, // 4 + E_NOTDEFINITION, // 5 + E_NO_VERTICES, // 6 + E_NOTFACESVALID, // 7 + E_NO_VALID_MATERIAL, // 8 + E_STREAMERROR // 9 }; /* @@ -72,18 +73,19 @@ public: { static const char* obj_error_msg[] = { - "No errors", // 0 - "Can't open file", // 1 - "can't close file", // 2 - "Premature End of file", // 3 - "File saving aborted", // 4 - "Function not defined", // 5 - "Vertices not valid", // 6 - "Faces not valid", // 7 - "The mesh has not a attribute containing the vector of materials" // 8 + "No errors", // 0 + "Can't open file", // 1 + "can't close file", // 2 + "Premature End of file", // 3 + "File saving aborted", // 4 + "Function not defined", // 5 + "Vertices not valid", // 6 + "Faces not valid", // 7 + "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]; }; @@ -277,7 +279,6 @@ public: fprintf(fp,"# %d faces, %d coords texture\n\n",m.fn,int(CoordIndexTexture.size())); fprintf(fp,"# End of File\n"); - fclose(fp); int errCode = E_NOERROR; if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) ) @@ -286,9 +287,13 @@ public: else errCode = WriteMaterials(materialVec, filename,cb); } - if(errCode!= E_NOERROR) - return errCode; - return E_NOERROR; + int result = E_NOERROR; + if (errCode != E_NOERROR) + result = errCode; + else if (ferror(fp)) + result = E_STREAMERROR; + fclose(fp); + return result; } /* diff --git a/wrap/io_trimesh/export_off.h b/wrap/io_trimesh/export_off.h index 1da346dc..26a0e019 100644 --- a/wrap/io_trimesh/export_off.h +++ b/wrap/io_trimesh/export_off.h @@ -139,28 +139,30 @@ public: } } - - fclose(fpout); // Recupera i flag originali j=0; for(vi=m.vert.begin();vi!=m.vert.end();++vi) (*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 std::vector off_error_msg; - if(off_error_msg.empty()) - { - off_error_msg.resize(2 ); - off_error_msg[0]="No errors"; - off_error_msg[1]="Can't open file"; - } + static std::vector off_error_msg; + if (off_error_msg.empty()) + { + off_error_msg.resize(3); + off_error_msg[0] = "No errors"; + off_error_msg[1] = "Can't open file"; + off_error_msg[1] = "Output Stream error"; + } - if(error>1 || error<0) return "Unknown error"; - else return off_error_msg[error].c_str(); + if (error>2 || error<0) return "Unknown error"; + else return off_error_msg[error].c_str(); } /* returns mask of capability one define with what are the saveable information of the format. diff --git a/wrap/io_trimesh/export_ply.h b/wrap/io_trimesh/export_ply.h index afa3c23c..3bd6208d 100644 --- a/wrap/io_trimesh/export_ply.h +++ b/wrap/io_trimesh/export_ply.h @@ -756,8 +756,10 @@ namespace vcg { } assert(ecnt==m.en); } + int result = 0; + if (ferror(fpout)) result = ply::E_STREAMERROR; fclose(fpout); - return 0; + return result; } static const char *ErrorMsg(int error) @@ -766,19 +768,21 @@ namespace vcg { if(ply_error_msg.empty()) { ply_error_msg.resize(PlyInfo::E_MAXPLYINFOERRORS ); - ply_error_msg[ply::E_NOERROR ]="No errors"; - ply_error_msg[ply::E_CANTOPEN ]="Can't open file"; - ply_error_msg[ply::E_NOTHEADER ]="Header not found"; - ply_error_msg[ply::E_UNESPECTEDEOF ]="Eof in header"; - ply_error_msg[ply::E_NOFORMAT ]="Format not found"; + ply_error_msg[ply::E_NOERROR ]="No errors"; + ply_error_msg[ply::E_CANTOPEN ]="Can't open file"; + ply_error_msg[ply::E_NOTHEADER ]="Header not found"; + ply_error_msg[ply::E_UNESPECTEDEOF ]="Eof in header"; + ply_error_msg[ply::E_NOFORMAT ]="Format not found"; 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_ELEMNOTFOUND ]="Element 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_INCOMPATIBLETYPE]="Incompatible type"; - ply_error_msg[ply::E_BADCAST ]="Bad cast"; + ply_error_msg[ply::E_BADTYPE ]="Bad type on addtoread"; + ply_error_msg[ply::E_INCOMPATIBLETYPE ]="Incompatible type"; + 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_FACE ]="No face field found"; diff --git a/wrap/io_trimesh/export_stl.h b/wrap/io_trimesh/export_stl.h index ff32d064..50859273 100644 --- a/wrap/io_trimesh/export_stl.h +++ b/wrap/io_trimesh/export_stl.h @@ -150,21 +150,24 @@ static int Save(SaveMeshType &m, const char * filename , bool binary =true, int } fprintf(fp,"endsolid vcg\n"); } + int result = 0; + if (ferror(fp)) result = 2; fclose(fp); - return 0; + return result; } static const char *ErrorMsg(int error) { - static std::vector stl_error_msg; - if(stl_error_msg.empty()) - { - stl_error_msg.resize(2 ); - stl_error_msg[0]="No errors"; - stl_error_msg[1]="Can't open file"; - } + static std::vector stl_error_msg; + if (stl_error_msg.empty()) + { + stl_error_msg.resize(3); + stl_error_msg[0] = "No errors"; + stl_error_msg[1] = "Can't open file"; + stl_error_msg[2] = "Output Stream error"; + } - if(error>1 || error<0) return "Unknown error"; - else return stl_error_msg[error].c_str(); + if (error>2 || error<0) return "Unknown error"; + else return stl_error_msg[error].c_str(); }; /* diff --git a/wrap/io_trimesh/export_vrml.h b/wrap/io_trimesh/export_vrml.h index b8ee4244..4348ef86 100644 --- a/wrap/io_trimesh/export_vrml.h +++ b/wrap/io_trimesh/export_vrml.h @@ -281,8 +281,10 @@ namespace vcg { " ]\n" "}\n" ); + int result = 0; + if (ferror(fp)) result = 2; fclose(fp); - return 0; + return result; } ///Returns mask of capability one define with what are the saveable information of the format. static int GetExportMaskCapability() @@ -305,11 +307,12 @@ namespace vcg { static std::vector wrl_error_msg; if(wrl_error_msg.empty()) { - wrl_error_msg.resize(2 ); - wrl_error_msg[0]="No errors"; - wrl_error_msg[1]="Can't open file"; + wrl_error_msg.resize(3); + wrl_error_msg[0] = "No errors"; + 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(); } diff --git a/wrap/io_trimesh/io_ply.h b/wrap/io_trimesh/io_ply.h index b376ee86..d0cfc042 100644 --- a/wrap/io_trimesh/io_ply.h +++ b/wrap/io_trimesh/io_ply.h @@ -152,15 +152,15 @@ public: enum Error { // Funzioni superiori - E_NO_VERTEX = ply::E_MAXPLYERRORS+1, // 14 - E_NO_FACE = ply::E_MAXPLYERRORS+2, // 15 - E_SHORTFILE = ply::E_MAXPLYERRORS+3, // 16 - E_NO_3VERTINFACE = ply::E_MAXPLYERRORS+4, // 17 - E_BAD_VERT_INDEX = ply::E_MAXPLYERRORS+5, // 18 - E_NO_6TCOORD = ply::E_MAXPLYERRORS+6, // 19 - E_DIFFER_COLORS = ply::E_MAXPLYERRORS+7, - E_BAD_VERT_INDEX_EDGE = ply::E_MAXPLYERRORS+8, // 18 - E_MAXPLYINFOERRORS= ply::E_MAXPLYERRORS+9// 20 + E_NO_VERTEX = ply::E_MAXPLYERRORS+1, // 15 + E_NO_FACE = ply::E_MAXPLYERRORS+2, // 16 + E_SHORTFILE = ply::E_MAXPLYERRORS+3, // 17 + E_NO_3VERTINFACE = ply::E_MAXPLYERRORS+4, // 18 + E_BAD_VERT_INDEX = ply::E_MAXPLYERRORS+5, // 19 + E_NO_6TCOORD = ply::E_MAXPLYERRORS+6, // 20 + E_DIFFER_COLORS = ply::E_MAXPLYERRORS+7, // 21 + E_BAD_VERT_INDEX_EDGE = ply::E_MAXPLYERRORS+8, // 22 + E_MAXPLYINFOERRORS= ply::E_MAXPLYERRORS+9 // 23 }; }; // end class diff --git a/wrap/ply/plylib.h b/wrap/ply/plylib.h index afdc6443..59e5eddd 100644 --- a/wrap/ply/plylib.h +++ b/wrap/ply/plylib.h @@ -91,6 +91,8 @@ enum PlyError { E_BADTYPE, // 10 E_INCOMPATIBLETYPE, // 11 E_BADCAST, // 12 + //saving error + E_STREAMERROR, // 13 E_MAXPLYERRORS };