diff --git a/.gitignore b/.gitignore index 6b75457c..1019c660 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,9 @@ release/ *.vcxproj *.vcxproj.filters *.suo +*.ply +wrap/nanoply/nanoply_vcg/nanoply_vcg.sln +*.db +wrap/nanoply/nanoply_vcg/nanoply_vcg.VC.VC.opendb +wrap/nanoply/nanoply_vcg/.vs/nanoply_vcg/v15/ipch/AutoPCH/NANOPLY_VCG-1b6b1a83/MAIN-5f62d91f/MAIN.ipch +*.sln diff --git a/apps/metro/metro.cpp b/apps/metro/metro.cpp index 9c682a53..bedc8858 100644 --- a/apps/metro/metro.cpp +++ b/apps/metro/metro.cpp @@ -296,15 +296,14 @@ int main(int argc, char**argv) // save error files. if(flags & SamplingFlags::SAVE_ERROR) { - vcg::tri::io::PlyInfo p; - p.mask|=vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY /* | vcg::ply::PLYMask::PM_VERTQUALITY*/ ; + int saveMask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY /* | vcg::ply::PLYMask::PM_VERTQUALITY*/ ; //p.mask|=vcg::ply::PLYMask::PM_VERTCOLOR|vcg::ply::PLYMask::PM_VERTQUALITY; if(ColorMax!=0 || ColorMin != 0){ vcg::tri::UpdateColor::PerVertexQualityRamp(S1,ColorMin,ColorMax); vcg::tri::UpdateColor::PerVertexQualityRamp(S2,ColorMin,ColorMax); } - tri::io::ExporterPLY::Save( S1,S1NewName.c_str(),true,p); - tri::io::ExporterPLY::Save( S2,S2NewName.c_str(),true,p); + tri::io::ExporterPLY::Save( S1,S1NewName.c_str(),saveMask); + tri::io::ExporterPLY::Save( S2,S2NewName.c_str(),saveMask); } // save error files. diff --git a/apps/sample/sample.pro b/apps/sample/sample.pro index 3b590577..b1c10547 100644 --- a/apps/sample/sample.pro +++ b/apps/sample/sample.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs SUBDIRS = trimesh_allocate \ trimesh_attribute \ + trimesh_attribute_saving \ trimesh_ball_pivoting \ trimesh_base \ trimesh_closest \ @@ -37,6 +38,7 @@ SUBDIRS = trimesh_allocate \ trimesh_smooth \ trimesh_split_vertex \ trimesh_texture \ + trimesh_texture_clean \ trimesh_topology \ trimesh_topological_cut \ trimesh_voronoi \ diff --git a/apps/sample/trimesh_attribute/trimesh_attribute.pro b/apps/sample/trimesh_attribute/trimesh_attribute.pro index 8da4c00d..16654d1e 100644 --- a/apps/sample/trimesh_attribute/trimesh_attribute.pro +++ b/apps/sample/trimesh_attribute/trimesh_attribute.pro @@ -1,3 +1,3 @@ include(../common.pri) TARGET = trimesh_attribute -SOURCES += trimesh_attribute.cpp ../../../wrap/ply/plylib.cpp +SOURCES += trimesh_attribute.cpp diff --git a/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp new file mode 100644 index 00000000..7afe64ee --- /dev/null +++ b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004-2016 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +/*! \file trimesh_attribute.cpp +\ingroup code_sample + +\brief the minimal example of using the attributes + +Attributes are a simple mechanism to associate user-defined 'attributes' to the simplicies and to the mesh. +See the page '\ref attributes' for more details. +*/ + +#include +#include +#include +class MyEdge; +class MyFace; +class MyVertex; +struct MyUsedTypes : public vcg::UsedTypes< vcg::Use::AsVertexType, + vcg::Use ::AsFaceType>{}; + +class MyVertex : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f,vcg::vertex::Normal3f, vcg::vertex::BitFlags>{}; +class MyFace : public vcg::Face< MyUsedTypes, vcg::face::VertexRef, vcg::face::Normal3f, vcg::face::BitFlags> {}; + +class MyMesh : public vcg::tri::TriMesh< std::vector, std::vector > {}; +int main() +{ + MyMesh m; + Torus(m, 3.0f, 1.0f); + //! [Adding a few attributes] + // add a per-vertex attribute with type float named "GaussianCurvature" + MyMesh::PerVertexAttributeHandle + hvf = vcg::tri::Allocator:: GetPerVertexAttribute (m,std::string("GaussianCurvature")); + + MyMesh::PerVertexAttributeHandle + hv3f = vcg::tri::Allocator:: GetPerVertexAttribute (m,std::string("InvertedNormal")); + + // add a per-face attribute with type float named "FaceArea" + MyMesh::PerFaceAttributeHandle + hff = vcg::tri::Allocator:: GetPerFaceAttribute (m,std::string("FaceArea")); + //! [filling the attribute] + vcg::tri::Allocator::ClearPerVertexAttribute(m,hvf, float(M_PI*2)); + vcg::tri::Allocator::ClearPerVertexAttribute(m,hv3f, vcg::Point3f(0,0,0)); + + ForEachFace(m, [&](MyFace &f){ + hff[&f]=vcg::DoubleArea(f)*0.5f; + for(int i=0;i<3;++i){ + hvf[f.V(i)] -= vcg::Angle(f.P1(i)-f.P0(i),f.P2(i)-f.P0(i)); + hv3f[f.V(i)] -= vcg::NormalizedTriangleNormal(f); + } + }); + + //! [Saving 3 attributes in ply, one of the 3 disguised as quality] + vcg::tri::io::PlyInfo pi; + pi.AddPerVertexFloatAttribute("GaussianCurvature","quality"); + pi.AddPerFaceFloatAttribute("FaceArea"); + pi.AddPerVertexPoint3fAttribute(m,"InvertedNormal"); + vcg::tri::io::ExporterPLY::Save(m,"MeshWithCurvature.ply",false,pi); +} diff --git a/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.pro b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.pro new file mode 100644 index 00000000..78228a1e --- /dev/null +++ b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.pro @@ -0,0 +1,3 @@ +include(../common.pri) +TARGET = trimesh_attribute_saving +SOURCES += trimesh_attribute_saving.cpp ../../../wrap/ply/plylib.cpp diff --git a/apps/sample/trimesh_ball_pivoting/trimesh_ball_pivoting.cpp b/apps/sample/trimesh_ball_pivoting/trimesh_ball_pivoting.cpp index 054710fd..644b1063 100644 --- a/apps/sample/trimesh_ball_pivoting/trimesh_ball_pivoting.cpp +++ b/apps/sample/trimesh_ball_pivoting/trimesh_ball_pivoting.cpp @@ -102,8 +102,7 @@ int main(int argc, char **argv) printf("Output mesh vn:%i fn:%i\n",m.VN(),m.FN()); printf("Created in :%i msec (%i+%i)\n",t2-t0,t1-t0,t2-t1); - vcg::tri::io::PlyInfo pi; - vcg::tri::io::ExporterPLY::Save(m,argv[2],pi.mask); + vcg::tri::io::ExporterPLY::Save(m,argv[2]); return 0; } diff --git a/apps/sample/trimesh_refine/trimesh_refine.cpp b/apps/sample/trimesh_refine/trimesh_refine.cpp index 59ab0631..7fae4830 100644 --- a/apps/sample/trimesh_refine/trimesh_refine.cpp +++ b/apps/sample/trimesh_refine/trimesh_refine.cpp @@ -137,8 +137,6 @@ int main(int argc, char **argv) printf("Output mesh vn:%i fn:%i\n",m.VN(),m.FN()); - vcg::tri::io::PlyInfo pi; - pi.mask|=vcg::tri::io::Mask::IOM_BITPOLYGONAL; - vcg::tri::io::Exporter::Save(m,argv[2],pi.mask); + vcg::tri::io::Exporter::Save(m,argv[2],vcg::tri::io::Mask::IOM_BITPOLYGONAL); return 0; } diff --git a/apps/sample/trimesh_texture_clean/trimesh_texture_clean.cpp b/apps/sample/trimesh_texture_clean/trimesh_texture_clean.cpp new file mode 100644 index 00000000..e6e5029e --- /dev/null +++ b/apps/sample/trimesh_texture_clean/trimesh_texture_clean.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004-2016 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +#include + +#include +#include +#include + +/*! \file trimesh_texture_clean.cpp +\ingroup code_sample + +\brief a small example about removing fake texture seams eventually generated by rounding error in a texture param + +*/ + +using namespace vcg; + +class MyEdge; +class MyFace; +class MyVertex; +struct MyUsedTypes : public UsedTypes< Use::AsVertexType, Use::AsFaceType>{}; + +class MyVertex : public Vertex< MyUsedTypes, vertex::Coord3f, vertex::VFAdj, vertex::Normal3f, vertex::BitFlags >{}; +class MyFace : public Face < MyUsedTypes, face::VertexRef, face::VFAdj, face::WedgeTexCoord2f, face::Mark, face::BitFlags > {}; +class MyMesh : public tri::TriMesh< std::vector, std::vector >{}; + + +int main(int ,char ** ) +{ + MyMesh m; + int mask = tri::io::Mask::IOM_WEDGTEXCOORD; + + // generate a simple 2D grid + Grid(m,20,20,1,1); + // assign it a simple planar parametrization + tri:UpdateTexture::WedgeTexFromPlane(m,Point3f(1.0f,0,0),Point3f(0,1.0f,0),true); + tri::io::ExporterOBJ::Save(m,"grid_0.obj",mask); + + // randomly perturb a few coord textures introducing fake seams + for(MyFace &f : m.face) + { + for(int i=0;i<3;++i) + if(rand()%20==0) + { + f.WT(i).U()+=0.0000001; + f.WT(i).V()-=0.0000001; + } + } + tri::io::ExporterOBJ::Save(m,"grid_1.obj",mask); + + // Merge texture coords that very close + tri::UpdateTopology::VertexFace(m); + tri::UpdateTexture::WedgeTexMergeClose(m); + + tri::io::ExporterOBJ::Save(m,"grid_2.obj",mask); + + return 0; +} + diff --git a/apps/sample/trimesh_texture_clean/trimesh_texture_clean.pro b/apps/sample/trimesh_texture_clean/trimesh_texture_clean.pro new file mode 100644 index 00000000..2c0f4f29 --- /dev/null +++ b/apps/sample/trimesh_texture_clean/trimesh_texture_clean.pro @@ -0,0 +1,4 @@ +include(../common.pri) +TARGET = trimesh_texture_clean +SOURCES += trimesh_texture_clean.cpp + diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h index 25493000..71daded7 100644 --- a/vcg/complex/algorithms/clean.h +++ b/vcg/complex/algorithms/clean.h @@ -24,6 +24,8 @@ #ifndef __VCGLIB_CLEAN #define __VCGLIB_CLEAN +#include + // VCG headers #include #include @@ -310,7 +312,7 @@ public: } - /** This function removes that are not referenced by any face or by any edge. + /** This function removes vertices that are not referenced by any face or by any edge. @param m The mesh @param DeleteVertexFlag if false prevent the vertex deletion and just count it. @return The number of removed vertices @@ -583,7 +585,7 @@ public: firstVp++; } - return ToSplitVec.size(); + return int(ToSplitVec.size()); } @@ -1369,7 +1371,7 @@ public: count = 0; ScalarType NormalThrRad = math::ToRad(normalThresholdDeg); - ScalarType eps = 0.0001; // this epsilon value is in absolute value. It is a distance from edge in baricentric coords. + ScalarType eps = ScalarType(0.0001); // this epsilon value is in absolute value. It is a distance from edge in baricentric coords. //detection stage for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV()) { Point3 NN = vcg::TriangleNormal((*fi)).Normalize(); @@ -1790,6 +1792,7 @@ public: */ static void SelectFoldedFaceFromOneRingFaces(MeshType &m, ScalarType cosThreshold) { + typedef std::unordered_set VertexSet; tri::RequireVFAdjacency(m); tri::RequirePerFaceNormal(m); tri::RequirePerVertexNormal(m); @@ -1803,33 +1806,33 @@ public: #pragma omp parallel for schedule(dynamic, 10) for (int i = 0; i < m.face.size(); i++) { - std::vector nearVertex; - std::vector point; - typename MeshType::FacePointer f = &m.face[i]; + VertexSet nearVertex; + std::vector pointVec; + FacePointer f = &m.face[i]; for (int j = 0; j < 3; j++) { - std::vector temp; - vcg::face::VVStarVF(f->V(j), temp); - typename std::vector::iterator iter = temp.begin(); + std::vector temp; + vcg::face::VVStarVF(f->V(j), temp); + typename std::vector::iterator iter = temp.begin(); for (; iter != temp.end(); iter++) { if ((*iter) != f->V1(j) && (*iter) != f->V2(j)) { - nearVertex.push_back((*iter)); - point.push_back((*iter)->P()); + if (nearVertex.insert((*iter)).second) + pointVec.push_back((*iter)->P()); } } - nearVertex.push_back(f->V(j)); - point.push_back(f->P(j)); + nearVertex.insert(f->V(j)); + pointVec.push_back(f->P(j)); } - if (point.size() > 3) + if (pointVec.size() > 3) { - vcg::Plane3 plane; - vcg::FitPlaneToPointSet(point, plane); + vcg::Plane3 plane; + vcg::FitPlaneToPointSet(pointVec, plane); float avgDot = 0; - for (int j = 0; j < nearVertex.size(); j++) - avgDot += plane.Direction().dot(nearVertex[j]->N()); + for (auto nvp : nearVertex) + avgDot += plane.Direction().dot(nvp->N()); avgDot /= nearVertex.size(); typename MeshType::VertexType::NormalType normal; if (avgDot < 0) diff --git a/vcg/complex/algorithms/convex_hull.h b/vcg/complex/algorithms/convex_hull.h index ebe660da..1739ff9b 100644 --- a/vcg/complex/algorithms/convex_hull.h +++ b/vcg/complex/algorithms/convex_hull.h @@ -398,7 +398,7 @@ public: { visible.vert[i].P() = m.vert[ind].P(); m.vert[ind].SetS(); - m.vert[ind].C() = Color4b::LightBlue; + //m.vert[ind].C() = Color4b::LightBlue; selCnt++; } } @@ -416,6 +416,8 @@ public: tri::Allocator::CompactEveryVector(visible); tri::Clean::FlipMesh(visible); + tri::UpdateNormal::PerFaceNormalized(visible); + tri::UpdateNormal::PerVertexNormalized(visible); } }; diff --git a/vcg/complex/algorithms/create/advancing_front.h b/vcg/complex/algorithms/create/advancing_front.h index a6de09ab..a3955f32 100644 --- a/vcg/complex/algorithms/create/advancing_front.h +++ b/vcg/complex/algorithms/create/advancing_front.h @@ -99,7 +99,7 @@ template class AdvancingFront { void BuildMesh(CallBackPos call = NULL, int interval = 512) { float finalfacesext = mesh.vert.size() * 2.0f; - if(call) call(0, "Advancing front"); + if (call) (*call)(0, "Advancing front"); while(1) { for(int i = 0; i < interval; i++) { diff --git a/vcg/complex/algorithms/create/ball_pivoting.h b/vcg/complex/algorithms/create/ball_pivoting.h index be8c3552..be1c6413 100644 --- a/vcg/complex/algorithms/create/ball_pivoting.h +++ b/vcg/complex/algorithms/create/ball_pivoting.h @@ -120,7 +120,7 @@ template class BallPivoting: public AdvancingFront { targets.push_back(vp); } - int n = targets.size(); + int n = int(targets.size()); if(n<3) continue; bool success = true; @@ -205,10 +205,10 @@ template class BallPivoting: public AdvancingFront { Mark(vv1); Mark(vv2); - v0 = tri::Index(this->mesh,vv0); - v1 = tri::Index(this->mesh,vv1); - v2 = tri::Index(this->mesh,vv2); - return true; + v0 = int(tri::Index(this->mesh, vv0)); + v1 = int(tri::Index(this->mesh, vv1)); + v2 = int(tri::Index(this->mesh, vv2)); + return true; } return false; } @@ -252,7 +252,7 @@ template class BallPivoting: public AdvancingFront { if(nn==0) return -1; VertexType *candidate = NULL; - ScalarType min_angle = M_PI; + ScalarType min_angle = ScalarType(M_PI); // // Loop over all the nearest vertexes and choose the best one according the ball pivoting strategy. // @@ -312,7 +312,7 @@ template class BallPivoting: public AdvancingFront { assert((candidate->P() - v1).Norm() > min_edge); } - int candidateIndex = tri::Index(this->mesh,candidate); + int candidateIndex = int(tri::Index(this->mesh,candidate)); assert(candidateIndex != edge.v0 && candidateIndex != edge.v1); Point3x newnormal = ((candidate->P() - v0)^(v1 - v0)).Normalize(); diff --git a/vcg/complex/algorithms/create/plymc/plymc.h b/vcg/complex/algorithms/create/plymc/plymc.h index 2f3315d3..ae268ef5 100644 --- a/vcg/complex/algorithms/create/plymc/plymc.h +++ b/vcg/complex/algorithms/create/plymc/plymc.h @@ -59,7 +59,7 @@ namespace tri { // Simple prototype for later use... template -void MCSimplify( MeshType &m, float perc, bool preserveBB=true, vcg::CallBackPos *cb=0); +int MCSimplify( MeshType &m, float perc, bool preserveBB=true, vcg::CallBackPos *cb=0); /** Surface Reconstruction @@ -550,63 +550,66 @@ template < class MeshType, class VertexPair> template< class MeshType> -void MCSimplify( MeshType &m, float absoluteError, bool preserveBB, vcg::CallBackPos *cb) +int MCSimplify( MeshType &m, float absoluteError, bool preserveBB, vcg::CallBackPos *cb) { - typedef PlyMCTriEdgeCollapse > MyColl; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::CoordType CoordType; + typedef PlyMCTriEdgeCollapse > MyColl; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::CoordType CoordType; - tri::UpdateBounding::Box(m); - tri::UpdateTopology::VertexFace(m); - TriEdgeCollapseMCParameter pp; - pp.bb.Import(m.bbox); - pp.preserveBBox=preserveBB; - vcg::LocalOptimization DeciSession(m,&pp); - if(absoluteError==0) - { + tri::UpdateBounding::Box(m); + tri::UpdateTopology::VertexFace(m); + TriEdgeCollapseMCParameter pp; + pp.bb.Import(m.bbox); + pp.preserveBBox=preserveBB; + vcg::LocalOptimization DeciSession(m,&pp); + if(absoluteError==0) + { // guess the mc side. // In a MC mesh the vertices are on the egdes of the cells. and the edges are (mostly) on face of the cells. // If you have 2 vert over the same face xy they share z - std::vector ZSet; - for(FaceIterator fi = m.face.begin();fi!=m.face.end();++fi) - if(!(*fi).IsD()) - { - CoordType v0=(*fi).V(0)->P(); - CoordType v1=(*fi).V(1)->P(); - CoordType v2=(*fi).V(2)->P(); - if(v0[2]==v1[2] && v0[1]!=v1[1] && v0[0]!=v1[0]) ZSet.push_back(v0[2]); - if(v0[2]==v2[2] && v0[1]!=v1[1] && v2[0]!=v2[0]) ZSet.push_back(v0[2]); - if(v1[2]==v2[2] && v1[1]!=v1[1] && v2[0]!=v2[0]) ZSet.push_back(v0[2]); - if(ZSet.size()>100) break; - } - std::sort(ZSet.begin(),ZSet.end()); - std::vector::iterator lastV = std::unique(ZSet.begin(),ZSet.end()); - ZSet.resize(lastV-ZSet.begin()); - float Delta=0; - for(size_t i = 0; i< ZSet.size()-1;++i) - { - Delta = std::max(ZSet[i+1]-ZSet[i],Delta); -// qDebug("%f",Delta); - } - absoluteError= Delta/4.0f; - } -// qDebug("Simplifying at absoluteError=%f",absoluteError); + std::vector ZSet; + for(FaceIterator fi = m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + { + CoordType v0=(*fi).V(0)->P(); + CoordType v1=(*fi).V(1)->P(); + CoordType v2=(*fi).V(2)->P(); + if(v0[2]==v1[2] && v0[1]!=v1[1] && v0[0]!=v1[0]) ZSet.push_back(v0[2]); + if(v0[2]==v2[2] && v0[1]!=v2[1] && v0[0]!=v2[0]) ZSet.push_back(v0[2]); + if(v1[2]==v2[2] && v1[1]!=v2[1] && v1[0]!=v2[0]) ZSet.push_back(v1[2]); + if(ZSet.size()>100) break; + } + if (ZSet.size() == 0) return -1; //no straight edges found. exit with error + std::sort(ZSet.begin(),ZSet.end()); + std::vector::iterator lastV = std::unique(ZSet.begin(),ZSet.end()); + ZSet.resize(lastV-ZSet.begin()); + float Delta=0; + for(size_t i = 0; i< ZSet.size()-1;++i) + { + Delta = std::max(ZSet[i+1]-ZSet[i],Delta); + //qDebug("%f",Delta); + } + absoluteError= Delta/4.0f; + } + //qDebug("Simplifying at absoluteError=%f",absoluteError); - float TargetError = absoluteError; - char buf[1024]; - DeciSession.template Init< MyColl > (); + float TargetError = absoluteError; + char buf[1024]; + DeciSession.template Init< MyColl > (); - pp.areaThr=TargetError*TargetError; - DeciSession.SetTimeBudget(1.0f); - if(TargetError < std::numeric_limits::max() ) DeciSession.SetTargetMetric(TargetError); - while(DeciSession.DoOptimization() && DeciSession.currMetric < TargetError) - { - sprintf(buf,"Simplyfing %7i err %9g \r",m.fn,DeciSession.currMetric); - if (cb) cb(int(100.0f*DeciSession.currMetric/TargetError),buf); - } + pp.areaThr=TargetError*TargetError; + DeciSession.SetTimeBudget(1.0f); + if(TargetError < std::numeric_limits::max() ) DeciSession.SetTargetMetric(TargetError); + while(DeciSession.DoOptimization() && DeciSession.currMetric < TargetError) + { + sprintf(buf,"Simplyfing %7i err %9g \r",m.fn,DeciSession.currMetric); + if (cb) cb(int(100.0f*DeciSession.currMetric/TargetError),buf); + } + + return 1; //success } diff --git a/vcg/complex/algorithms/create/resampler.h b/vcg/complex/algorithms/create/resampler.h index 9d6b6f3a..edf9eae5 100644 --- a/vcg/complex/algorithms/create/resampler.h +++ b/vcg/complex/algorithms/create/resampler.h @@ -27,8 +27,9 @@ #include #include #include -#include -#include +//#include +//#include +#include namespace vcg { namespace tri { @@ -63,13 +64,15 @@ class Resampler : public BasicGrid { private: typedef int VertexIndex; - typedef typename vcg::GridStaticPtr GridType; + //typedef typename vcg::GridStaticPtr GridType; + typedef vcg::KdTreeFace GridType; protected: int SliceSize; int CurrentSlice; - typedef tri::FaceTmark MarkerFace; + //typedef tri::FaceTmark MarkerFace; + typedef vcg::tri::EmptyTMark MarkerFace; MarkerFace markerFunctor; VertexIndex *_x_cs; // indici dell'intersezioni della superficie lungo gli Xedge della fetta corrente @@ -159,6 +162,7 @@ class Resampler : public BasicGrid OldCoordType closestPt; DISTFUNCTOR PDistFunct; OldFaceType *f = _g.GetClosest(PDistFunct,markerFunctor,testPt,max_dist,dist,closestPt); + if (f==NULL) return field_value(false,0); if(AbsDistFlag) return field_value(true,dist); assert(!f->IsD()); @@ -230,6 +234,7 @@ class Resampler : public BasicGrid /// the distance of the bb void ComputeSliceValues(int slice,field_value *slice_values) { +#pragma omp parallel for schedule(dynamic, 10) for (int i=0; i<=this->siz.X(); i++) { for (int k=0; k<=this->siz.Z(); k++) diff --git a/vcg/complex/algorithms/hole.h b/vcg/complex/algorithms/hole.h index ed687fb7..064d1807 100644 --- a/vcg/complex/algorithms/hole.h +++ b/vcg/complex/algorithms/hole.h @@ -283,7 +283,7 @@ public: template class MinimumWeightEar : public TrivialEar { public: - static float &DiedralWeight() { static float _dw=0.1; return _dw;} + static float &DiedralWeight() { static float _dw=0.1f; return _dw;} typedef TrivialEar TE; typename MESH::ScalarType dihedralRad; typename MESH::ScalarType aspectRatio; diff --git a/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h b/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h index e1edbfba..072de7da 100644 --- a/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h +++ b/vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h @@ -179,7 +179,7 @@ public: this->optimalPos = newPos; } - void Execute(TriMeshType &m, BaseParameterClass */*_pp*/) + void Execute(TriMeshType &m, BaseParameterClass * /*_pp*/) { CoordType newPos = this->optimalPos; QH::Qd(this->pos.V(1))+=QH::Qd(this->pos.V(0)); // v0 is deleted and v1 take the new position diff --git a/vcg/complex/algorithms/mesh_to_matrix.h b/vcg/complex/algorithms/mesh_to_matrix.h index d1240216..06ff42f6 100644 --- a/vcg/complex/algorithms/mesh_to_matrix.h +++ b/vcg/complex/algorithms/mesh_to_matrix.h @@ -241,7 +241,7 @@ public: { tri::RequireCompactness(m); h.resize(m.vn); - for(int i=0;i - namespace vcg { @@ -94,7 +93,7 @@ class OutlierRemoval dem += 0.230389 * value * value; dem += 0.000972 * value * value * value; dem += 0.078108 * value * value * value * value; - ScalarType op = max(0.0, 1.0 - 1.0 / dem); + ScalarType op = std::max(0.0, 1.0 - 1.0 / dem); outlierScore[i] = op; } diff --git a/vcg/complex/algorithms/stat.h b/vcg/complex/algorithms/stat.h index 5c45ddb4..ca1f3de5 100644 --- a/vcg/complex/algorithms/stat.h +++ b/vcg/complex/algorithms/stat.h @@ -162,7 +162,7 @@ public: for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) if (!(*vi).IsD()) { - ScalarType weight = useQualityAsWeight ? (*vi).Q() : 1.0; + ScalarType weight = useQualityAsWeight ? (*vi).Q() : 1.0f; accumulator[0] += (double)((*vi).P()[0] * weight); accumulator[1] += (double)((*vi).P()[1] * weight); accumulator[2] += (double)((*vi).P()[2] * weight); @@ -212,6 +212,21 @@ public: return area/ScalarType(2.0); } + static ScalarType ComputeBorderLength(MeshType & m) + { + RequireFFAdjacency(m); + ScalarType sum = 0; + tri::UpdateTopology::FaceFace(m); + ForEachFace(m, [&](FaceType &f) { + for (int k=0; k &h, bool selectionOnly = false) // V1.0 { tri::RequirePerVertexQuality(m); diff --git a/vcg/complex/algorithms/update/color.h b/vcg/complex/algorithms/update/color.h index 8a24b5aa..dc5fbe81 100644 --- a/vcg/complex/algorithms/update/color.h +++ b/vcg/complex/algorithms/update/color.h @@ -790,6 +790,7 @@ static Color4b ColorDesaturate(Color4b c, int method) } default: assert(0); } + return Color4b(255, 255, 255, 255); } //ausiliary function to compute average lightness. value = (R+G+B)/3 diff --git a/vcg/complex/algorithms/update/texture.h b/vcg/complex/algorithms/update/texture.h index c2ff6f92..d67bb999 100644 --- a/vcg/complex/algorithms/update/texture.h +++ b/vcg/complex/algorithms/update/texture.h @@ -48,6 +48,7 @@ typedef typename MeshType::VertexIterator VertexIterator; typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FaceIterator FaceIterator; +typedef typename vcg::Point2 UVCoordType; static void WedgeTexFromPlane(ComputeMeshType &m, const Point3 &uVec, const Point3 &vVec, bool aspectRatio, ScalarType sideGutter=0.0) { @@ -70,7 +71,7 @@ static void WedgeTexFromPlane(ComputeMeshType &m, const Point3 &uVec if (sideGutter>0.0) { - ScalarType deltaGutter = std::min(wideU, wideV) * min(sideGutter, (ScalarType)0.5); + ScalarType deltaGutter = std::min(wideU, wideV) * std::min(sideGutter, (ScalarType)0.5); bb.max[0] += deltaGutter; bb.min[0] -= deltaGutter; @@ -138,6 +139,40 @@ static void WedgeTexRemoveNull(ComputeMeshType &m, const std::string &texturenam } } +/** \brief Merge supposedly wrong texcoords + * It can happens that for rounding errors texcoords on different wedges but on the same vertex have different tex coords. + * This function merges them according a threshold. It requires initialized VF adjacency. + * the default for merging is if two textures dist less than one 16th of texel on a 4k texture... +*/ + +static int WedgeTexMergeClose(ComputeMeshType &m, ScalarType mergeThr = ScalarType(1.0/65536.0) ) +{ + tri::RequireVFAdjacency(m); + int mergedCnt=0; + ForEachVertex(m, [&](VertexType &v){ + face::VFIterator vfi(&v); + std::vector clusterVec; + clusterVec.push_back(vfi.F()->WT(vfi.I()).P()); + ++vfi; + while(!vfi.End()) + { + UVCoordType cur= vfi.F()->WT(vfi.I()).P(); + bool merged=false; + for(auto p:clusterVec) { + if(p!=cur && Distance(p,cur) < mergeThr){ + vfi.F()->WT(vfi.I()).P()=p; + ++mergedCnt; + merged=true; + } + } + if(!merged) + clusterVec.push_back(cur); + + ++vfi; + } + }); + return mergedCnt; +} }; // end class diff --git a/vcg/complex/algorithms/voronoi_remesher.h b/vcg/complex/algorithms/voronoi_remesher.h index 54541533..f2521b26 100644 --- a/vcg/complex/algorithms/voronoi_remesher.h +++ b/vcg/complex/algorithms/voronoi_remesher.h @@ -133,7 +133,7 @@ protected: } public: - static const int VoroRelaxationStep = 20; + static const int VoroRelaxationStep = 30; /// /// \brief Remesh the main function that remeshes a mesh preserving creases. @@ -355,7 +355,7 @@ protected: // refine to obtain a base mesh VoronoiProcessingParameter vpp; - vpp.refinementRatio = 4.0f; + vpp.refinementRatio = 5.0f; Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp); // Poisson sampling preserving border @@ -372,7 +372,15 @@ protected: // Montecarlo oversampling Mesh montecarloMesh; - int poissonCount = SurfaceSampler::ComputePoissonSampleNum(original, samplingRadius) * 0.7; +// const int poissonCount = SurfaceSampler::ComputePoissonSampleNum(original, samplingRadius)/* * 0.7*/; + int poissonCount = 0; + { + const ScalarType meshArea = Stat::ComputeMeshArea(original); + const ScalarType meshBoundary = Stat::ComputeBorderLength(original); + const double factor = math::Sqrt(3)/2; + const ScalarType areaPerSample = samplingRadius*samplingRadius * factor; + poissonCount = meshArea / areaPerSample - meshBoundary * samplingRadius * factor * 0.5; // totalArea / (r^2 * sqrt(3)/2) - (totalBoundary * r * sqrt(3)/4) + } // std::cout << "poisson Count: " << poissonCount << std::endl; if (poissonCount <= 0) @@ -386,7 +394,7 @@ protected: else { // Montecarlo poisson sampling - SurfaceSampler::MontecarloPoisson(original, mps, poissonCount * 20); + SurfaceSampler::MontecarloPoisson(original, mps, poissonCount * 40); BuildMeshFromCoordVector(montecarloMesh,sampleVec); #ifdef DEBUG_VORO @@ -421,6 +429,7 @@ protected: vpp.seedPerturbationProbability = 0.0f; Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep, vpp); + #ifdef DEBUG_VORO BuildMeshFromCoordVector(poissonMesh,seedPointVec); io::ExporterPLY::Save(poissonMesh, QString("relaxedMesh_%1.ply").arg(idx).toStdString().c_str()); diff --git a/vcg/complex/allocate.h b/vcg/complex/allocate.h index a04754c3..ea5255db 100644 --- a/vcg/complex/allocate.h +++ b/vcg/complex/allocate.h @@ -1157,12 +1157,12 @@ public: template static void - ClearPerVertexAttribute( MeshType & m,typename MeshType::template PerVertexAttributeHandle & h){ + ClearPerVertexAttribute( MeshType & m,typename MeshType::template PerVertexAttributeHandle & h, const ATTR_TYPE & initVal = ATTR_TYPE()){ typename std::set ::iterator i; for( i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) if( (*i)._handle == h._handle ){ for(typename MeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - h[vi] = ATTR_TYPE(); + h[vi] = initVal; return;} assert(0); } diff --git a/vcg/math/gen_normal.h b/vcg/math/gen_normal.h index ad5e71aa..3e9968c4 100644 --- a/vcg/math/gen_normal.h +++ b/vcg/math/gen_normal.h @@ -92,7 +92,7 @@ static void UniformCone(int vn, std::vector > &NN, ScalarTyp printf("----------AngleRad %f Angledeg %f ratio %f vn %i vn2 %i \n",AngleRad,math::ToDeg(AngleRad),Ratio,vn,int(vn/Ratio)); Fibonacci(vn/Ratio,NNT); - printf("asked %i got %i (expecting %i instead of %i)\n", int(vn/Ratio), NNT.size(), int(NNT.size()*Ratio), vn); + printf("asked %i got %i (expecting %i instead of %i)\n", int(vn/Ratio), int(NNT.size()), int(NNT.size()*Ratio), vn); typename std::vector >::iterator vi; ScalarType cosAngle = cos(AngleRad); diff --git a/vcg/space/index/kdtree/kdtree_face.h b/vcg/space/index/kdtree/kdtree_face.h index 3fc373ee..3936789e 100644 --- a/vcg/space/index/kdtree/kdtree_face.h +++ b/vcg/space/index/kdtree/kdtree_face.h @@ -57,18 +57,23 @@ namespace vcg { public: - KdTreeFace(MeshType& mesh, unsigned int maxObjPerCell = 64, unsigned int maxDepth = 64) : epsilon(std::numeric_limits::epsilon()) + KdTreeFace():epsilon(std::numeric_limits::epsilon()) + { + targetCellSize = 64; + targetMaxDepth = 64; + }; + + KdTreeFace(unsigned int maxObjPerCell, unsigned int maxDepth) : epsilon(std::numeric_limits::epsilon()) { targetCellSize = maxObjPerCell; targetMaxDepth = maxDepth; - mNodes.resize(1); - Node& node = mNodes.back(); - node.leaf = 0; - node.aabb = mesh.bbox; - node.aabb.Offset(VectorType(epsilon, epsilon, epsilon)); - for (int i = 0; i < mesh.face.size(); i++) - node.list.push_back(&mesh.face[i]); - numLevel = createTree(0, 1); + }; + + KdTreeFace(MeshType& mesh, unsigned int maxObjPerCell = 64, unsigned int maxDepth = 64, bool onlySelection = false) : epsilon(std::numeric_limits::epsilon()) + { + targetCellSize = maxObjPerCell; + targetMaxDepth = maxDepth; + Set(mesh.face.begin(), mesh.face.end(), mesh.face.size(), onlySelection); }; ~KdTreeFace() @@ -76,10 +81,53 @@ namespace vcg { }; - - template FacePointer doQueryClosest(const VectorType& queryPoint, VectorType& narestPoint, Scalar& dist, ObjectMarker& marker, Scalar maxDist = std::numeric_limits::max()) + template + void Set(const ObjIter & _oBegin, const ObjIter & _oEnd, int size = 0, bool onlySelection = false) { - if (maxDist < std::numeric_limits::max() && !mNodes[0].aabb.IsIn(queryPoint) && vcg::PointFilledBoxDistance(queryPoint, mNodes[0].aabb) >= maxDist) + mNodes.resize(1); + Node& node = mNodes.back(); + node.leaf = 0; + node.aabb.Offset(VectorType(epsilon, epsilon, epsilon)); + Box3 box; + if (onlySelection) + { + for (ObjIter i = _oBegin; i != _oEnd; ++i) + { + if ((*i).IsS()) + { + node.list.push_back(&(*i)); + box.Add((*i).P(0)); + box.Add((*i).P(1)); + box.Add((*i).P(2)); + } + } + } + else + { + for (ObjIter i = _oBegin; i != _oEnd; ++i) + { + node.list.push_back(&(*i)); + box.Add((*i).P(0)); + box.Add((*i).P(1)); + box.Add((*i).P(2)); + } + } + node.aabb = box; + numLevel = CreateTree(0, 1); + }; + + void Clear() + { + for (int i = 0; i < mNodes.size(); i++) + mNodes[i].list.clear(); + mNodes.clear(); + }; + + //template FacePointer GetClosest(const VectorType& queryPoint, VectorType& narestPoint, Scalar& dist, ObjectMarker& marker, Scalar maxDist = std::numeric_limits::max()) + template + FacePointer GetClosest(ObjPointDistFunction& pDistFunc, ObjectMarker& marker, const VectorType& queryPoint, Scalar maxDist, Scalar& dist, VectorType& narestPoint) + { + if (mNodes.size() == 0|| (maxDist < std::numeric_limits::max() && !mNodes[0].aabb.IsIn(queryPoint) && vcg::PointFilledBoxDistance(queryPoint, mNodes[0].aabb) >= maxDist)) { dist = maxDist; return NULL; @@ -109,7 +157,7 @@ namespace vcg { marker.Mark(node.list[i]); Scalar tempDist = minDist; VectorType tempP; - if (vcg::face::PointDistanceBase(*node.list[i], queryPoint, tempDist, tempP)) + if (pDistFunc(*node.list[i], queryPoint, tempDist, tempP)) { if (tempDist < minDist) { @@ -176,7 +224,7 @@ namespace vcg { }; - int createTree(unsigned int nodeId, unsigned int level) + int CreateTree(unsigned int nodeId, unsigned int level) { Node& node = mNodes[nodeId]; VectorType diag = node.aabb.max - node.aabb.min; @@ -264,7 +312,7 @@ namespace vcg { else { leftChild.leaf = 0; - leftLevel = createTree(firstChildId, level + 1); + leftLevel = CreateTree(firstChildId, level + 1); } } @@ -278,7 +326,7 @@ namespace vcg { else { rightChild.leaf = 0; - rightLevel = createTree(firstChildId + 1, level + 1); + rightLevel = CreateTree(firstChildId + 1, level + 1); } } if (leftLevel > rightLevel) diff --git a/vcg/space/index/spatial_hashing.h b/vcg/space/index/spatial_hashing.h index 24f64a96..449017c0 100644 --- a/vcg/space/index/spatial_hashing.h +++ b/vcg/space/index/spatial_hashing.h @@ -206,7 +206,7 @@ protected: inSphVec.push_back(hi); } } - return inSphVec.size(); + return int(inSphVec.size()); } size_t RemoveInSphere(const Point3 &p, const ScalarType radius) diff --git a/vcg/space/point_matching.h b/vcg/space/point_matching.h index 05c599b6..7df6a116 100644 --- a/vcg/space/point_matching.h +++ b/vcg/space/point_matching.h @@ -50,26 +50,26 @@ void ComputeCrossCovarianceMatrix(const std::vector > &spVec, Point3 > &tpVec, Point3 &tpBarycenter, Eigen::Matrix3d &m) { - assert(spVec.size()==tpVec.size()); - m.setZero(); - spBarycenter.SetZero(); - tpBarycenter.SetZero(); - Eigen::Vector3d spe; - Eigen::Vector3d tpe; - typename std::vector >::const_iterator si,ti; - for(si=spVec.begin(),ti=tpVec.begin();si!=spVec.end();++si,++ti){ - spBarycenter+=*si; - tpBarycenter+=*ti; - si->ToEigenVector(spe); - ti->ToEigenVector(tpe); - m+=spe*tpe.transpose(); - } - spBarycenter/=spVec.size(); - tpBarycenter/=tpVec.size(); - spBarycenter.ToEigenVector(spe); - tpBarycenter.ToEigenVector(tpe); - m/=spVec.size(); - m-=spe*tpe.transpose(); + assert(spVec.size() == tpVec.size()); + m.setZero(); + spBarycenter.SetZero(); + tpBarycenter.SetZero(); + Eigen::Vector3d spe; + Eigen::Vector3d tpe; + typename std::vector >::const_iterator si, ti; + for (si = spVec.begin(), ti = tpVec.begin(); si != spVec.end(); ++si, ++ti){ + spBarycenter += *si; + tpBarycenter += *ti; + si->ToEigenVector(spe); + ti->ToEigenVector(tpe); + m += spe*tpe.transpose(); + } + spBarycenter /= double(spVec.size()); + tpBarycenter /= double(tpVec.size()); + spBarycenter.ToEigenVector(spe); + tpBarycenter.ToEigenVector(tpe); + m /= double(spVec.size()); + m -= spe*tpe.transpose(); } /*! \brief Compute the roto-translation that applied to PMov bring them onto Pfix diff --git a/wrap/dae/colladaformat.h b/wrap/dae/colladaformat.h index 72f137d3..29b6dfe7 100644 --- a/wrap/dae/colladaformat.h +++ b/wrap/dae/colladaformat.h @@ -760,7 +760,7 @@ namespace Tags class BindVertexInputTag : public XMLTag { public: - BindVertexInputTag(const QString& semantic,const QString& input_semantic,const QString& input_set) + BindVertexInputTag(const QString& semantic,const QString& input_semantic,const QString& /*input_set*/) :XMLTag("bind_vertex_input") { _attributes.push_back(TagAttribute("semantic",semantic)); diff --git a/wrap/gl/gl_mesh_attributes_multi_viewer_bo_manager.h b/wrap/gl/gl_mesh_attributes_multi_viewer_bo_manager.h index 840a7af7..ccd15b0c 100644 --- a/wrap/gl/gl_mesh_attributes_multi_viewer_bo_manager.h +++ b/wrap/gl/gl_mesh_attributes_multi_viewer_bo_manager.h @@ -97,7 +97,7 @@ namespace vcg _perwire_noshading = true; _persolid_noshading = false; - _perpoint_pointsize = 1.0f; + _perpoint_pointsize = 3.0f; _perpoint_pointsmooth_enabled = false; _perpoint_pointattenuation_enabled = true; _perwire_wirewidth = 1.0f; @@ -296,7 +296,7 @@ namespace vcg if (_glopts != NULL) { std::string tmp; - int size = _glopts->serialize(tmp); + size_t size = _glopts->serialize(tmp); token[i] = str.substr(pos, size); if (token[i].length() < size) return false; @@ -1509,7 +1509,7 @@ namespace vcg { //qDebug("Indexed drawing"); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_bohandle); - glDrawElements(GL_TRIANGLES, _mesh.FN() * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components, GL_UNSIGNED_INT, NULL); + glDrawElements(GL_TRIANGLES, GLsizei(_mesh.FN() * _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_components), GL_UNSIGNED_INT, NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } @@ -1819,7 +1819,7 @@ namespace vcg //qDebug("Indexed drawing"); updateClientState(req); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_EDGEINDICES]->_bohandle); - glDrawElements(GL_LINES, _edge.size() * _bo[INT_ATT_NAMES::ATT_EDGEINDICES]->_components, GL_UNSIGNED_INT, NULL); + glDrawElements(GL_LINES, GLsizei(_edge.size() * _bo[INT_ATT_NAMES::ATT_EDGEINDICES]->_components), GL_UNSIGNED_INT, NULL); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); InternalRendAtts tmp; updateClientState(tmp); @@ -2235,8 +2235,8 @@ namespace vcg assert(nz >= 0); assert(nz < 2); - _v[0] = size_t(vcg::tri::Index(m, pe->V(nz)));; - _v[1] = size_t(vcg::tri::Index(m, pe->V((nz + 1) % 2))); + _v[0] = GLuint(vcg::tri::Index(m, pe->V(nz)));; + _v[1] = GLuint(vcg::tri::Index(m, pe->V((nz + 1) % 2))); assert(_v[0] != _v[1]); // The face pointed by 'f' is Degenerate (two coincident vertexes) if (_v[0] > _v[1]) diff --git a/wrap/gl/pick.h b/wrap/gl/pick.h index 8fcae841..1bff385f 100644 --- a/wrap/gl/pick.h +++ b/wrap/gl/pick.h @@ -226,7 +226,7 @@ public: //err = glGetError(); std::vector result; PickFace(x,y,m,result,width,height); - ScalarType LocalEpsilon(0.001); + ScalarType LocalEpsilon(ScalarType(0.001)); for(size_t i =0;i::digits(); const int DGTVR = vcg::tri::io::Precision::digits(); const int DGTFQ = vcg::tri::io::Precision::digits(); - bool multit = false; + bool saveTexIndexFlag = false; if(binary) h=hbin; else h=hasc; @@ -127,10 +126,10 @@ namespace vcg { { const char * TFILE = "TextureFile"; - for(i=0; i < static_cast(m.textures.size()); ++i) + for(size_t i=0; i < m.textures.size(); ++i) fprintf(fpout,"comment %s %s\n", TFILE, (const char *)(m.textures[i].c_str()) ); - if(m.textures.size()>1 && (HasPerWedgeTexCoord(m) || HasPerVertexTexCoord(m))) multit = true; + if(m.textures.size()>1 && (HasPerWedgeTexCoord(m) || HasPerVertexTexCoord(m))) saveTexIndexFlag = true; } if((pi.mask & Mask::IOM_CAMERA)) @@ -211,8 +210,8 @@ namespace vcg { "property float texture_v\n" ); } - for(i=0;i0 && (pi.mask & Mask::IOM_EDGEINDEX) ) fprintf(fpout, @@ -344,7 +351,59 @@ namespace vcg { VertexPointer vp; VertexIterator vi; SimpleTempData indices(m.vert); - + + std::vector > thfv(pi.VertDescriptorVec.size()); + std::vector > thdv(pi.VertDescriptorVec.size()); + std::vector > thiv(pi.VertDescriptorVec.size()); + std::vector > thsv(pi.VertDescriptorVec.size()); + std::vector > thcv(pi.VertDescriptorVec.size()); + std::vector > thuv(pi.VertDescriptorVec.size()); + + for(size_t i=0;i::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_DOUBLE : thdv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_INT : thiv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_SHORT : thsv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_CHAR : thcv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_UCHAR : thuv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + default : assert(0); + } + } + } + std::vector > thff(pi.FaceDescriptorVec.size()); + std::vector > thdf(pi.FaceDescriptorVec.size()); + std::vector > thif(pi.FaceDescriptorVec.size()); + std::vector > thsf(pi.FaceDescriptorVec.size()); + std::vector > thcf(pi.FaceDescriptorVec.size()); + std::vector > thuf(pi.FaceDescriptorVec.size()); + + for(size_t i=0;i::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_DOUBLE : thdf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_INT : thif[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_SHORT : thsf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_CHAR : thcf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_UCHAR : thuf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + default : assert(0); + } + } + } + + + + for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi){ vp=&(*vi); indices[vi] = j; @@ -381,22 +440,39 @@ namespace vcg { if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) ) { - t = float(vp->T().u()); fwrite(&t,sizeof(float),1,fpout); - t = float(vp->T().v()); fwrite(&t,sizeof(float),1,fpout); + t = ScalarType(vp->T().u()); fwrite(&t,sizeof(ScalarType),1,fpout); + t = ScalarType(vp->T().v()); fwrite(&t,sizeof(ScalarType),1,fpout); } - for(i=0;iT().u(),vp->T().v()); - for(i=0;icV(0)]; vv[1]=indices[fp->cV(1)]; vv[2]=indices[fp->cV(2)]; - fwrite(&c,1,1,fpout); + fwrite(&b3char,sizeof(char),1,fpout); fwrite(vv,sizeof(int),3,fpout); if(HasPerFaceFlags(m)&&( pi.mask & Mask::IOM_FACEFLAGS) ) fwrite(&(fp->Flags()),sizeof(int),1,fpout); - if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) ) + if( HasPerVertexTexCoord(m) && (!HasPerWedgeTexCoord(m)) && (pi.mask & Mask::IOM_WEDGTEXCOORD) ) // Note that you can save VT as WT if you really want it... { - fwrite(&b6,sizeof(char),1,fpout); + fwrite(&b6char,sizeof(char),1,fpout); float t[6]; for(int k=0;k<3;++k) { @@ -487,7 +579,7 @@ namespace vcg { } else if( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) ) { - fwrite(&b6,sizeof(char),1,fpout); + fwrite(&b6char,sizeof(char),1,fpout); float t[6]; for(int k=0;k<3;++k) { @@ -497,7 +589,7 @@ namespace vcg { fwrite(t,sizeof(float),6,fpout); } - if(multit) + if(saveTexIndexFlag) { int t = fp->WT(0).n(); fwrite(&t,sizeof(int),1,fpout); @@ -509,7 +601,7 @@ namespace vcg { if( HasPerWedgeColor(m) && (pi.mask & Mask::IOM_WEDGCOLOR) ) { - fwrite(&b9,sizeof(char),1,fpout); + fwrite(&b9char,sizeof(char),1,fpout); float t[3]; for(int z=0;z<3;++z) { @@ -524,17 +616,34 @@ namespace vcg { fwrite( &(fp->Q()),sizeof(typename FaceType::ScalarType),1,fpout); - for(i=0;iWT(0).n()); } @@ -589,20 +698,36 @@ namespace vcg { if( HasPerFaceQuality(m) && (pi.mask & Mask::IOM_FACEQUALITY) ) fprintf(fpout,"%.*g ",DGTFQ,fp->Q()); - for(i=0;i > & shots, shots[i].Intrinsics.FocalMm = f/100.0f; shots[i].Intrinsics.k[0] = 0.0;//k1; To be uncommented when distortion is taken into account reliably shots[i].Intrinsics.k[1] = 0.0;//k2; - shots[i].Intrinsics.PixelSizeMm = vcg::Point2(0.01,0.01); + shots[i].Intrinsics.PixelSizeMm = vcg::Point2(ScalarType(0.01), ScalarType(0.01)); QImageReader sizeImg(QString::fromStdString(image_filenames[i])); QSize size=sizeImg.size(); shots[i].Intrinsics.ViewportPx = vcg::Point2i(size.width(),size.height()); diff --git a/wrap/io_trimesh/import_obj.h b/wrap/io_trimesh/import_obj.h index 31033ee6..9a924dc8 100644 --- a/wrap/io_trimesh/import_obj.h +++ b/wrap/io_trimesh/import_obj.h @@ -615,6 +615,15 @@ namespace vcg { } else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage { + // emergency check. If there are no materials, the materail library failed to load or was not specified + // but there are tools that save the material library with the same name of the file, but do not add the + // "mtllib" definition in the header. So, we can try to see if this is the case + if ((materials.size() == 1)&&(materials[0].materialName == "")){ + std::string materialFileName(filename); + materialFileName.replace(materialFileName.end()-4, materialFileName.end(), ".mtl"); + LoadMaterials(materialFileName.c_str(), materials, m.textures); + } + std::string materialName; if (tokens.size() == 2) materialName = tokens[1]; //play it safe @@ -887,6 +896,7 @@ namespace vcg { oi.numNormals=0; int lineCount=0; int totRead=0; + bool firstV = true; std::string line; while (!stream.eof()) { @@ -899,11 +909,20 @@ namespace vcg { { if(line[0]=='v') { - if(line[1]==' ') + if ((line[1] == ' ') || (line[1] == '\t')) { oi.numVertices++; - if(line.size()>=7) - bHasPerVertexColor = true; + if (firstV) + { + int sepN = 0; + for (size_t lit = 0; lit < line.size(); lit++){ + if ((line[lit] == ' ') || (line[lit] == '\t')) + sepN++; + } + if (sepN >= 6) + bHasPerVertexColor = true; + firstV = false; + } } if(line[1]=='t') oi.numTexCoords++; if(line[1]=='n') { @@ -930,8 +949,8 @@ namespace vcg { // Usually if you have tex coords you also have materials oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; } - if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; - if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; + if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; + if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; if (bHasNormals) { if (oi.numNormals == oi.numVertices) oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; diff --git a/wrap/io_trimesh/import_ply.h b/wrap/io_trimesh/import_ply.h index a37e9240..abff74c1 100644 --- a/wrap/io_trimesh/import_ply.h +++ b/wrap/io_trimesh/import_ply.h @@ -210,8 +210,8 @@ static const PropDescriptor &FaceDesc(int i) /* 5 */ {"face", "texnumber", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,texcoordind), 0,0,0,0,0 ,0}, /* 6 */ {"face", "red" , ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,r), 0,0,0,0,0 ,0}, /* 7 */ {"face", "green", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,g), 0,0,0,0,0 ,0}, -/* 8 */ {"face", "blue", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,b), 0,0,0,0,0 ,0}, -/* 9 */ {"face", "alpha", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,a), 0,0,0,0,0 ,0}, +/* 8 */ {"face", "blue", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,b), 0,0,0,0,0 ,0}, +/* 9 */ {"face", "alpha", ply::T_UCHAR, ply::T_UCHAR, offsetof(LoadPly_FaceAux,a), 0,0,0,0,0 ,0}, /* 10 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_UCHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, /* 11 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_CHAR, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, /* 12 */ {"face", "vertex_index", ply::T_INT, ply::T_INT, offsetof(LoadPly_FaceAux,v), 1,0,ply::T_INT, ply::T_CHAR,offsetof(LoadPly_FaceAux,size) ,0}, @@ -547,15 +547,15 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi ) } // User defined descriptors - std::vector VPV(pi.vdn); // property descriptor relative al tipo LoadPly_VertexAux - std::vector FPV(pi.fdn); // property descriptor relative al tipo LoadPly_FaceAux - if(pi.vdn>0){ + std::vector VPV(pi.VertDescriptorVec.size()); // property descriptor relative al tipo LoadPly_VertexAux + std::vector FPV(pi.FaceDescriptorVec.size()); // property descriptor relative al tipo LoadPly_FaceAux + if(pi.VertDescriptorVec.size()>0){ // Compute the total size needed to load additional per vertex data. size_t totsz=0; - for(int i=0;i,data)+totsz; - totsz+=pi.VertexData[i].memtypesize(); + totsz+=pi.VertDescriptorVec[i].memtypesize(); if( pf.AddToRead(VPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; } } if(totsz > MAX_USER_DATA) @@ -564,12 +564,12 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi ) return pi.status; } } - if(pi.fdn>0){ + if(pi.FaceDescriptorVec.size()>0){ size_t totsz=0; - for(int i=0;i MAX_USER_DATA) @@ -583,7 +583,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi ) /* Main Reading Loop */ /**************************************************************/ m.Clear(); - for(int i=0;i=m.vn ) + { + pi.status = PlyInfo::E_BAD_VERT_INDEX; + return pi.status; + } + (*fi).V(k) = index[ fa.v[k] ]; + } + fi++; + continue; + } + /// Now the temporary struct 'fa' is ready to be copied into the real face '*fi' /// This loop for(k=0;k<3;++k) @@ -820,8 +836,8 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi ) // tag faux vertices of first face if (fa.size>3) fi->SetF(2); - for(k=0;kSetF(0); if(qq<(fa.size-4)) fi->SetF(2); - for(k=0;k(bufstr.length()); - for(i=0;i32 && bufstr[i]<125 ) bufclean.push_back(bufstr[i]); char buf2[255]; @@ -1036,8 +1052,7 @@ int LoadCamera(const char * filename) bool found = true; - int i; - for(i=0;i<23;++i) + for(int i=0;i<23;++i) { if( pf.AddToRead(CameraDesc(i))==-1 ) { @@ -1049,7 +1064,7 @@ int LoadCamera(const char * filename) if(!found) return this->pi.status; - for(i=0;i +#include #include namespace vcg { @@ -60,10 +61,11 @@ public: }; enum STLError { - E_NOERROR, // 0 - // Errori di open - E_CANTOPEN, // 1 - E_UNESPECTEDEOF // 2 + E_NOERROR, // 0 + E_CANTOPEN, // 1 + E_UNESPECTEDEOF, // 2 + E_MALFORMED, // 3 + E_LAST }; static const char *ErrorMsg(int error) @@ -72,20 +74,23 @@ static const char *ErrorMsg(int error) { "No errors", "Can't open file", - "Premature End of file", + "Premature end of file", + "Malformed file", }; - if(error>2 || error<0) return "Unknown error"; + if(error>=E_LAST || error<0) return "Unknown error"; else return stl_error_msg[error]; -}; +} static bool LoadMask(const char * filename, int &mask) { - bool magicMode; + bool magicMode,colored; mask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; - if(IsSTLColored(filename,magicMode)) - mask |= Mask::IOM_FACECOLOR; - return true; + if(!IsSTLColored(filename, colored, magicMode)) + return false; + + if(colored) mask |= Mask::IOM_FACECOLOR; + return true; } /* Try to guess if a stl has color @@ -94,11 +99,19 @@ static bool LoadMask(const char * filename, int &mask) * - It has to be binary * - The per face attribute should be not zero * + * return false in case of malformed files */ -static bool IsSTLColored(const char * filename, bool &magicsMode) +static bool IsSTLColored(const char * filename, bool &coloredFlag, bool &magicsMode) { - if(IsSTLBinary(filename)==false) + coloredFlag=false; + magicsMode=false; + bool binaryFlag; + if(IsSTLBinary(filename,binaryFlag)==false) return false; + + if(binaryFlag==false) + return true; + FILE *fp = fopen(filename, "rb"); char buf[STL_LABEL_SIZE+1]; fread(buf,sizeof(char),STL_LABEL_SIZE,fp); @@ -123,39 +136,54 @@ static bool IsSTLColored(const char * filename, bool &magicsMode) if(attr!=0) { if(Color4b::FromUnsignedR5G5B5(attr) != Color4b(Color4b::White)) - return true; + coloredFlag=true; } } - return false; + return true; } -static bool IsSTLBinary(const char * filename) +/* Try to guess if a stl is in binary format + * + * return false in case of malformed files + */ +static bool IsSTLBinary(const char * filename, bool &binaryFlag) { - bool binary=false; + binaryFlag=false; FILE *fp = fopen(filename, "r"); /* Find size of file */ fseek(fp, 0, SEEK_END); - int file_size = ftell(fp); - int facenum; + long file_size = ftell(fp); + unsigned int facenum; /* Check for binary or ASCII file */ fseek(fp, STL_LABEL_SIZE, SEEK_SET); - fread(&facenum, sizeof(int), 1, fp); + fread(&facenum, sizeof(unsigned int), 1, fp); + int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+sizeof(STLFacet) )*facenum ; - if(file_size == expected_file_size) binary = true; - unsigned char tmpbuf[128]; - fread(tmpbuf,sizeof(tmpbuf),1,fp); - for(unsigned int i = 0; i < sizeof(tmpbuf); i++) + if(file_size == expected_file_size) + { + binaryFlag = true; + return true; + } + + // second check, sometimes the size is a bit wrong, + // lets'make a test to check that we find only ascii stuff before assuming it is ascii + unsigned char tmpbuf[1000]; + int byte_to_read = std::min(int(sizeof(tmpbuf)), int(file_size - 80)); + fread(tmpbuf, byte_to_read,1,fp); + fclose(fp); + for(int i = 0; i < byte_to_read; i++) { if(tmpbuf[i] > 127) { - binary=true; + binaryFlag=true; + if(abs(file_size-expected_file_size) > file_size/20 ) + return false; // break; } } // Now we know if the stl file is ascii or binary. - fclose(fp); - return binary; + return true; } static int Open( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0) @@ -165,8 +193,11 @@ static int Open( OpenMeshType &m, const char * filename, int &loadMask, CallBack return E_CANTOPEN; fclose(fp); loadMask |= Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; - - if(IsSTLBinary(filename)) return OpenBinary(m,filename,loadMask,cb); + bool binaryFlag; + if(!IsSTLBinary(filename,binaryFlag)) + return E_MALFORMED; + + if(binaryFlag) return OpenBinary(m,filename,loadMask,cb); else return OpenAscii(m,filename,cb); } @@ -179,8 +210,10 @@ static int OpenBinary( OpenMeshType &m, const char * filename, int &loadMask, Ca return E_CANTOPEN; } - bool magicsMode; - if(!IsSTLColored(filename,magicsMode)) + bool magicsMode,coloredFlag; + if(!IsSTLColored(filename,coloredFlag, magicsMode)) + return E_MALFORMED; + if(!coloredFlag) loadMask = loadMask & (~Mask::IOM_FACECOLOR); int facenum; diff --git a/wrap/io_trimesh/io_ply.h b/wrap/io_trimesh/io_ply.h index 33db9d4c..b376ee86 100644 --- a/wrap/io_trimesh/io_ply.h +++ b/wrap/io_trimesh/io_ply.h @@ -52,6 +52,8 @@ namespace vcg { namespace tri { namespace io { + + /** Additional data needed or useful for parsing a ply mesh. This class can be passed to the ImporterPLY::Open() function for @@ -63,14 +65,66 @@ class PlyInfo { public: typedef ::vcg::ply::PropDescriptor PropDescriptor ; - + + void AddPerElemFloatAttribute(int elemType, const char *attrName, const char * propName=0) + { + static const char *elemStr[2]={"vertex","face"}; + static std::vector *elemDescVec[2]={&(this->VertDescriptorVec), &(this->FaceDescriptorVec)}; + static std::vector *elemNameVec[2]={&(this->VertAttrNameVec), &(this->FaceAttrNameVec)}; + + if(propName==0) propName=attrName; + elemDescVec[elemType]->push_back(PropDescriptor()); + elemNameVec[elemType]->push_back(attrName); + elemDescVec[elemType]->back().elemname=elemStr[elemType]; + elemDescVec[elemType]->back().propname=strdup(propName); + elemDescVec[elemType]->back().stotype1 = vcg::ply::T_FLOAT; + elemDescVec[elemType]->back().memtype1 = vcg::ply::T_FLOAT; + } + + void AddPerVertexFloatAttribute(const char *attrName, const char *propName=0) { + AddPerElemFloatAttribute(0,attrName,propName); + } + void AddPerFaceFloatAttribute(const char *attrName, const char *propName=0) { + AddPerElemFloatAttribute(1,attrName,propName); + } + + + /* Note that saving a per vertex point3 attribute is a mess. + * Actually require to allocate 3 float attribute and save them. And they are never deallocated... */ + template + void AddPerVertexPoint3fAttribute(MeshType &m, const char *attrName, const char *propName="") + { + if(propName==0) propName=attrName; + + const char *attrxyz[3] = { + strdup((std::string(attrName)+std::string("_x")).c_str()), + strdup((std::string(attrName)+std::string("_y")).c_str()), + strdup((std::string(attrName)+std::string("_z")).c_str()), + }; + typename MeshType::template PerVertexAttributeHandle + ht = vcg::tri::Allocator:: template GetPerVertexAttribute (m,attrName); + + typename MeshType::template PerVertexAttributeHandle htt[3]; + + for(int i=0;i<3;++i) + { + htt[i] = vcg::tri::Allocator:: template GetPerVertexAttribute (m,std::string(attrxyz[i])); +// ForEachVertex (m, [&](typename MeshType::VertexType &v) { +// htt[i][v] = ht[v][i]; +// }); + for(auto vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!vi->IsD()) + htt[i][vi] = ht[vi][i]; + AddPerVertexFloatAttribute(attrxyz[i]); + } + } + + PlyInfo() { status=0; mask=0; - cb=0; - vdn=fdn=0; - VertexData=FaceData=0; + cb=0; } /// Store the error codes enconutered when parsing a ply int status; @@ -81,15 +135,16 @@ public: // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...) CallBackPos *cb; - /// the number of per-vertex descriptor (usually 0) - int vdn; /// The additional vertex descriptor that a user can specify to load additional per-vertex non-standard data stored in a ply - PropDescriptor *VertexData; - /// the number of per-face descriptor (usually 0) - int fdn; + std::vector VertDescriptorVec; + /// AttributeName is an array, externally allocated, containing the names of the attributes to be saved (loaded). + /// We assume that AttributeName[], if not empty, is exactly of the same size of VertexdData[] + /// If AttributeName[i] is not empty we use it to retrieve/store the info instead of the offsetted space in the current vertex + std::vector VertAttrNameVec; /// The additional vertex descriptor that a user can specify to load additional per-face non-standard data stored in a ply - PropDescriptor *FaceData; + std::vector FaceDescriptorVec; + std::vector FaceAttrNameVec; /// a string containing the current ply header. Useful for showing it to the user. std::string header;