This commit is contained in:
T.Alderighi 2018-04-05 18:46:15 +02:00
commit 58a9b0eefe
42 changed files with 827 additions and 292 deletions

6
.gitignore vendored
View File

@ -19,3 +19,9 @@ release/
*.vcxproj *.vcxproj
*.vcxproj.filters *.vcxproj.filters
*.suo *.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

View File

@ -296,15 +296,14 @@ int main(int argc, char**argv)
// save error files. // save error files.
if(flags & SamplingFlags::SAVE_ERROR) if(flags & SamplingFlags::SAVE_ERROR)
{ {
vcg::tri::io::PlyInfo p; int saveMask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY /* | vcg::ply::PLYMask::PM_VERTQUALITY*/ ;
p.mask|=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; //p.mask|=vcg::ply::PLYMask::PM_VERTCOLOR|vcg::ply::PLYMask::PM_VERTQUALITY;
if(ColorMax!=0 || ColorMin != 0){ if(ColorMax!=0 || ColorMin != 0){
vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S1,ColorMin,ColorMax); vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S1,ColorMin,ColorMax);
vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S2,ColorMin,ColorMax); vcg::tri::UpdateColor<CMesh>::PerVertexQualityRamp(S2,ColorMin,ColorMax);
} }
tri::io::ExporterPLY<CMesh>::Save( S1,S1NewName.c_str(),true,p); tri::io::ExporterPLY<CMesh>::Save( S1,S1NewName.c_str(),saveMask);
tri::io::ExporterPLY<CMesh>::Save( S2,S2NewName.c_str(),true,p); tri::io::ExporterPLY<CMesh>::Save( S2,S2NewName.c_str(),saveMask);
} }
// save error files. // save error files.

View File

@ -2,6 +2,7 @@
TEMPLATE = subdirs TEMPLATE = subdirs
SUBDIRS = trimesh_allocate \ SUBDIRS = trimesh_allocate \
trimesh_attribute \ trimesh_attribute \
trimesh_attribute_saving \
trimesh_ball_pivoting \ trimesh_ball_pivoting \
trimesh_base \ trimesh_base \
trimesh_closest \ trimesh_closest \
@ -37,6 +38,7 @@ SUBDIRS = trimesh_allocate \
trimesh_smooth \ trimesh_smooth \
trimesh_split_vertex \ trimesh_split_vertex \
trimesh_texture \ trimesh_texture \
trimesh_texture_clean \
trimesh_topology \ trimesh_topology \
trimesh_topological_cut \ trimesh_topological_cut \
trimesh_voronoi \ trimesh_voronoi \

View File

@ -1,3 +1,3 @@
include(../common.pri) include(../common.pri)
TARGET = trimesh_attribute TARGET = trimesh_attribute
SOURCES += trimesh_attribute.cpp ../../../wrap/ply/plylib.cpp SOURCES += trimesh_attribute.cpp

View File

@ -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<vcg/complex/complex.h>
#include<vcg/complex/algorithms/create/platonic.h>
#include<wrap/io_trimesh/export_ply.h>
class MyEdge;
class MyFace;
class MyVertex;
struct MyUsedTypes : public vcg::UsedTypes< vcg::Use<MyVertex>::AsVertexType,
vcg::Use<MyFace> ::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<MyVertex>, std::vector<MyFace> > {};
int main()
{
MyMesh m;
Torus<MyMesh>(m, 3.0f, 1.0f);
//! [Adding a few attributes]
// add a per-vertex attribute with type float named "GaussianCurvature"
MyMesh::PerVertexAttributeHandle<float>
hvf = vcg::tri::Allocator<MyMesh>:: GetPerVertexAttribute<float> (m,std::string("GaussianCurvature"));
MyMesh::PerVertexAttributeHandle<vcg::Point3f>
hv3f = vcg::tri::Allocator<MyMesh>:: GetPerVertexAttribute<vcg::Point3f> (m,std::string("InvertedNormal"));
// add a per-face attribute with type float named "FaceArea"
MyMesh::PerFaceAttributeHandle<float>
hff = vcg::tri::Allocator<MyMesh>:: GetPerFaceAttribute<float> (m,std::string("FaceArea"));
//! [filling the attribute]
vcg::tri::Allocator<MyMesh>::ClearPerVertexAttribute<float>(m,hvf, float(M_PI*2));
vcg::tri::Allocator<MyMesh>::ClearPerVertexAttribute<vcg::Point3f>(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<MyMesh>::Save(m,"MeshWithCurvature.ply",false,pi);
}

View File

@ -0,0 +1,3 @@
include(../common.pri)
TARGET = trimesh_attribute_saving
SOURCES += trimesh_attribute_saving.cpp ../../../wrap/ply/plylib.cpp

View File

@ -102,8 +102,7 @@ int main(int argc, char **argv)
printf("Output mesh vn:%i fn:%i\n",m.VN(),m.FN()); 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); printf("Created in :%i msec (%i+%i)\n",t2-t0,t1-t0,t2-t1);
vcg::tri::io::PlyInfo pi; vcg::tri::io::ExporterPLY<MyMesh>::Save(m,argv[2]);
vcg::tri::io::ExporterPLY<MyMesh>::Save(m,argv[2],pi.mask);
return 0; return 0;
} }

View File

@ -137,8 +137,6 @@ int main(int argc, char **argv)
printf("Output mesh vn:%i fn:%i\n",m.VN(),m.FN()); printf("Output mesh vn:%i fn:%i\n",m.VN(),m.FN());
vcg::tri::io::PlyInfo pi; vcg::tri::io::Exporter<MyMesh>::Save(m,argv[2],vcg::tri::io::Mask::IOM_BITPOLYGONAL);
pi.mask|=vcg::tri::io::Mask::IOM_BITPOLYGONAL;
vcg::tri::io::Exporter<MyMesh>::Save(m,argv[2],pi.mask);
return 0; return 0;
} }

View File

@ -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<vcg/complex/complex.h>
#include <wrap/io_trimesh/export_obj.h>
#include <vcg/complex/algorithms/update/texture.h>
#include <vcg/complex/algorithms/create/platonic.h>
/*! \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<MyVertex>::AsVertexType, Use<MyFace>::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<MyVertex>, std::vector<MyFace > >{};
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<MyMesh>::WedgeTexFromPlane(m,Point3f(1.0f,0,0),Point3f(0,1.0f,0),true);
tri::io::ExporterOBJ<MyMesh>::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<MyMesh>::Save(m,"grid_1.obj",mask);
// Merge texture coords that very close
tri::UpdateTopology<MyMesh>::VertexFace(m);
tri::UpdateTexture<MyMesh>::WedgeTexMergeClose(m);
tri::io::ExporterOBJ<MyMesh>::Save(m,"grid_2.obj",mask);
return 0;
}

View File

@ -0,0 +1,4 @@
include(../common.pri)
TARGET = trimesh_texture_clean
SOURCES += trimesh_texture_clean.cpp

View File

@ -24,6 +24,8 @@
#ifndef __VCGLIB_CLEAN #ifndef __VCGLIB_CLEAN
#define __VCGLIB_CLEAN #define __VCGLIB_CLEAN
#include <unordered_set>
// VCG headers // VCG headers
#include <vcg/complex/complex.h> #include <vcg/complex/complex.h>
#include <vcg/complex/algorithms/closest.h> #include <vcg/complex/algorithms/closest.h>
@ -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 m The mesh
@param DeleteVertexFlag if false prevent the vertex deletion and just count it. @param DeleteVertexFlag if false prevent the vertex deletion and just count it.
@return The number of removed vertices @return The number of removed vertices
@ -583,7 +585,7 @@ public:
firstVp++; firstVp++;
} }
return ToSplitVec.size(); return int(ToSplitVec.size());
} }
@ -1369,7 +1371,7 @@ public:
count = 0; count = 0;
ScalarType NormalThrRad = math::ToRad(normalThresholdDeg); 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 //detection stage
for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV()) for(FaceIterator fi=m.face.begin();fi!= m.face.end();++fi ) if(!(*fi).IsV())
{ Point3<ScalarType> NN = vcg::TriangleNormal((*fi)).Normalize(); { Point3<ScalarType> NN = vcg::TriangleNormal((*fi)).Normalize();
@ -1790,6 +1792,7 @@ public:
*/ */
static void SelectFoldedFaceFromOneRingFaces(MeshType &m, ScalarType cosThreshold) static void SelectFoldedFaceFromOneRingFaces(MeshType &m, ScalarType cosThreshold)
{ {
typedef std::unordered_set<VertexPointer> VertexSet;
tri::RequireVFAdjacency(m); tri::RequireVFAdjacency(m);
tri::RequirePerFaceNormal(m); tri::RequirePerFaceNormal(m);
tri::RequirePerVertexNormal(m); tri::RequirePerVertexNormal(m);
@ -1803,33 +1806,33 @@ public:
#pragma omp parallel for schedule(dynamic, 10) #pragma omp parallel for schedule(dynamic, 10)
for (int i = 0; i < m.face.size(); i++) for (int i = 0; i < m.face.size(); i++)
{ {
std::vector<typename MeshType::VertexPointer> nearVertex; VertexSet nearVertex;
std::vector<typename MeshType::CoordType> point; std::vector<CoordType> pointVec;
typename MeshType::FacePointer f = &m.face[i]; FacePointer f = &m.face[i];
for (int j = 0; j < 3; j++) for (int j = 0; j < 3; j++)
{ {
std::vector<typename MeshType::VertexPointer> temp; std::vector<VertexPointer> temp;
vcg::face::VVStarVF<typename MeshType::FaceType>(f->V(j), temp); vcg::face::VVStarVF<FaceType>(f->V(j), temp);
typename std::vector<typename MeshType::VertexPointer>::iterator iter = temp.begin(); typename std::vector<VertexPointer>::iterator iter = temp.begin();
for (; iter != temp.end(); iter++) for (; iter != temp.end(); iter++)
{ {
if ((*iter) != f->V1(j) && (*iter) != f->V2(j)) if ((*iter) != f->V1(j) && (*iter) != f->V2(j))
{ {
nearVertex.push_back((*iter)); if (nearVertex.insert((*iter)).second)
point.push_back((*iter)->P()); pointVec.push_back((*iter)->P());
} }
} }
nearVertex.push_back(f->V(j)); nearVertex.insert(f->V(j));
point.push_back(f->P(j)); pointVec.push_back(f->P(j));
} }
if (point.size() > 3) if (pointVec.size() > 3)
{ {
vcg::Plane3<typename MeshType::ScalarType> plane; vcg::Plane3<ScalarType> plane;
vcg::FitPlaneToPointSet(point, plane); vcg::FitPlaneToPointSet(pointVec, plane);
float avgDot = 0; float avgDot = 0;
for (int j = 0; j < nearVertex.size(); j++) for (auto nvp : nearVertex)
avgDot += plane.Direction().dot(nearVertex[j]->N()); avgDot += plane.Direction().dot(nvp->N());
avgDot /= nearVertex.size(); avgDot /= nearVertex.size();
typename MeshType::VertexType::NormalType normal; typename MeshType::VertexType::NormalType normal;
if (avgDot < 0) if (avgDot < 0)

View File

@ -398,7 +398,7 @@ public:
{ {
visible.vert[i].P() = m.vert[ind].P(); visible.vert[i].P() = m.vert[ind].P();
m.vert[ind].SetS(); m.vert[ind].SetS();
m.vert[ind].C() = Color4b::LightBlue; //m.vert[ind].C() = Color4b::LightBlue;
selCnt++; selCnt++;
} }
} }
@ -416,6 +416,8 @@ public:
tri::Allocator<CHMesh>::CompactEveryVector(visible); tri::Allocator<CHMesh>::CompactEveryVector(visible);
tri::Clean<CHMesh>::FlipMesh(visible); tri::Clean<CHMesh>::FlipMesh(visible);
tri::UpdateNormal<CHMesh>::PerFaceNormalized(visible);
tri::UpdateNormal<CHMesh>::PerVertexNormalized(visible);
} }
}; };

View File

@ -99,7 +99,7 @@ template <class MESH> class AdvancingFront {
void BuildMesh(CallBackPos call = NULL, int interval = 512) void BuildMesh(CallBackPos call = NULL, int interval = 512)
{ {
float finalfacesext = mesh.vert.size() * 2.0f; float finalfacesext = mesh.vert.size() * 2.0f;
if(call) call(0, "Advancing front"); if (call) (*call)(0, "Advancing front");
while(1) { while(1) {
for(int i = 0; i < interval; i++) { for(int i = 0; i < interval; i++) {

View File

@ -120,7 +120,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
targets.push_back(vp); targets.push_back(vp);
} }
int n = targets.size(); int n = int(targets.size());
if(n<3) continue; if(n<3) continue;
bool success = true; bool success = true;
@ -205,10 +205,10 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
Mark(vv1); Mark(vv1);
Mark(vv2); Mark(vv2);
v0 = tri::Index(this->mesh,vv0); v0 = int(tri::Index(this->mesh, vv0));
v1 = tri::Index(this->mesh,vv1); v1 = int(tri::Index(this->mesh, vv1));
v2 = tri::Index(this->mesh,vv2); v2 = int(tri::Index(this->mesh, vv2));
return true; return true;
} }
return false; return false;
} }
@ -252,7 +252,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
if(nn==0) return -1; if(nn==0) return -1;
VertexType *candidate = NULL; 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. // Loop over all the nearest vertexes and choose the best one according the ball pivoting strategy.
// //
@ -312,7 +312,7 @@ template <class MESH> class BallPivoting: public AdvancingFront<MESH> {
assert((candidate->P() - v1).Norm() > min_edge); 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); assert(candidateIndex != edge.v0 && candidateIndex != edge.v1);
Point3x newnormal = ((candidate->P() - v0)^(v1 - v0)).Normalize(); Point3x newnormal = ((candidate->P() - v0)^(v1 - v0)).Normalize();

View File

@ -59,7 +59,7 @@ namespace tri {
// Simple prototype for later use... // Simple prototype for later use...
template<class MeshType> template<class MeshType>
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 /** Surface Reconstruction
@ -550,63 +550,66 @@ template < class MeshType, class VertexPair>
template< class MeshType> 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<MeshType,BasicVertexPair<typename MeshType::VertexType> > MyColl; typedef PlyMCTriEdgeCollapse<MeshType,BasicVertexPair<typename MeshType::VertexType> > MyColl;
typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::CoordType CoordType; typedef typename MeshType::CoordType CoordType;
tri::UpdateBounding<MeshType>::Box(m); tri::UpdateBounding<MeshType>::Box(m);
tri::UpdateTopology<MeshType>::VertexFace(m); tri::UpdateTopology<MeshType>::VertexFace(m);
TriEdgeCollapseMCParameter pp; TriEdgeCollapseMCParameter pp;
pp.bb.Import(m.bbox); pp.bb.Import(m.bbox);
pp.preserveBBox=preserveBB; pp.preserveBBox=preserveBB;
vcg::LocalOptimization<MeshType> DeciSession(m,&pp); vcg::LocalOptimization<MeshType> DeciSession(m,&pp);
if(absoluteError==0) if(absoluteError==0)
{ {
// guess the mc side. // 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. // 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 // If you have 2 vert over the same face xy they share z
std::vector<float> ZSet; std::vector<float> ZSet;
for(FaceIterator fi = m.face.begin();fi!=m.face.end();++fi) for(FaceIterator fi = m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
{ {
CoordType v0=(*fi).V(0)->P(); CoordType v0=(*fi).V(0)->P();
CoordType v1=(*fi).V(1)->P(); CoordType v1=(*fi).V(1)->P();
CoordType v2=(*fi).V(2)->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]==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(v0[2]==v2[2] && v0[1]!=v2[1] && v0[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(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()>100) break;
} }
std::sort(ZSet.begin(),ZSet.end()); if (ZSet.size() == 0) return -1; //no straight edges found. exit with error
std::vector<float>::iterator lastV = std::unique(ZSet.begin(),ZSet.end()); std::sort(ZSet.begin(),ZSet.end());
ZSet.resize(lastV-ZSet.begin()); std::vector<float>::iterator lastV = std::unique(ZSet.begin(),ZSet.end());
float Delta=0; ZSet.resize(lastV-ZSet.begin());
for(size_t i = 0; i< ZSet.size()-1;++i) 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); Delta = std::max(ZSet[i+1]-ZSet[i],Delta);
} //qDebug("%f",Delta);
absoluteError= Delta/4.0f; }
} absoluteError= Delta/4.0f;
// qDebug("Simplifying at absoluteError=%f",absoluteError); }
//qDebug("Simplifying at absoluteError=%f",absoluteError);
float TargetError = absoluteError; float TargetError = absoluteError;
char buf[1024]; char buf[1024];
DeciSession.template Init< MyColl > (); DeciSession.template Init< MyColl > ();
pp.areaThr=TargetError*TargetError; pp.areaThr=TargetError*TargetError;
DeciSession.SetTimeBudget(1.0f); DeciSession.SetTimeBudget(1.0f);
if(TargetError < std::numeric_limits<float>::max() ) DeciSession.SetTargetMetric(TargetError); if(TargetError < std::numeric_limits<float>::max() ) DeciSession.SetTargetMetric(TargetError);
while(DeciSession.DoOptimization() && DeciSession.currMetric < TargetError) while(DeciSession.DoOptimization() && DeciSession.currMetric < TargetError)
{ {
sprintf(buf,"Simplyfing %7i err %9g \r",m.fn,DeciSession.currMetric); sprintf(buf,"Simplyfing %7i err %9g \r",m.fn,DeciSession.currMetric);
if (cb) cb(int(100.0f*DeciSession.currMetric/TargetError),buf); if (cb) cb(int(100.0f*DeciSession.currMetric/TargetError),buf);
} }
return 1; //success
} }

View File

@ -27,8 +27,9 @@
#include <vcg/complex/algorithms/update/bounding.h> #include <vcg/complex/algorithms/update/bounding.h>
#include <vcg/complex/algorithms/update/component_ep.h> #include <vcg/complex/algorithms/update/component_ep.h>
#include <vcg/complex/algorithms/create/marching_cubes.h> #include <vcg/complex/algorithms/create/marching_cubes.h>
#include <vcg/space/index/grid_static_ptr.h> //#include <vcg/space/index/grid_static_ptr.h>
#include <vcg/complex/algorithms/closest.h> //#include <vcg/complex/algorithms/closest.h>
#include <vcg/space/index/kdtree/kdtree_face.h>
namespace vcg { namespace vcg {
namespace tri { namespace tri {
@ -63,13 +64,15 @@ class Resampler : public BasicGrid<typename NewMeshType::ScalarType>
{ {
private: private:
typedef int VertexIndex; typedef int VertexIndex;
typedef typename vcg::GridStaticPtr<OldFaceType, OldScalarType> GridType; //typedef typename vcg::GridStaticPtr<OldFaceType, OldScalarType> GridType;
typedef vcg::KdTreeFace<OldMeshType> GridType;
protected: protected:
int SliceSize; int SliceSize;
int CurrentSlice; int CurrentSlice;
typedef tri::FaceTmark<OldMeshType> MarkerFace; //typedef tri::FaceTmark<OldMeshType> MarkerFace;
typedef vcg::tri::EmptyTMark<OldMeshType> MarkerFace;
MarkerFace markerFunctor; MarkerFace markerFunctor;
VertexIndex *_x_cs; // indici dell'intersezioni della superficie lungo gli Xedge della fetta corrente VertexIndex *_x_cs; // indici dell'intersezioni della superficie lungo gli Xedge della fetta corrente
@ -159,6 +162,7 @@ class Resampler : public BasicGrid<typename NewMeshType::ScalarType>
OldCoordType closestPt; OldCoordType closestPt;
DISTFUNCTOR PDistFunct; DISTFUNCTOR PDistFunct;
OldFaceType *f = _g.GetClosest(PDistFunct,markerFunctor,testPt,max_dist,dist,closestPt); OldFaceType *f = _g.GetClosest(PDistFunct,markerFunctor,testPt,max_dist,dist,closestPt);
if (f==NULL) return field_value(false,0); if (f==NULL) return field_value(false,0);
if(AbsDistFlag) return field_value(true,dist); if(AbsDistFlag) return field_value(true,dist);
assert(!f->IsD()); assert(!f->IsD());
@ -230,6 +234,7 @@ class Resampler : public BasicGrid<typename NewMeshType::ScalarType>
/// the distance of the bb /// the distance of the bb
void ComputeSliceValues(int slice,field_value *slice_values) 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 i=0; i<=this->siz.X(); i++)
{ {
for (int k=0; k<=this->siz.Z(); k++) for (int k=0; k<=this->siz.Z(); k++)

View File

@ -283,7 +283,7 @@ public:
template<class MESH> class MinimumWeightEar : public TrivialEar<MESH> template<class MESH> class MinimumWeightEar : public TrivialEar<MESH>
{ {
public: public:
static float &DiedralWeight() { static float _dw=0.1; return _dw;} static float &DiedralWeight() { static float _dw=0.1f; return _dw;}
typedef TrivialEar<MESH> TE; typedef TrivialEar<MESH> TE;
typename MESH::ScalarType dihedralRad; typename MESH::ScalarType dihedralRad;
typename MESH::ScalarType aspectRatio; typename MESH::ScalarType aspectRatio;

View File

@ -179,7 +179,7 @@ public:
this->optimalPos = newPos; this->optimalPos = newPos;
} }
void Execute(TriMeshType &m, BaseParameterClass */*_pp*/) void Execute(TriMeshType &m, BaseParameterClass * /*_pp*/)
{ {
CoordType newPos = this->optimalPos; 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 QH::Qd(this->pos.V(1))+=QH::Qd(this->pos.V(0)); // v0 is deleted and v1 take the new position

View File

@ -241,7 +241,7 @@ public:
{ {
tri::RequireCompactness(m); tri::RequireCompactness(m);
h.resize(m.vn); h.resize(m.vn);
for(int i=0;i<m.vn;++i) h[i]=0; fill(h.begin(),h.end(),0);
for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi)
{ {
ScalarType a = DoubleArea(*fi)/6.0; ScalarType a = DoubleArea(*fi)/6.0;

View File

@ -25,7 +25,6 @@
#include <vcg/space/index/kdtree/kdtree.h> #include <vcg/space/index/kdtree/kdtree.h>
namespace vcg namespace vcg
{ {
@ -94,7 +93,7 @@ class OutlierRemoval
dem += 0.230389 * value * value; dem += 0.230389 * value * value;
dem += 0.000972 * value * value * value; dem += 0.000972 * value * value * value;
dem += 0.078108 * value * 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; outlierScore[i] = op;
} }

View File

@ -162,7 +162,7 @@ public:
for (vi = m.vert.begin(); vi != m.vert.end(); ++vi) for (vi = m.vert.begin(); vi != m.vert.end(); ++vi)
if (!(*vi).IsD()) 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[0] += (double)((*vi).P()[0] * weight);
accumulator[1] += (double)((*vi).P()[1] * weight); accumulator[1] += (double)((*vi).P()[1] * weight);
accumulator[2] += (double)((*vi).P()[2] * weight); accumulator[2] += (double)((*vi).P()[2] * weight);
@ -212,6 +212,21 @@ public:
return area/ScalarType(2.0); return area/ScalarType(2.0);
} }
static ScalarType ComputeBorderLength(MeshType & m)
{
RequireFFAdjacency(m);
ScalarType sum = 0;
tri::UpdateTopology<MeshType>::FaceFace(m);
ForEachFace(m, [&](FaceType &f) {
for (int k=0; k<f.VN(); k++)
if (face::IsBorder(f, k))
{
sum += Distance(f.cP(k), f.cP(1));
}
});
return sum;
}
static void ComputePerVertexQualityDistribution( MeshType & m, Distribution<ScalarType> &h, bool selectionOnly = false) // V1.0 static void ComputePerVertexQualityDistribution( MeshType & m, Distribution<ScalarType> &h, bool selectionOnly = false) // V1.0
{ {
tri::RequirePerVertexQuality(m); tri::RequirePerVertexQuality(m);

View File

@ -790,6 +790,7 @@ static Color4b ColorDesaturate(Color4b c, int method)
} }
default: assert(0); default: assert(0);
} }
return Color4b(255, 255, 255, 255);
} }
//ausiliary function to compute average lightness. value = (R+G+B)/3 //ausiliary function to compute average lightness. value = (R+G+B)/3

View File

@ -48,6 +48,7 @@ typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FacePointer FacePointer;
typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceIterator FaceIterator;
typedef typename vcg::Point2<ScalarType> UVCoordType;
static void WedgeTexFromPlane(ComputeMeshType &m, const Point3<ScalarType> &uVec, const Point3<ScalarType> &vVec, bool aspectRatio, ScalarType sideGutter=0.0) static void WedgeTexFromPlane(ComputeMeshType &m, const Point3<ScalarType> &uVec, const Point3<ScalarType> &vVec, bool aspectRatio, ScalarType sideGutter=0.0)
{ {
@ -70,7 +71,7 @@ static void WedgeTexFromPlane(ComputeMeshType &m, const Point3<ScalarType> &uVec
if (sideGutter>0.0) 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.max[0] += deltaGutter;
bb.min[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<FaceType> vfi(&v);
std::vector<UVCoordType> 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 }; // end class

View File

@ -133,7 +133,7 @@ protected:
} }
public: public:
static const int VoroRelaxationStep = 20; static const int VoroRelaxationStep = 30;
/// ///
/// \brief Remesh the main function that remeshes a mesh preserving creases. /// \brief Remesh the main function that remeshes a mesh preserving creases.
@ -355,7 +355,7 @@ protected:
// refine to obtain a base mesh // refine to obtain a base mesh
VoronoiProcessingParameter vpp; VoronoiProcessingParameter vpp;
vpp.refinementRatio = 4.0f; vpp.refinementRatio = 5.0f;
Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp); Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp);
// Poisson sampling preserving border // Poisson sampling preserving border
@ -372,7 +372,15 @@ protected:
// Montecarlo oversampling // Montecarlo oversampling
Mesh montecarloMesh; 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<Mesh>::ComputeMeshArea(original);
const ScalarType meshBoundary = Stat<Mesh>::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; // std::cout << "poisson Count: " << poissonCount << std::endl;
if (poissonCount <= 0) if (poissonCount <= 0)
@ -386,7 +394,7 @@ protected:
else else
{ {
// Montecarlo poisson sampling // Montecarlo poisson sampling
SurfaceSampler::MontecarloPoisson(original, mps, poissonCount * 20); SurfaceSampler::MontecarloPoisson(original, mps, poissonCount * 40);
BuildMeshFromCoordVector(montecarloMesh,sampleVec); BuildMeshFromCoordVector(montecarloMesh,sampleVec);
#ifdef DEBUG_VORO #ifdef DEBUG_VORO
@ -421,6 +429,7 @@ protected:
vpp.seedPerturbationProbability = 0.0f; vpp.seedPerturbationProbability = 0.0f;
Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep, vpp); Voronoi::RestrictedVoronoiRelaxing(baseMesh, seedPointVec, seedFixedVec, VoroRelaxationStep, vpp);
#ifdef DEBUG_VORO #ifdef DEBUG_VORO
BuildMeshFromCoordVector(poissonMesh,seedPointVec); BuildMeshFromCoordVector(poissonMesh,seedPointVec);
io::ExporterPLY<MeshType>::Save(poissonMesh, QString("relaxedMesh_%1.ply").arg(idx).toStdString().c_str()); io::ExporterPLY<MeshType>::Save(poissonMesh, QString("relaxedMesh_%1.ply").arg(idx).toStdString().c_str());

View File

@ -1157,12 +1157,12 @@ public:
template <class ATTR_TYPE> template <class ATTR_TYPE>
static static
void void
ClearPerVertexAttribute( MeshType & m,typename MeshType::template PerVertexAttributeHandle<ATTR_TYPE> & h){ ClearPerVertexAttribute( MeshType & m,typename MeshType::template PerVertexAttributeHandle<ATTR_TYPE> & h, const ATTR_TYPE & initVal = ATTR_TYPE()){
typename std::set<PointerToAttribute > ::iterator i; typename std::set<PointerToAttribute > ::iterator i;
for( i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i) for( i = m.vert_attr.begin(); i != m.vert_attr.end(); ++i)
if( (*i)._handle == h._handle ){ if( (*i)._handle == h._handle ){
for(typename MeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) for(typename MeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
h[vi] = ATTR_TYPE(); h[vi] = initVal;
return;} return;}
assert(0); assert(0);
} }

View File

@ -92,7 +92,7 @@ static void UniformCone(int vn, std::vector<Point3<ScalarType > > &NN, ScalarTyp
printf("----------AngleRad %f Angledeg %f ratio %f vn %i vn2 %i \n",AngleRad,math::ToDeg(AngleRad),Ratio,vn,int(vn/Ratio)); 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); 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<Point3<ScalarType> >::iterator vi; typename std::vector<Point3<ScalarType> >::iterator vi;
ScalarType cosAngle = cos(AngleRad); ScalarType cosAngle = cos(AngleRad);

View File

@ -57,18 +57,23 @@ namespace vcg {
public: public:
KdTreeFace(MeshType& mesh, unsigned int maxObjPerCell = 64, unsigned int maxDepth = 64) : epsilon(std::numeric_limits<Scalar>::epsilon()) KdTreeFace():epsilon(std::numeric_limits<Scalar>::epsilon())
{
targetCellSize = 64;
targetMaxDepth = 64;
};
KdTreeFace(unsigned int maxObjPerCell, unsigned int maxDepth) : epsilon(std::numeric_limits<Scalar>::epsilon())
{ {
targetCellSize = maxObjPerCell; targetCellSize = maxObjPerCell;
targetMaxDepth = maxDepth; targetMaxDepth = maxDepth;
mNodes.resize(1); };
Node& node = mNodes.back();
node.leaf = 0; KdTreeFace(MeshType& mesh, unsigned int maxObjPerCell = 64, unsigned int maxDepth = 64, bool onlySelection = false) : epsilon(std::numeric_limits<Scalar>::epsilon())
node.aabb = mesh.bbox; {
node.aabb.Offset(VectorType(epsilon, epsilon, epsilon)); targetCellSize = maxObjPerCell;
for (int i = 0; i < mesh.face.size(); i++) targetMaxDepth = maxDepth;
node.list.push_back(&mesh.face[i]); Set(mesh.face.begin(), mesh.face.end(), mesh.face.size(), onlySelection);
numLevel = createTree(0, 1);
}; };
~KdTreeFace() ~KdTreeFace()
@ -76,10 +81,53 @@ namespace vcg {
}; };
template <class ObjIter>
template <class ObjectMarker> FacePointer doQueryClosest(const VectorType& queryPoint, VectorType& narestPoint, Scalar& dist, ObjectMarker& marker, Scalar maxDist = std::numeric_limits<Scalar>::max()) void Set(const ObjIter & _oBegin, const ObjIter & _oEnd, int size = 0, bool onlySelection = false)
{ {
if (maxDist < std::numeric_limits<Scalar>::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<Scalar> 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 <class ObjectMarker> FacePointer GetClosest(const VectorType& queryPoint, VectorType& narestPoint, Scalar& dist, ObjectMarker& marker, Scalar maxDist = std::numeric_limits<Scalar>::max())
template <class ObjPointDistFunction, class ObjectMarker>
FacePointer GetClosest(ObjPointDistFunction& pDistFunc, ObjectMarker& marker, const VectorType& queryPoint, Scalar maxDist, Scalar& dist, VectorType& narestPoint)
{
if (mNodes.size() == 0|| (maxDist < std::numeric_limits<Scalar>::max() && !mNodes[0].aabb.IsIn(queryPoint) && vcg::PointFilledBoxDistance(queryPoint, mNodes[0].aabb) >= maxDist))
{ {
dist = maxDist; dist = maxDist;
return NULL; return NULL;
@ -109,7 +157,7 @@ namespace vcg {
marker.Mark(node.list[i]); marker.Mark(node.list[i]);
Scalar tempDist = minDist; Scalar tempDist = minDist;
VectorType tempP; VectorType tempP;
if (vcg::face::PointDistanceBase(*node.list[i], queryPoint, tempDist, tempP)) if (pDistFunc(*node.list[i], queryPoint, tempDist, tempP))
{ {
if (tempDist < minDist) 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]; Node& node = mNodes[nodeId];
VectorType diag = node.aabb.max - node.aabb.min; VectorType diag = node.aabb.max - node.aabb.min;
@ -264,7 +312,7 @@ namespace vcg {
else else
{ {
leftChild.leaf = 0; leftChild.leaf = 0;
leftLevel = createTree(firstChildId, level + 1); leftLevel = CreateTree(firstChildId, level + 1);
} }
} }
@ -278,7 +326,7 @@ namespace vcg {
else else
{ {
rightChild.leaf = 0; rightChild.leaf = 0;
rightLevel = createTree(firstChildId + 1, level + 1); rightLevel = CreateTree(firstChildId + 1, level + 1);
} }
} }
if (leftLevel > rightLevel) if (leftLevel > rightLevel)

View File

@ -206,7 +206,7 @@ protected:
inSphVec.push_back(hi); inSphVec.push_back(hi);
} }
} }
return inSphVec.size(); return int(inSphVec.size());
} }
size_t RemoveInSphere(const Point3<ScalarType> &p, const ScalarType radius) size_t RemoveInSphere(const Point3<ScalarType> &p, const ScalarType radius)

View File

@ -50,26 +50,26 @@ void ComputeCrossCovarianceMatrix(const std::vector<Point3<S> > &spVec, Point3<S
const std::vector<Point3<S> > &tpVec, Point3<S> &tpBarycenter, const std::vector<Point3<S> > &tpVec, Point3<S> &tpBarycenter,
Eigen::Matrix3d &m) Eigen::Matrix3d &m)
{ {
assert(spVec.size()==tpVec.size()); assert(spVec.size() == tpVec.size());
m.setZero(); m.setZero();
spBarycenter.SetZero(); spBarycenter.SetZero();
tpBarycenter.SetZero(); tpBarycenter.SetZero();
Eigen::Vector3d spe; Eigen::Vector3d spe;
Eigen::Vector3d tpe; Eigen::Vector3d tpe;
typename std::vector <Point3<S> >::const_iterator si,ti; typename std::vector <Point3<S> >::const_iterator si, ti;
for(si=spVec.begin(),ti=tpVec.begin();si!=spVec.end();++si,++ti){ for (si = spVec.begin(), ti = tpVec.begin(); si != spVec.end(); ++si, ++ti){
spBarycenter+=*si; spBarycenter += *si;
tpBarycenter+=*ti; tpBarycenter += *ti;
si->ToEigenVector(spe); si->ToEigenVector(spe);
ti->ToEigenVector(tpe); ti->ToEigenVector(tpe);
m+=spe*tpe.transpose(); m += spe*tpe.transpose();
} }
spBarycenter/=spVec.size(); spBarycenter /= double(spVec.size());
tpBarycenter/=tpVec.size(); tpBarycenter /= double(tpVec.size());
spBarycenter.ToEigenVector(spe); spBarycenter.ToEigenVector(spe);
tpBarycenter.ToEigenVector(tpe); tpBarycenter.ToEigenVector(tpe);
m/=spVec.size(); m /= double(spVec.size());
m-=spe*tpe.transpose(); m -= spe*tpe.transpose();
} }
/*! \brief Compute the roto-translation that applied to PMov bring them onto Pfix /*! \brief Compute the roto-translation that applied to PMov bring them onto Pfix

View File

@ -760,7 +760,7 @@ namespace Tags
class BindVertexInputTag : public XMLTag class BindVertexInputTag : public XMLTag
{ {
public: 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") :XMLTag("bind_vertex_input")
{ {
_attributes.push_back(TagAttribute("semantic",semantic)); _attributes.push_back(TagAttribute("semantic",semantic));

View File

@ -97,7 +97,7 @@ namespace vcg
_perwire_noshading = true; _perwire_noshading = true;
_persolid_noshading = false; _persolid_noshading = false;
_perpoint_pointsize = 1.0f; _perpoint_pointsize = 3.0f;
_perpoint_pointsmooth_enabled = false; _perpoint_pointsmooth_enabled = false;
_perpoint_pointattenuation_enabled = true; _perpoint_pointattenuation_enabled = true;
_perwire_wirewidth = 1.0f; _perwire_wirewidth = 1.0f;
@ -296,7 +296,7 @@ namespace vcg
if (_glopts != NULL) if (_glopts != NULL)
{ {
std::string tmp; std::string tmp;
int size = _glopts->serialize(tmp); size_t size = _glopts->serialize(tmp);
token[i] = str.substr(pos, size); token[i] = str.substr(pos, size);
if (token[i].length() < size) if (token[i].length() < size)
return false; return false;
@ -1509,7 +1509,7 @@ namespace vcg
{ {
//qDebug("Indexed drawing"); //qDebug("Indexed drawing");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_VERTINDICES]->_bohandle); 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); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
@ -1819,7 +1819,7 @@ namespace vcg
//qDebug("Indexed drawing"); //qDebug("Indexed drawing");
updateClientState(req); updateClientState(req);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bo[INT_ATT_NAMES::ATT_EDGEINDICES]->_bohandle); 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); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
InternalRendAtts tmp; InternalRendAtts tmp;
updateClientState(tmp); updateClientState(tmp);
@ -2235,8 +2235,8 @@ namespace vcg
assert(nz >= 0); assert(nz >= 0);
assert(nz < 2); assert(nz < 2);
_v[0] = size_t(vcg::tri::Index(m, pe->V(nz)));; _v[0] = GLuint(vcg::tri::Index(m, pe->V(nz)));;
_v[1] = size_t(vcg::tri::Index(m, pe->V((nz + 1) % 2))); _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) assert(_v[0] != _v[1]); // The face pointed by 'f' is Degenerate (two coincident vertexes)
if (_v[0] > _v[1]) if (_v[0] > _v[1])

View File

@ -226,7 +226,7 @@ public:
//err = glGetError(); //err = glGetError();
std::vector<FacePointer> result; std::vector<FacePointer> result;
PickFace(x,y,m,result,width,height); PickFace(x,y,m,result,width,height);
ScalarType LocalEpsilon(0.001); ScalarType LocalEpsilon(ScalarType(0.001));
for(size_t i =0;i<result.size();++i) for(size_t i =0;i<result.size();++i)
{ {
CoordType p = glProject(M,vp,CoordType::Construct(Barycenter(*(result[i])))) ; CoordType p = glProject(M,vp,CoordType::Construct(Barycenter(*(result[i])))) ;

View File

@ -139,7 +139,7 @@ void Rubberband::Render(QGLWidget* gla)
assert(!glGetError()); assert(!glGetError());
} }
void Rubberband::RenderLine(QGLWidget* gla, Point3f AA, Point3f BB) void Rubberband::RenderLine(QGLWidget* /*gla*/, Point3f AA, Point3f BB)
{ {
// Drawing of the line from AA to BB // Drawing of the line from AA to BB
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT); glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);

View File

@ -234,7 +234,7 @@ namespace io {
if(AddDuplexVertexCoord(ListOfDuplexVert,Key(i,t))) if(AddDuplexVertexCoord(ListOfDuplexVert,Key(i,t)))
{ {
VectorOfVertexType.push_back((*(*fi).V(k))); VectorOfVertexType.push_back((*(*fi).V(k)));
ListOfDuplexVert[Key(i,t)] = VectorOfVertexType.size()-1; ListOfDuplexVert[Key(i,t)] = int(VectorOfVertexType.size()-1);
count++; count++;
} }
} }

View File

@ -96,7 +96,6 @@ namespace vcg {
static int Save(SaveMeshType &m, const char * filename, bool binary, PlyInfo &pi, CallBackPos *cb=0) // V1.0 static int Save(SaveMeshType &m, const char * filename, bool binary, PlyInfo &pi, CallBackPos *cb=0) // V1.0
{ {
FILE * fpout; FILE * fpout;
int i;
const char * hbin = "binary_little_endian"; const char * hbin = "binary_little_endian";
const char * hasc = "ascii"; const char * hasc = "ascii";
const char * h; const char * h;
@ -106,7 +105,7 @@ namespace vcg {
const int DGTVQ = vcg::tri::io::Precision<typename VertexType::QualityType>::digits(); const int DGTVQ = vcg::tri::io::Precision<typename VertexType::QualityType>::digits();
const int DGTVR = vcg::tri::io::Precision<typename VertexType::RadiusType>::digits(); const int DGTVR = vcg::tri::io::Precision<typename VertexType::RadiusType>::digits();
const int DGTFQ = vcg::tri::io::Precision<typename FaceType::QualityType>::digits(); const int DGTFQ = vcg::tri::io::Precision<typename FaceType::QualityType>::digits();
bool multit = false; bool saveTexIndexFlag = false;
if(binary) h=hbin; if(binary) h=hbin;
else h=hasc; else h=hasc;
@ -127,10 +126,10 @@ namespace vcg {
{ {
const char * TFILE = "TextureFile"; const char * TFILE = "TextureFile";
for(i=0; i < static_cast<int>(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()) ); 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)) if((pi.mask & Mask::IOM_CAMERA))
@ -211,8 +210,8 @@ namespace vcg {
"property float texture_v\n" "property float texture_v\n"
); );
} }
for(i=0;i<pi.vdn;i++) for(size_t i=0;i<pi.VertDescriptorVec.size();i++)
fprintf(fpout,"property %s %s\n",pi.VertexData[i].stotypename(),pi.VertexData[i].propname); fprintf(fpout,"property %s %s\n",pi.VertDescriptorVec[i].stotypename(),pi.VertDescriptorVec[i].propname);
fprintf(fpout, fprintf(fpout,
"element face %d\n" "element face %d\n"
@ -226,14 +225,22 @@ namespace vcg {
"property int flags\n" "property int flags\n"
); );
} }
if( (HasPerWedgeTexCoord(m) || HasPerVertexTexCoord(m) ) && pi.mask & Mask::IOM_WEDGTEXCOORD ) // Note that you can save VT as WT if you really want it... if( (HasPerWedgeTexCoord(m) && pi.mask & Mask::IOM_WEDGTEXCOORD ) ||
(HasPerVertexTexCoord(m) && (!HasPerWedgeTexCoord(m)) && pi.mask & Mask::IOM_WEDGTEXCOORD ) ) // Note that you can save VT as WT if you really really want it...
{ {
fprintf(fpout, fprintf(fpout,
"property list uchar float texcoord\n" "property list uchar float texcoord\n"
); );
}
if(multit) // The texture index information has to be saved for each face (if necessary) both for PerVert and PerWedg
if( saveTexIndexFlag &&
( ( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) ) ||
( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) ) ||
( HasPerVertexTexCoord(m) && (!HasPerWedgeTexCoord(m)) && (pi.mask & Mask::IOM_WEDGTEXCOORD) )
)
)
{
fprintf(fpout, fprintf(fpout,
"property int texnumber\n" "property int texnumber\n"
); );
@ -262,8 +269,8 @@ namespace vcg {
fprintf(fpout,"property %s quality\n",fqtp); fprintf(fpout,"property %s quality\n",fqtp);
} }
for(i=0;i<pi.fdn;i++) for(size_t i=0;i<pi.FaceDescriptorVec.size();i++)
fprintf(fpout,"property %s %s\n",pi.FaceData[i].stotypename(),pi.FaceData[i].propname); fprintf(fpout,"property %s %s\n",pi.FaceDescriptorVec[i].stotypename(),pi.FaceDescriptorVec[i].propname);
// Saving of edges is enabled if requested // Saving of edges is enabled if requested
if( m.en>0 && (pi.mask & Mask::IOM_EDGEINDEX) ) if( m.en>0 && (pi.mask & Mask::IOM_EDGEINDEX) )
fprintf(fpout, fprintf(fpout,
@ -344,7 +351,59 @@ namespace vcg {
VertexPointer vp; VertexPointer vp;
VertexIterator vi; VertexIterator vi;
SimpleTempData<typename SaveMeshType::VertContainer,int> indices(m.vert); SimpleTempData<typename SaveMeshType::VertContainer,int> indices(m.vert);
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<float > > thfv(pi.VertDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<double> > thdv(pi.VertDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<int > > thiv(pi.VertDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<short > > thsv(pi.VertDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<char > > thcv(pi.VertDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerVertexAttributeHandle<unsigned char> > thuv(pi.VertDescriptorVec.size());
for(size_t i=0;i<pi.VertDescriptorVec.size();i++)
{
if(!pi.VertAttrNameVec.empty() && !pi.VertAttrNameVec[i].empty())
{ // trying to use named attribute to retrieve the value to store
assert(vcg::tri::HasPerVertexAttribute(m,pi.VertAttrNameVec[i]));
switch (pi.VertDescriptorVec[i].stotype1)
{
case ply::T_FLOAT : thfv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<float>(m,pi.VertAttrNameVec[i]); break;
case ply::T_DOUBLE : thdv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<double>(m,pi.VertAttrNameVec[i]); break;
case ply::T_INT : thiv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<int >(m,pi.VertAttrNameVec[i]); break;
case ply::T_SHORT : thsv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<short >(m,pi.VertAttrNameVec[i]); break;
case ply::T_CHAR : thcv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<char>(m,pi.VertAttrNameVec[i]); break;
case ply::T_UCHAR : thuv[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerVertexAttribute<unsigned char>(m,pi.VertAttrNameVec[i]); break;
default : assert(0);
}
}
}
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<float > > thff(pi.FaceDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<double> > thdf(pi.FaceDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<int > > thif(pi.FaceDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<short > > thsf(pi.FaceDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<char > > thcf(pi.FaceDescriptorVec.size());
std::vector<typename SaveMeshType:: template PerFaceAttributeHandle<unsigned char> > thuf(pi.FaceDescriptorVec.size());
for(size_t i=0;i<pi.FaceDescriptorVec.size();i++)
{
if(!pi.FaceAttrNameVec.empty() && !pi.FaceAttrNameVec[i].empty())
{ // trying to use named attribute to retrieve the value to store
assert(vcg::tri::HasPerFaceAttribute(m,pi.FaceAttrNameVec[i]));
switch (pi.FaceDescriptorVec[i].stotype1)
{
case ply::T_FLOAT : thff[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<float>(m,pi.FaceAttrNameVec[i]); break;
case ply::T_DOUBLE : thdf[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<double>(m,pi.FaceAttrNameVec[i]); break;
case ply::T_INT : thif[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<int >(m,pi.FaceAttrNameVec[i]); break;
case ply::T_SHORT : thsf[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<short >(m,pi.FaceAttrNameVec[i]); break;
case ply::T_CHAR : thcf[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<char>(m,pi.FaceAttrNameVec[i]); break;
case ply::T_UCHAR : thuf[i] = vcg::tri::Allocator<SaveMeshType>::template FindPerFaceAttribute<unsigned char>(m,pi.FaceAttrNameVec[i]); break;
default : assert(0);
}
}
}
for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi){ for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi){
vp=&(*vi); vp=&(*vi);
indices[vi] = j; indices[vi] = j;
@ -381,22 +440,39 @@ namespace vcg {
if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) ) if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) )
{ {
t = float(vp->T().u()); fwrite(&t,sizeof(float),1,fpout); t = ScalarType(vp->T().u()); fwrite(&t,sizeof(ScalarType),1,fpout);
t = float(vp->T().v()); fwrite(&t,sizeof(float),1,fpout); t = ScalarType(vp->T().v()); fwrite(&t,sizeof(ScalarType),1,fpout);
} }
for(i=0;i<pi.vdn;i++) for(size_t i=0;i<pi.VertDescriptorVec.size();i++)
{ {
double td(0); float tf(0);int ti;short ts; char tc; unsigned char tuc; double td(0); float tf(0);int ti;short ts; char tc; unsigned char tu;
switch (pi.VertexData[i].stotype1) if(!pi.VertAttrNameVec.empty() && !pi.VertAttrNameVec[i].empty())
{ // trying to use named attribute to retrieve the value to store
assert(vcg::tri::HasPerVertexAttribute(m,pi.VertAttrNameVec[i]));
switch (pi.VertDescriptorVec[i].stotype1)
{
case ply::T_FLOAT : tf=thfv[i][vp]; fwrite(&tf, sizeof(float),1,fpout); break;
case ply::T_DOUBLE : td=thdv[i][vp]; fwrite(&td, sizeof(double),1,fpout); break;
case ply::T_INT : ti=thiv[i][vp]; fwrite(&ti, sizeof(int),1,fpout); break;
case ply::T_SHORT : ts=thsv[i][vp]; fwrite(&ts, sizeof(short),1,fpout); break;
case ply::T_CHAR : tc=thcv[i][vp]; fwrite(&tc, sizeof(char),1,fpout); break;
case ply::T_UCHAR : tu=thuv[i][vp]; fwrite(&tu,sizeof(unsigned char),1,fpout); break;
default : assert(0);
}
}
else
{ {
case ply::T_FLOAT : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, tf ); fwrite(&tf, sizeof(float),1,fpout); break; switch (pi.VertDescriptorVec[i].stotype1)
case ply::T_DOUBLE : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, td ); fwrite(&td, sizeof(double),1,fpout); break; {
case ply::T_INT : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, ti ); fwrite(&ti, sizeof(int),1,fpout); break; case ply::T_FLOAT : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, tf ); fwrite(&tf, sizeof(float),1,fpout); break;
case ply::T_SHORT : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, ts ); fwrite(&ts, sizeof(short),1,fpout); break; case ply::T_DOUBLE : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, td ); fwrite(&td, sizeof(double),1,fpout); break;
case ply::T_CHAR : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, tc ); fwrite(&tc, sizeof(char),1,fpout); break; case ply::T_INT : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, ti ); fwrite(&ti, sizeof(int),1,fpout); break;
case ply::T_UCHAR : PlyConv(pi.VertexData[i].memtype1, ((char *)vp)+pi.VertexData[i].offset1, tuc); fwrite(&tuc,sizeof(unsigned char),1,fpout); break; case ply::T_SHORT : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, ts ); fwrite(&ts, sizeof(short),1,fpout); break;
default : assert(0); case ply::T_CHAR : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, tc ); fwrite(&tc, sizeof(char),1,fpout); break;
case ply::T_UCHAR : PlyConv(pi.VertDescriptorVec[i].memtype1, ((char *)vp)+pi.VertDescriptorVec[i].offset1, tu ); fwrite(&tu,sizeof(unsigned char),1,fpout); break;
default : assert(0);
}
} }
} }
} }
@ -422,19 +498,35 @@ namespace vcg {
if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) ) if( HasPerVertexTexCoord(m) && (pi.mask & Mask::IOM_VERTTEXCOORD) )
fprintf(fpout,"%f %f",vp->T().u(),vp->T().v()); fprintf(fpout,"%f %f",vp->T().u(),vp->T().v());
for(i=0;i<pi.vdn;i++) for(size_t i=0;i<pi.VertDescriptorVec.size();i++)
{ {
float tf(0); double td(0); float tf(0); double td(0); int ti;
int ti; if(!pi.VertAttrNameVec.empty() && !pi.VertAttrNameVec[i].empty())
switch (pi.VertexData[i].memtype1) { // trying to use named attribute to retrieve the value to store
assert(vcg::tri::HasPerVertexAttribute(m,pi.VertAttrNameVec[i]));
switch (pi.VertDescriptorVec[i].stotype1)
{
case ply::T_FLOAT : tf=thfv[i][vp]; fprintf(fpout,"%f ",tf); break;
case ply::T_DOUBLE : td=thdv[i][vp]; fprintf(fpout,"%lf ",td); break;
case ply::T_INT : ti=thiv[i][vp]; fprintf(fpout,"%i ",ti); break;
case ply::T_SHORT : ti=thsv[i][vp]; fprintf(fpout,"%i ",ti); break;
case ply::T_CHAR : ti=thcv[i][vp]; fprintf(fpout,"%i ",ti); break;
case ply::T_UCHAR : ti=thuv[i][vp]; fprintf(fpout,"%i ",ti); break;
default : assert(0);
}
}
else
{ {
case ply::T_FLOAT : tf=*( (float *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%f ",tf); break; switch (pi.VertDescriptorVec[i].memtype1)
case ply::T_DOUBLE : td=*( (double *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%f ",tf); break; {
case ply::T_INT : ti=*( (int *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_FLOAT : tf=*( (float *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%f ",tf); break;
case ply::T_SHORT : ti=*( (short *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_DOUBLE : td=*( (double *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%f ",tf); break;
case ply::T_CHAR : ti=*( (char *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_INT : ti=*( (int *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
case ply::T_UCHAR : ti=*( (unsigned char *) (((char *)vp)+pi.VertexData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_SHORT : ti=*( (short *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
default : assert(0); case ply::T_CHAR : ti=*( (char *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
case ply::T_UCHAR : ti=*( (unsigned char *) (((char *)vp)+pi.VertDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
default : assert(0);
}
} }
} }
@ -447,9 +539,9 @@ namespace vcg {
// this assert triggers when the vn != number of vertexes in vert that are not deleted. // this assert triggers when the vn != number of vertexes in vert that are not deleted.
assert(j==m.vn); assert(j==m.vn);
char c = 3; unsigned char b3char = 3;
unsigned char b9 = 9; unsigned char b9char = 9;
unsigned char b6 = 6; unsigned char b6char = 6;
FacePointer fp; FacePointer fp;
int vv[3]; int vv[3];
FaceIterator fi; FaceIterator fi;
@ -468,15 +560,15 @@ namespace vcg {
vv[0]=indices[fp->cV(0)]; vv[0]=indices[fp->cV(0)];
vv[1]=indices[fp->cV(1)]; vv[1]=indices[fp->cV(1)];
vv[2]=indices[fp->cV(2)]; vv[2]=indices[fp->cV(2)];
fwrite(&c,1,1,fpout); fwrite(&b3char,sizeof(char),1,fpout);
fwrite(vv,sizeof(int),3,fpout); fwrite(vv,sizeof(int),3,fpout);
if(HasPerFaceFlags(m)&&( pi.mask & Mask::IOM_FACEFLAGS) ) if(HasPerFaceFlags(m)&&( pi.mask & Mask::IOM_FACEFLAGS) )
fwrite(&(fp->Flags()),sizeof(int),1,fpout); 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]; float t[6];
for(int k=0;k<3;++k) for(int k=0;k<3;++k)
{ {
@ -487,7 +579,7 @@ namespace vcg {
} }
else if( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) ) else if( HasPerWedgeTexCoord(m) && (pi.mask & Mask::IOM_WEDGTEXCOORD) )
{ {
fwrite(&b6,sizeof(char),1,fpout); fwrite(&b6char,sizeof(char),1,fpout);
float t[6]; float t[6];
for(int k=0;k<3;++k) for(int k=0;k<3;++k)
{ {
@ -497,7 +589,7 @@ namespace vcg {
fwrite(t,sizeof(float),6,fpout); fwrite(t,sizeof(float),6,fpout);
} }
if(multit) if(saveTexIndexFlag)
{ {
int t = fp->WT(0).n(); int t = fp->WT(0).n();
fwrite(&t,sizeof(int),1,fpout); fwrite(&t,sizeof(int),1,fpout);
@ -509,7 +601,7 @@ namespace vcg {
if( HasPerWedgeColor(m) && (pi.mask & Mask::IOM_WEDGCOLOR) ) if( HasPerWedgeColor(m) && (pi.mask & Mask::IOM_WEDGCOLOR) )
{ {
fwrite(&b9,sizeof(char),1,fpout); fwrite(&b9char,sizeof(char),1,fpout);
float t[3]; float t[3];
for(int z=0;z<3;++z) for(int z=0;z<3;++z)
{ {
@ -524,17 +616,34 @@ namespace vcg {
fwrite( &(fp->Q()),sizeof(typename FaceType::ScalarType),1,fpout); fwrite( &(fp->Q()),sizeof(typename FaceType::ScalarType),1,fpout);
for(i=0;i<pi.fdn;i++) for(size_t i=0;i<pi.FaceDescriptorVec.size();i++)
{ {
double td(0); float tf(0);int ti;short ts; char tc; unsigned char tuc; double td(0); float tf(0);int ti;short ts; char tc; unsigned char tu;
switch (pi.FaceData[i].stotype1){ if(!pi.FaceAttrNameVec.empty() && !pi.FaceAttrNameVec[i].empty())
case ply::T_FLOAT : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, tf ); fwrite(&tf, sizeof(float),1,fpout); break; { // trying to use named attribute to retrieve the value to store
case ply::T_DOUBLE : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, td ); fwrite(&td, sizeof(double),1,fpout); break; assert(vcg::tri::HasPerFaceAttribute(m,pi.FaceAttrNameVec[i]));
case ply::T_INT : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, ti ); fwrite(&ti, sizeof(int),1,fpout); break; switch (pi.FaceDescriptorVec[i].stotype1)
case ply::T_SHORT : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, ts ); fwrite(&ts, sizeof(short),1,fpout); break; {
case ply::T_CHAR : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, tc ); fwrite(&tc, sizeof(char),1,fpout); break; case ply::T_FLOAT : tf=thff[i][fp]; fwrite(&tf, sizeof(float),1,fpout); break;
case ply::T_UCHAR : PlyConv(pi.FaceData[i].memtype1, ((char *)fp)+pi.FaceData[i].offset1, tuc); fwrite(&tuc,sizeof(unsigned char),1,fpout); break; case ply::T_DOUBLE : td=thdf[i][fp]; fwrite(&td, sizeof(double),1,fpout); break;
default : assert(0); case ply::T_INT : ti=thif[i][fp]; fwrite(&ti, sizeof(int),1,fpout); break;
case ply::T_SHORT : ts=thsf[i][fp]; fwrite(&ts, sizeof(short),1,fpout); break;
case ply::T_CHAR : tc=thcf[i][fp]; fwrite(&tc, sizeof(char),1,fpout); break;
case ply::T_UCHAR : tu=thuf[i][fp]; fwrite(&tu,sizeof(unsigned char),1,fpout); break;
default : assert(0);
}
}
else
{
switch (pi.FaceDescriptorVec[i].stotype1){
case ply::T_FLOAT : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, tf ); fwrite(&tf, sizeof(float),1,fpout); break;
case ply::T_DOUBLE : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, td ); fwrite(&td, sizeof(double),1,fpout); break;
case ply::T_INT : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, ti ); fwrite(&ti, sizeof(int),1,fpout); break;
case ply::T_SHORT : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, ts ); fwrite(&ts, sizeof(short),1,fpout); break;
case ply::T_CHAR : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, tc ); fwrite(&tc, sizeof(char),1,fpout); break;
case ply::T_UCHAR : PlyConv(pi.FaceDescriptorVec[i].memtype1, ((char *)fp)+pi.FaceDescriptorVec[i].offset1, tu ); fwrite(&tu, sizeof(unsigned char),1,fpout); break;
default : assert(0);
}
} }
} }
} }
@ -566,7 +675,7 @@ namespace vcg {
); );
} }
if(multit) if(saveTexIndexFlag)
{ {
fprintf(fpout,"%d ",fp->WT(0).n()); fprintf(fpout,"%d ",fp->WT(0).n());
} }
@ -589,20 +698,36 @@ namespace vcg {
if( HasPerFaceQuality(m) && (pi.mask & Mask::IOM_FACEQUALITY) ) if( HasPerFaceQuality(m) && (pi.mask & Mask::IOM_FACEQUALITY) )
fprintf(fpout,"%.*g ",DGTFQ,fp->Q()); fprintf(fpout,"%.*g ",DGTFQ,fp->Q());
for(i=0;i<pi.fdn;i++) for(size_t i=0;i<pi.FaceDescriptorVec.size();i++)
{ {
float tf(0); double td(0); float tf(0); double td(0); int ti;
int ti; if(!pi.FaceAttrNameVec.empty() && !pi.FaceAttrNameVec[i].empty())
switch (pi.FaceData[i].memtype1) { // trying to use named attribute to retrieve the value to store
assert(vcg::tri::HasPerFaceAttribute(m,pi.FaceAttrNameVec[i]));
switch (pi.FaceDescriptorVec[i].stotype1)
{ {
case ply::T_FLOAT : tf=*( (float *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%g ",tf); break; case ply::T_FLOAT : tf=thff[i][fp]; fprintf(fpout,"%f ",tf); break;
case ply::T_DOUBLE : td=*( (double *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%g ",tf); break; case ply::T_DOUBLE : td=thdf[i][fp]; fprintf(fpout,"%g ",td); break;
case ply::T_INT : ti=*( (int *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_INT : ti=thif[i][fp]; fprintf(fpout,"%i ",ti); break;
case ply::T_SHORT : ti=*( (short *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_SHORT : ti=thsf[i][fp]; fprintf(fpout,"%i ",ti); break;
case ply::T_CHAR : ti=*( (char *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_CHAR : ti=thcf[i][fp]; fprintf(fpout,"%i ",ti); break;
case ply::T_UCHAR : ti=*( (unsigned char *) (((char *)fp)+pi.FaceData[i].offset1)); fprintf(fpout,"%i ",ti); break; case ply::T_UCHAR : ti=thuf[i][fp]; fprintf(fpout,"%i ",ti); break;
default : assert(0); default : assert(0);
} }
}
else
{
switch (pi.FaceDescriptorVec[i].memtype1)
{
case ply::T_FLOAT : tf=*( (float *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%g ",tf); break;
case ply::T_DOUBLE : td=*( (double *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%g ",tf); break;
case ply::T_INT : ti=*( (int *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
case ply::T_SHORT : ti=*( (short *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
case ply::T_CHAR : ti=*( (char *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
case ply::T_UCHAR : ti=*( (unsigned char *) (((char *)fp)+pi.FaceDescriptorVec[i].offset1)); fprintf(fpout,"%i ",ti); break;
default : assert(0);
}
}
} }
fprintf(fpout,"\n"); fprintf(fpout,"\n");

View File

@ -65,7 +65,7 @@ namespace vcg {
typedef typename SaveMeshType::FaceIterator FaceIterator; typedef typename SaveMeshType::FaceIterator FaceIterator;
///Standard call for saving a mesh ///Standard call for saving a mesh
static int Save(SaveMeshType &m, const char * filename, const int &mask, CallBackPos */*cb=0*/) static int Save(SaveMeshType &m, const char * filename, const int &mask, CallBackPos * /*cb=0*/)
{ {
FILE *fp; FILE *fp;
fp = fopen(filename,"wb"); fp = fopen(filename,"wb");

View File

@ -87,7 +87,7 @@ static const char* ErrorMsg(int error)
}; };
static int Open( OpenMeshType &m, const char * filename, int &loadmask, CallBackPos */*cb*/=0) static int Open( OpenMeshType &m, const char * filename, int &loadmask, CallBackPos * /*cb*/=0)
{ {
CTMcontext context; CTMcontext context;

View File

@ -154,7 +154,7 @@ static int Open( OpenMeshType &m, std::vector<Shot<ScalarType> > & shots,
shots[i].Intrinsics.FocalMm = f/100.0f; 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[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.k[1] = 0.0;//k2;
shots[i].Intrinsics.PixelSizeMm = vcg::Point2<ScalarType>(0.01,0.01); shots[i].Intrinsics.PixelSizeMm = vcg::Point2<ScalarType>(ScalarType(0.01), ScalarType(0.01));
QImageReader sizeImg(QString::fromStdString(image_filenames[i])); QImageReader sizeImg(QString::fromStdString(image_filenames[i]));
QSize size=sizeImg.size(); QSize size=sizeImg.size();
shots[i].Intrinsics.ViewportPx = vcg::Point2i(size.width(),size.height()); shots[i].Intrinsics.ViewportPx = vcg::Point2i(size.width(),size.height());

View File

@ -615,6 +615,15 @@ namespace vcg {
} }
else if ((header.compare("usemtl")==0) && (tokens.size() > 1)) // material usage 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; std::string materialName;
if (tokens.size() == 2) if (tokens.size() == 2)
materialName = tokens[1]; //play it safe materialName = tokens[1]; //play it safe
@ -887,6 +896,7 @@ namespace vcg {
oi.numNormals=0; oi.numNormals=0;
int lineCount=0; int lineCount=0;
int totRead=0; int totRead=0;
bool firstV = true;
std::string line; std::string line;
while (!stream.eof()) while (!stream.eof())
{ {
@ -899,11 +909,20 @@ namespace vcg {
{ {
if(line[0]=='v') if(line[0]=='v')
{ {
if(line[1]==' ') if ((line[1] == ' ') || (line[1] == '\t'))
{ {
oi.numVertices++; oi.numVertices++;
if(line.size()>=7) if (firstV)
bHasPerVertexColor = true; {
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]=='t') oi.numTexCoords++;
if(line[1]=='n') { if(line[1]=='n') {
@ -930,8 +949,8 @@ namespace vcg {
// Usually if you have tex coords you also have materials // Usually if you have tex coords you also have materials
oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR; oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
} }
if(bHasPerFaceColor) 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(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
if (bHasNormals) { if (bHasNormals) {
if (oi.numNormals == oi.numVertices) if (oi.numNormals == oi.numVertices)
oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;

View File

@ -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}, /* 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}, /* 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}, /* 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}, /* 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}, /* 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}, /* 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}, /* 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}, /* 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 // User defined descriptors
std::vector<PropDescriptor> VPV(pi.vdn); // property descriptor relative al tipo LoadPly_VertexAux std::vector<PropDescriptor> VPV(pi.VertDescriptorVec.size()); // property descriptor relative al tipo LoadPly_VertexAux
std::vector<PropDescriptor> FPV(pi.fdn); // property descriptor relative al tipo LoadPly_FaceAux std::vector<PropDescriptor> FPV(pi.FaceDescriptorVec.size()); // property descriptor relative al tipo LoadPly_FaceAux
if(pi.vdn>0){ if(pi.VertDescriptorVec.size()>0){
// Compute the total size needed to load additional per vertex data. // Compute the total size needed to load additional per vertex data.
size_t totsz=0; size_t totsz=0;
for(int i=0;i<pi.vdn;i++){ for(size_t i=0;i<pi.VertDescriptorVec.size();i++){
VPV[i] = pi.VertexData[i]; VPV[i] = pi.VertDescriptorVec[i];
VPV[i].offset1=offsetof(LoadPly_VertAux<ScalarType>,data)+totsz; VPV[i].offset1=offsetof(LoadPly_VertAux<ScalarType>,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( pf.AddToRead(VPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; }
} }
if(totsz > MAX_USER_DATA) if(totsz > MAX_USER_DATA)
@ -564,12 +564,12 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
return pi.status; return pi.status;
} }
} }
if(pi.fdn>0){ if(pi.FaceDescriptorVec.size()>0){
size_t totsz=0; size_t totsz=0;
for(int i=0;i<pi.fdn;i++){ for(size_t i=0;i<pi.FaceDescriptorVec.size();i++){
FPV[i] = pi.FaceData[i]; FPV[i] = pi.FaceDescriptorVec[i];
FPV[i].offset1=offsetof(LoadPly_FaceAux,data)+totsz; FPV[i].offset1=offsetof(LoadPly_FaceAux,data)+totsz;
totsz+=pi.FaceData[i].memtypesize(); totsz+=pi.FaceDescriptorVec[i].memtypesize();
if( pf.AddToRead(FPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; } if( pf.AddToRead(FPV[i])==-1 ) { pi.status = pf.GetError(); return pi.status; }
} }
if(totsz > MAX_USER_DATA) if(totsz > MAX_USER_DATA)
@ -583,7 +583,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
/* Main Reading Loop */ /* Main Reading Loop */
/**************************************************************/ /**************************************************************/
m.Clear(); m.Clear();
for(int i=0;i<int(pf.elements.size());i++) for(size_t i=0;i<pf.elements.size();i++)
{ {
int n = pf.ElemNumber(i); int n = pf.ElemNumber(i);
@ -695,8 +695,8 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
(*vi).R() = va.radius; (*vi).R() = va.radius;
for(int k=0;k<pi.vdn;k++) for(size_t k=0;k<pi.VertDescriptorVec.size();k++)
memcpy((char *)(&*vi) + pi.VertexData[k].offset1, memcpy((char *)(&*vi) + pi.VertDescriptorVec[k].offset1,
(char *)(&va) + VPV[k].offset1, (char *)(&va) + VPV[k].offset1,
VPV[k].memtypesize()); VPV[k].memtypesize());
++vi; ++vi;
@ -756,7 +756,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
} }
} }
if(HasPolyInfo(m)) (*fi).Alloc(3); if(HasPolyInfo(m)) (*fi).Alloc(fa.size);
if(HasPerFaceFlags(m) &&( pi.mask & Mask::IOM_FACEFLAGS) ) if(HasPerFaceFlags(m) &&( pi.mask & Mask::IOM_FACEFLAGS) )
{ {
@ -805,6 +805,22 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
(*fi).C()[2] = (unsigned char)((fa.colors[0*3+2]*255+fa.colors[1*3+2]*255+fa.colors[2*3+2]*255)/3.0f); (*fi).C()[2] = (unsigned char)((fa.colors[0*3+2]*255+fa.colors[1*3+2]*255+fa.colors[2*3+2]*255)/3.0f);
} }
} }
if (HasPolyInfo(m))
{
for(k=0; k<fa.size; ++k)
{
if( fa.v[k]<0 || fa.v[k]>=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' /// Now the temporary struct 'fa' is ready to be copied into the real face '*fi'
/// This loop /// This loop
for(k=0;k<3;++k) 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 // tag faux vertices of first face
if (fa.size>3) fi->SetF(2); if (fa.size>3) fi->SetF(2);
for(k=0;k<pi.fdn;k++) for(size_t k=0;k<pi.FaceDescriptorVec.size();k++)
memcpy((char *)(&(*fi)) + pi.FaceData[k].offset1, memcpy((char *)(&(*fi)) + pi.FaceDescriptorVec[k].offset1,
(char *)(&fa) + FPV[k].offset1, (char *)(&fa) + FPV[k].offset1,
FPV[k].memtypesize()); FPV[k].memtypesize());
@ -861,8 +877,8 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
fi->SetF(0); fi->SetF(0);
if(qq<(fa.size-4)) fi->SetF(2); if(qq<(fa.size-4)) fi->SetF(2);
for(k=0;k<pi.fdn;k++) for(size_t k=0;k<pi.FaceDescriptorVec.size();k++)
memcpy((char *)(&(*fi)) + pi.FaceData[k].offset1, memcpy((char *)(&(*fi)) + pi.FaceDescriptorVec[k].offset1,
(char *)(&fa) + FPV[k].offset1, FPV[k].memtypesize()); (char *)(&fa) + FPV[k].offset1, FPV[k].memtypesize());
++fi; ++fi;
} }
@ -911,7 +927,7 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
//qDebug("Starting Reading of Range Grid"); //qDebug("Starting Reading of Range Grid");
if(RangeGridCols==0) // not initialized. if(RangeGridCols==0) // not initialized.
{ {
for(int co=0;co<int(pf.comments.size());++co) for(size_t co=0;co< pf.comments.size();++co)
{ {
std::string num_cols = "num_cols"; std::string num_cols = "num_cols";
std::string num_rows = "num_rows"; std::string num_rows = "num_rows";
@ -974,20 +990,20 @@ static int Open( OpenMeshType &m, const char * filename, PlyInfo &pi )
m.textures.clear(); m.textures.clear();
m.normalmaps.clear(); m.normalmaps.clear();
for(int co=0;co<int(pf.comments.size());++co) for(size_t co=0;co<pf.comments.size();++co)
{ {
std::string TFILE = "TextureFile"; std::string TFILE = "TextureFile";
std::string NFILE = "TextureNormalFile"; std::string NFILE = "TextureNormalFile";
std::string &c = pf.comments[co]; std::string &c = pf.comments[co];
// char buf[256]; // char buf[256];
std::string bufstr,bufclean; std::string bufstr,bufclean;
int i,n; int n;
if( TFILE == c.substr(0,TFILE.length()) ) if( TFILE == c.substr(0,TFILE.length()) )
{ {
bufstr = c.substr(TFILE.length()+1); bufstr = c.substr(TFILE.length()+1);
n = static_cast<int>(bufstr.length()); n = static_cast<int>(bufstr.length());
for(i=0;i<n;i++) for(int i=0;i<n;i++)
if( bufstr[i]!=' ' && bufstr[i]!='\t' && bufstr[i]>32 && bufstr[i]<125 ) bufclean.push_back(bufstr[i]); if( bufstr[i]!=' ' && bufstr[i]!='\t' && bufstr[i]>32 && bufstr[i]<125 ) bufclean.push_back(bufstr[i]);
char buf2[255]; char buf2[255];
@ -1036,8 +1052,7 @@ int LoadCamera(const char * filename)
bool found = true; bool found = true;
int i; for(int i=0;i<23;++i)
for(i=0;i<23;++i)
{ {
if( pf.AddToRead(CameraDesc(i))==-1 ) if( pf.AddToRead(CameraDesc(i))==-1 )
{ {
@ -1049,7 +1064,7 @@ int LoadCamera(const char * filename)
if(!found) if(!found)
return this->pi.status; return this->pi.status;
for(i=0;i<int(pf.elements.size());i++) for(size_t i=0;i<pf.elements.size();i++)
{ {
int n = pf.ElemNumber(i); int n = pf.ElemNumber(i);

View File

@ -24,6 +24,7 @@
#ifndef __VCGLIB_IMPORT_STL #ifndef __VCGLIB_IMPORT_STL
#define __VCGLIB_IMPORT_STL #define __VCGLIB_IMPORT_STL
#include <stdio.h> #include <stdio.h>
#include<algorithm>
#include <wrap/io_trimesh/io_mask.h> #include <wrap/io_trimesh/io_mask.h>
namespace vcg { namespace vcg {
@ -60,10 +61,11 @@ public:
}; };
enum STLError { enum STLError {
E_NOERROR, // 0 E_NOERROR, // 0
// Errori di open E_CANTOPEN, // 1
E_CANTOPEN, // 1 E_UNESPECTEDEOF, // 2
E_UNESPECTEDEOF // 2 E_MALFORMED, // 3
E_LAST
}; };
static const char *ErrorMsg(int error) static const char *ErrorMsg(int error)
@ -72,20 +74,23 @@ static const char *ErrorMsg(int error)
{ {
"No errors", "No errors",
"Can't open file", "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]; else return stl_error_msg[error];
}; }
static bool LoadMask(const char * filename, int &mask) static bool LoadMask(const char * filename, int &mask)
{ {
bool magicMode; bool magicMode,colored;
mask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; mask = Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX;
if(IsSTLColored(filename,magicMode)) if(!IsSTLColored(filename, colored, magicMode))
mask |= Mask::IOM_FACECOLOR; return false;
return true;
if(colored) mask |= Mask::IOM_FACECOLOR;
return true;
} }
/* Try to guess if a stl has color /* 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 * - It has to be binary
* - The per face attribute should be not zero * - 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; return false;
if(binaryFlag==false)
return true;
FILE *fp = fopen(filename, "rb"); FILE *fp = fopen(filename, "rb");
char buf[STL_LABEL_SIZE+1]; char buf[STL_LABEL_SIZE+1];
fread(buf,sizeof(char),STL_LABEL_SIZE,fp); fread(buf,sizeof(char),STL_LABEL_SIZE,fp);
@ -123,39 +136,54 @@ static bool IsSTLColored(const char * filename, bool &magicsMode)
if(attr!=0) if(attr!=0)
{ {
if(Color4b::FromUnsignedR5G5B5(attr) != Color4b(Color4b::White)) 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"); FILE *fp = fopen(filename, "r");
/* Find size of file */ /* Find size of file */
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
int file_size = ftell(fp); long file_size = ftell(fp);
int facenum; unsigned int facenum;
/* Check for binary or ASCII file */ /* Check for binary or ASCII file */
fseek(fp, STL_LABEL_SIZE, SEEK_SET); 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 ; int expected_file_size=STL_LABEL_SIZE + 4 + (sizeof(short)+sizeof(STLFacet) )*facenum ;
if(file_size == expected_file_size) binary = true; if(file_size == expected_file_size)
unsigned char tmpbuf[128]; {
fread(tmpbuf,sizeof(tmpbuf),1,fp); binaryFlag = true;
for(unsigned int i = 0; i < sizeof(tmpbuf); i++) 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) if(tmpbuf[i] > 127)
{ {
binary=true; binaryFlag=true;
if(abs(file_size-expected_file_size) > file_size/20 )
return false; //
break; break;
} }
} }
// Now we know if the stl file is ascii or binary. // Now we know if the stl file is ascii or binary.
fclose(fp); return true;
return binary;
} }
static int Open( OpenMeshType &m, const char * filename, int &loadMask, CallBackPos *cb=0) 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; return E_CANTOPEN;
fclose(fp); fclose(fp);
loadMask |= Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX; loadMask |= Mask::IOM_VERTCOORD | Mask::IOM_FACEINDEX;
bool binaryFlag;
if(IsSTLBinary(filename)) return OpenBinary(m,filename,loadMask,cb); if(!IsSTLBinary(filename,binaryFlag))
return E_MALFORMED;
if(binaryFlag) return OpenBinary(m,filename,loadMask,cb);
else return OpenAscii(m,filename,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; return E_CANTOPEN;
} }
bool magicsMode; bool magicsMode,coloredFlag;
if(!IsSTLColored(filename,magicsMode)) if(!IsSTLColored(filename,coloredFlag, magicsMode))
return E_MALFORMED;
if(!coloredFlag)
loadMask = loadMask & (~Mask::IOM_FACECOLOR); loadMask = loadMask & (~Mask::IOM_FACECOLOR);
int facenum; int facenum;

View File

@ -52,6 +52,8 @@ namespace vcg {
namespace tri { namespace tri {
namespace io { namespace io {
/** Additional data needed or useful for parsing a ply mesh. /** Additional data needed or useful for parsing a ply mesh.
This class can be passed to the ImporterPLY::Open() function for This class can be passed to the ImporterPLY::Open() function for
@ -63,14 +65,66 @@ class PlyInfo
{ {
public: public:
typedef ::vcg::ply::PropDescriptor PropDescriptor ; 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<PropDescriptor> *elemDescVec[2]={&(this->VertDescriptorVec), &(this->FaceDescriptorVec)};
static std::vector<std::string > *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<class MeshType>
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 <vcg::Point3f>
ht = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute <vcg::Point3f> (m,attrName);
typename MeshType::template PerVertexAttributeHandle <float> htt[3];
for(int i=0;i<3;++i)
{
htt[i] = vcg::tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (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() PlyInfo()
{ {
status=0; status=0;
mask=0; mask=0;
cb=0; cb=0;
vdn=fdn=0;
VertexData=FaceData=0;
} }
/// Store the error codes enconutered when parsing a ply /// Store the error codes enconutered when parsing a ply
int status; 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...) // it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...)
CallBackPos *cb; 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 /// The additional vertex descriptor that a user can specify to load additional per-vertex non-standard data stored in a ply
PropDescriptor *VertexData; std::vector<PropDescriptor> VertDescriptorVec;
/// the number of per-face descriptor (usually 0) /// AttributeName is an array, externally allocated, containing the names of the attributes to be saved (loaded).
int fdn; /// 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<std::string> VertAttrNameVec;
/// The additional vertex descriptor that a user can specify to load additional per-face non-standard data stored in a ply /// 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<PropDescriptor> FaceDescriptorVec;
std::vector<std::string> FaceAttrNameVec;
/// a string containing the current ply header. Useful for showing it to the user. /// a string containing the current ply header. Useful for showing it to the user.
std::string header; std::string header;