From 5405d435ba520ca14ab4174034aa6bd8def4c2f3 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni Date: Thu, 29 Aug 2024 08:50:59 +0200 Subject: [PATCH] Heavy Restructuring of the Ply Import/Export for handling attributes --- .../trimesh_attribute_saving.cpp | 51 +- wrap/io_trimesh/export_ply.h | 158 ++--- wrap/io_trimesh/import_ply.h | 74 ++- wrap/io_trimesh/io_ply.h | 561 ++++++++++++------ 4 files changed, 534 insertions(+), 310 deletions(-) diff --git a/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp index 400a9da44..f0a46cb5e 100644 --- a/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp +++ b/apps/sample/trimesh_attribute_saving/trimesh_attribute_saving.cpp @@ -31,6 +31,7 @@ See the page '\ref attributes' for more details. #include #include +#include #include class MyEdge; class MyFace; @@ -57,7 +58,7 @@ int main() // add a per-face attribute with type float named "FaceArea" MyMesh::PerFaceAttributeHandle hff = vcg::tri::Allocator:: GetPerFaceAttribute (m,std::string("FaceArea")); - //! [filling the attribute] + //! [filling the attributes] vcg::tri::Allocator::ClearPerVertexAttribute(m,hvf, float(M_PI*2)); vcg::tri::Allocator::ClearPerVertexAttribute(m,hv3f, vcg::Point3f(0,0,0)); @@ -69,10 +70,52 @@ int main() } }); - //! [Saving 3 attributes in ply, one of the 3 disguised as quality] + //! [Saving 3 attributes in ply, one of the 3 is saved as the standard ply property quality] vcg::tri::io::PlyInfo pi; - pi.AddPerVertexFloatAttribute("GaussianCurvature","quality"); + + // // The first attribute is a per-vertex float attribute named "GaussianCurvature" and is saved as quality even if this mesh has not quality + // pi.AddPerVertexFloatAttribute("GaussianCurvature","quality"); + pi.AddPerVertexFloatAttribute("GaussianCurvature"); pi.AddPerFaceFloatAttribute("FaceArea"); pi.AddPerVertexPoint3fAttribute(m,"InvertedNormal"); - vcg::tri::io::ExporterPLY::Save(m,"MeshWithCurvature.ply",false,pi); + vcg::tri::io::ExporterPLY::Save(m,"MeshWithCurvature.ply",false,pi); + + printf("Face 0 has area %f\n",hff[&m.face[0]]); + printf("Vertex 1 has GaussianCurvature %f\n",hvf[1]); + + /******************************************************************************/ + + //! Now Trying to reload it in a new mesh + MyMesh mi; + //! use an attribute with a slightly different name for testing + MyMesh::PerFaceAttributeHandle + ihff = vcg::tri::Allocator:: GetPerFaceAttribute (mi,std::string("MyFaceArea")); + + MyMesh::PerVertexAttributeHandle + ihvf = vcg::tri::Allocator:: GetPerVertexAttribute (mi,std::string("GaussianCurvature")); + + vcg::tri::io::PlyInfo piOpen0; + // Use load Mask to get info about the file + int mask=0; + vcg::tri::io::ImporterPLY::LoadMask("MeshWithCurvature.ply",mask,piOpen0); + + + + vcg::tri::io::PlyInfo piOpen; + piOpen.AddPerFaceFloatAttribute("MyFaceArea", "FaceArea"); + piOpen.AddPerVertexFloatAttribute("GaussianCurvature"); + + + int ret = vcg::tri::io::ImporterPLY::Open(mi,"MeshWithCurvature.ply",piOpen); + if(ret!=0) + { + printf("Unable to open MeshWithCurvature.ply for '%s'\n",vcg::tri::io::ImporterPLY::ErrorMsg(ret)); + return -1; + } + + printf("Loaded %i vertices and %i faces\n",mi.VN(),mi.FN()); + printf("Face 0 has area %f\n",ihff[&mi.face[0]]); + printf("Vertex 1 has GaussianCurvature %f\n",ihvf[1]); + + } diff --git a/wrap/io_trimesh/export_ply.h b/wrap/io_trimesh/export_ply.h index 8db1c86c9..2d95716fb 100644 --- a/wrap/io_trimesh/export_ply.h +++ b/wrap/io_trimesh/export_ply.h @@ -29,7 +29,8 @@ #ifndef __VCGLIB_EXPORT_PLY #define __VCGLIB_EXPORT_PLY -//#include +#include +#include #include #include #include @@ -384,79 +385,8 @@ class ExporterPLY 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()); - std::vector > thp3fv(pi.VertDescriptorVec.size()); - std::vector > thp3dv(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); - } - } - else { - switch (pi.VertDescriptorVec[i].stotype1) - { - case ply::T_FLOAT : thp3fv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; - case ply::T_DOUBLE : thp3dv[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()); - std::vector > thp3ff(pi.FaceDescriptorVec.size()); - std::vector > thp3df(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); - } - } - else { - switch (pi.FaceDescriptorVec[i].stotype1) - { - case ply::T_FLOAT : thp3ff[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; - case ply::T_DOUBLE : thp3df[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; - default : assert(0); - } - } - } - } + + PlyAttributeHelper PAH(pi,m); for(j=0,vi=m.vert.begin();vi!=m.vert.end();++vi){ vp=&(*vi); @@ -513,12 +443,12 @@ class ExporterPLY if (!pi.VertDescriptorVec[i].islist){ 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; + case ply::T_FLOAT : tf=PAH.thfv[i][vp]; fwrite(&tf, sizeof(float),1,fpout); break; + case ply::T_DOUBLE : td=PAH.thdv[i][vp]; fwrite(&td, sizeof(double),1,fpout); break; + case ply::T_INT : ti=PAH.thiv[i][vp]; fwrite(&ti, sizeof(int),1,fpout); break; + case ply::T_SHORT : ts=PAH.thsv[i][vp]; fwrite(&ts, sizeof(short),1,fpout); break; + case ply::T_CHAR : tc=PAH.thcv[i][vp]; fwrite(&tc, sizeof(char),1,fpout); break; + case ply::T_UCHAR : tu=PAH.thuv[i][vp]; fwrite(&tu,sizeof(unsigned char),1,fpout); break; default : assert(0); } } @@ -528,16 +458,16 @@ class ExporterPLY { case ply::T_FLOAT : fwrite(&psize, sizeof(unsigned char), 1,fpout); - fwrite(&thp3fv[i][vp][0], sizeof(float), 1,fpout); - fwrite(&thp3fv[i][vp][1], sizeof(float), 1,fpout); - fwrite(&thp3fv[i][vp][2], sizeof(float), 1,fpout); + fwrite(&PAH.thp3fv[i][vp][0], sizeof(float), 1,fpout); + fwrite(&PAH.thp3fv[i][vp][1], sizeof(float), 1,fpout); + fwrite(&PAH.thp3fv[i][vp][2], sizeof(float), 1,fpout); break; //fprintf(fpout,"%d %f %f %f", 3, thp3fv[i][vp][0], thp3fv[i][vp][1], thp3fv[i][vp][2]); break; case ply::T_DOUBLE : fwrite(&psize, sizeof(unsigned char), 1,fpout); - fwrite(&thp3dv[i][vp][0], sizeof(double), 1,fpout); - fwrite(&thp3dv[i][vp][1], sizeof(double), 1,fpout); - fwrite(&thp3dv[i][vp][2], sizeof(double), 1,fpout); + fwrite(&PAH.thp3dv[i][vp][0], sizeof(double), 1,fpout); + fwrite(&PAH.thp3dv[i][vp][1], sizeof(double), 1,fpout); + fwrite(&PAH.thp3dv[i][vp][2], sizeof(double), 1,fpout); break; //fprintf(fpout,"%d %lf %lf %lf", 3, thp3dv[i][vp][0], thp3dv[i][vp][1], thp3dv[i][vp][2]); break; default : assert(0); @@ -590,20 +520,20 @@ class ExporterPLY if (!pi.VertDescriptorVec[i].islist){ 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; + case ply::T_FLOAT : tf=PAH.tchfv[i][vp]; fprintf(fpout,"%f ",tf); break; + case ply::T_DOUBLE : td=PAH.tchdv[i][vp]; fprintf(fpout,"%lf ",td); break; + case ply::T_INT : ti=PAH.tchiv[i][vp]; fprintf(fpout,"%i ",ti); break; + case ply::T_SHORT : ti=PAH.tchsv[i][vp]; fprintf(fpout,"%i ",ti); break; + case ply::T_CHAR : ti=PAH.tchcv[i][vp]; fprintf(fpout,"%i ",ti); break; + case ply::T_UCHAR : ti=PAH.tchuv[i][vp]; fprintf(fpout,"%i ",ti); break; default : assert(0); } } else { //it is a Poin3f or a Point3d attribute. Saving it as a list switch (pi.VertDescriptorVec[i].stotype1) { - case ply::T_FLOAT : fprintf(fpout,"%d %f %f %f", 3, thp3fv[i][vp][0], thp3fv[i][vp][1], thp3fv[i][vp][2]); break; - case ply::T_DOUBLE : fprintf(fpout,"%d %lf %lf %lf", 3, thp3dv[i][vp][0], thp3dv[i][vp][1], thp3dv[i][vp][2]); break; + case ply::T_FLOAT : fprintf(fpout,"%d %f %f %f", 3, PAH.tchp3fv[i][vp][0], PAH.tchp3fv[i][vp][1], PAH.tchp3fv[i][vp][2]); break; + case ply::T_DOUBLE : fprintf(fpout,"%d %lf %lf %lf", 3, PAH.tchp3dv[i][vp][0], PAH.tchp3dv[i][vp][1], PAH.tchp3dv[i][vp][2]); break; default : assert(0); } } @@ -728,12 +658,12 @@ class ExporterPLY if (!pi.FaceDescriptorVec[i].islist){ switch (pi.FaceDescriptorVec[i].stotype1) { - case ply::T_FLOAT : tf=thff[i][fp]; fwrite(&tf, sizeof(float),1,fpout); break; - case ply::T_DOUBLE : td=thdf[i][fp]; fwrite(&td, sizeof(double),1,fpout); break; - 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; + case ply::T_FLOAT : tf=PAH.thff[i][fp]; fwrite(&tf, sizeof(float),1,fpout); break; + case ply::T_DOUBLE : td=PAH.thdf[i][fp]; fwrite(&td, sizeof(double),1,fpout); break; + case ply::T_INT : ti=PAH.thif[i][fp]; fwrite(&ti, sizeof(int),1,fpout); break; + case ply::T_SHORT : ts=PAH.thsf[i][fp]; fwrite(&ts, sizeof(short),1,fpout); break; + case ply::T_CHAR : tc=PAH.thcf[i][fp]; fwrite(&tc, sizeof(char),1,fpout); break; + case ply::T_UCHAR : tu=PAH.thuf[i][fp]; fwrite(&tu,sizeof(unsigned char),1,fpout); break; default : assert(0); } } @@ -743,15 +673,15 @@ class ExporterPLY { case ply::T_FLOAT : fwrite(&psize, sizeof(unsigned char), 1,fpout); - fwrite(&thp3ff[i][fp][0], sizeof(float), 1,fpout); - fwrite(&thp3ff[i][fp][1], sizeof(float), 1,fpout); - fwrite(&thp3ff[i][fp][2], sizeof(float), 1,fpout); + fwrite(&PAH.thp3ff[i][fp][0], sizeof(float), 1,fpout); + fwrite(&PAH.thp3ff[i][fp][1], sizeof(float), 1,fpout); + fwrite(&PAH.thp3ff[i][fp][2], sizeof(float), 1,fpout); break; case ply::T_DOUBLE : fwrite(&psize, sizeof(unsigned char), 1,fpout); - fwrite(&thp3df[i][fp][0], sizeof(double), 1,fpout); - fwrite(&thp3df[i][fp][1], sizeof(double), 1,fpout); - fwrite(&thp3df[i][fp][2], sizeof(double), 1,fpout); + fwrite(&PAH.thp3df[i][fp][0], sizeof(double), 1,fpout); + fwrite(&PAH.thp3df[i][fp][1], sizeof(double), 1,fpout); + fwrite(&PAH.thp3df[i][fp][2], sizeof(double), 1,fpout); break; default : assert(0); } @@ -834,20 +764,20 @@ class ExporterPLY if(!pi.FaceDescriptorVec[i].islist) { switch (pi.FaceDescriptorVec[i].stotype1) { - case ply::T_FLOAT : tf=thff[i][fp]; fprintf(fpout,"%f ",tf); break; - case ply::T_DOUBLE : td=thdf[i][fp]; fprintf(fpout,"%g ",td); break; - case ply::T_INT : ti=thif[i][fp]; fprintf(fpout,"%i ",ti); break; - case ply::T_SHORT : ti=thsf[i][fp]; fprintf(fpout,"%i ",ti); break; - case ply::T_CHAR : ti=thcf[i][fp]; fprintf(fpout,"%i ",ti); break; - case ply::T_UCHAR : ti=thuf[i][fp]; fprintf(fpout,"%i ",ti); break; + case ply::T_FLOAT : tf=PAH.tchff[i][fp]; fprintf(fpout,"%f ",tf); break; + case ply::T_DOUBLE : td=PAH.tchdf[i][fp]; fprintf(fpout,"%g ",td); break; + case ply::T_INT : ti=PAH.tchif[i][fp]; fprintf(fpout,"%i ",ti); break; + case ply::T_SHORT : ti=PAH.tchsf[i][fp]; fprintf(fpout,"%i ",ti); break; + case ply::T_CHAR : ti=PAH.tchcf[i][fp]; fprintf(fpout,"%i ",ti); break; + case ply::T_UCHAR : ti=PAH.tchuf[i][fp]; fprintf(fpout,"%i ",ti); break; default : assert(0); } } else { switch (pi.FaceDescriptorVec[i].stotype1) { - case ply::T_FLOAT : fprintf(fpout,"%d %f %f %f", 3, thp3ff[i][fp][0], thp3ff[i][fp][1], thp3ff[i][fp][2]); break; - case ply::T_DOUBLE : fprintf(fpout,"%d %lf %lf %lf", 3, thp3df[i][fp][0], thp3df[i][fp][1], thp3df[i][fp][2]); break; + case ply::T_FLOAT : fprintf(fpout,"%d %f %f %f", 3, PAH.tchp3ff[i][fp][0], PAH.tchp3ff[i][fp][1], PAH.tchp3ff[i][fp][2]); break; + case ply::T_DOUBLE : fprintf(fpout,"%d %lf %lf %lf", 3, PAH.tchp3df[i][fp][0], PAH.tchp3df[i][fp][1], PAH.tchp3df[i][fp][2]); break; default : assert(0); } } diff --git a/wrap/io_trimesh/import_ply.h b/wrap/io_trimesh/import_ply.h index 847ec99ca..dc2777b32 100644 --- a/wrap/io_trimesh/import_ply.h +++ b/wrap/io_trimesh/import_ply.h @@ -611,6 +611,8 @@ class ImporterPLY /* Main Reading Loop */ /**************************************************************/ m.Clear(); + PlyAttributeHelper PAH(pi,m); + for(size_t i=0;i0) )/******************** EDGE READING *******************************/ + /******************** EDGE ELEMENTS READING LOOP *******************************/ + else if( !strcmp( pf.ElemName(i),"edge") && (n>0) ) { assert( pi.mask & Mask::IOM_EDGEINDEX ); EdgeIterator ei=Allocator::AddEdges(m,n); @@ -757,15 +785,13 @@ class ImporterPLY ++ei; } } - /******************** FACE READING LOOP ****************************************/ + /******************** FACE ELEMENT READING ****************************************/ else if( !strcmp( pf.ElemName(i),"face") && (n>0) ) { - int j; - FaceIterator fi=Allocator::AddFaces(m,n); pf.SetCurElement(i); - for(j=0;j3) fi->SetF(2); - + + // Now try to read additional data as described in the PlyInfo FaceDescriptorVe; two cases: + // 1) you are using attributes (so the corresponding entry of FaceAttrNameVec is not empty) + // 2) your face type has some space and you just use memcopy + for(size_t k=0;k - /** -@name Load and Save in Ply format +@name Ply I/O +It contains the definition of the accessory class PlyInfo +It is directly included by the importer and exporter ply classes */ //@{ -#include -#include +#include "wrap/callback.h" +#include "wrap/ply/plylib.h" 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 - retrieving additional per-vertex per-face data @@ -67,170 +46,27 @@ class PlyInfo { public: typedef ::vcg::ply::PropDescriptor PropDescriptor ; - - void addPerElemScalarAttribute(int elemType, vcg::ply::PlyTypes propertyType, const std::string& attrName, std::string propName="") - { - if(propName=="") - propName=attrName; - - PropDescriptor p; - p.propname=propName; - p.islist = false; - p.stotype1 = propertyType; - p.memtype1 = propertyType; - - if (elemType == 0){ //vertex - VertAttrNameVec.push_back(attrName); - p.elemname="vertex"; - VertDescriptorVec.push_back(p); - } - else if (elemType == 1){ //face - FaceAttrNameVec.push_back(attrName); - p.elemname="face"; - FaceDescriptorVec.push_back(p); - } - } - - void AddPerElemFloatAttribute(int elemType, const std::string& attrName, std::string propName="") - { - addPerElemScalarAttribute(elemType, vcg::ply::T_FLOAT, attrName, propName); - } - - void AddPerElemDoubleAttribute(int elemType, const std::string& attrName, std::string propName="") - { - addPerElemScalarAttribute(elemType, vcg::ply::T_DOUBLE, attrName, propName); - } - - void addPerVertexScalarAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") - { - addPerElemScalarAttribute(0,attrType, attrName,propName); - } - - void AddPerVertexFloatAttribute(const std::string& attrName, std::string propName="") - { - AddPerElemFloatAttribute(0,attrName,propName); - } - - void addPerFaceScalarAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") - { - addPerElemScalarAttribute(1,attrType, attrName,propName); - } - - void AddPerFaceFloatAttribute(const std::string& attrName, std::string propName="") - { - AddPerElemFloatAttribute(1,attrName,propName); - } - - void addPerElemPointAttribute(int elemType, vcg::ply::PlyTypes propertyType, const std::string& attrName, std::string propName="") - { - if(propName=="") - propName=attrName; - - PropDescriptor p; - p.propname=propName; - p.stotype1 = propertyType; - p.memtype1 = propertyType; - p.islist = true; - p.memtype2 = vcg::ply::PlyTypes::T_UCHAR; - p.stotype2 = vcg::ply::PlyTypes::T_UCHAR; - - if (elemType == 0){ //vertex - VertAttrNameVec.push_back(attrName); - p.elemname="vertex"; - VertDescriptorVec.push_back(p); - } - else if (elemType == 1){ //face - FaceAttrNameVec.push_back(attrName); - p.elemname="face"; - FaceDescriptorVec.push_back(p); - } - } - - void addPerVertexPoint3mAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") - { - addPerElemPointAttribute(0,attrType, attrName,propName); - } - - void addPerVertexPoint3fAttribute(const std::string& attrName, std::string propName="") - { - addPerElemPointAttribute(0,vcg::ply::PlyTypes::T_FLOAT, attrName,propName); - } - - void addPerVertexPoint3dAttribute(const std::string& attrName, std::string propName="") - { - addPerElemPointAttribute(0,vcg::ply::PlyTypes::T_DOUBLE, attrName,propName); - } - - void addPerFacePoint3mAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") - { - addPerElemPointAttribute(1,attrType, attrName,propName); - } - - void addPerFacePoint3fAttribute(const std::string& attrName, std::string propName="") - { - addPerElemPointAttribute(1,vcg::ply::PlyTypes::T_FLOAT, attrName,propName); - } - - void addPerFacePoint3dAttribute(const std::string& attrName, std::string propName="") - { - addPerElemPointAttribute(1,vcg::ply::PlyTypes::T_DOUBLE, attrName,propName); - } - - /* Note that saving a per vertex point3 attribute is a mess. - * Actually it requires to allocate 3 float attribute and save them. And they are never deallocated... */ - template - void AddPerVertexPoint3fAttribute(MeshType &m, const std::string& attrName, std::string propName="") - { - if(propName=="") - 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; - } + typedef int PlyElemType; + const static PlyElemType PlyElemVertex = 0; + const static PlyElemType PlyElemFace = 1; + /// Store the error codes enconutered when parsing a ply - int status; + int status=0; /// It returns a bit mask describing the field present in the ply file - int mask; + int mask=0; /// a Simple callback that can be used for long ply parsing. // 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=0; /// The additional vertex descriptor that a user can specify to load additional per-vertex non-standard data stored in a ply 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 + + /// VertAttrNameVec is a vector containing the names of the attributes to be saved (loaded). + /// We assume that VertAttrNameVec, if not empty, is exactly of the same size of VertDescriptorVec + /// If VertAttrNameVec[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 std::vector FaceDescriptorVec; std::vector FaceAttrNameVec; @@ -250,8 +86,371 @@ enum Error E_BAD_VERT_INDEX_EDGE = ply::E_MAXPLYERRORS+8, // 22 E_MAXPLYINFOERRORS= ply::E_MAXPLYERRORS+9 // 23 }; + + /** + * @brief addPerElemScalarAttribute + * @param elemType Vertex or Face + * @param propertyType the type of the property + * @param attrName the name of the attribute (both in the ply file and in the mesh) + * @param propName, optional only in case we want to load a certain ply property in an attribute with a different name + * + * This function is used to specify additional per-vertex or per-face data + * that is stored in the ply file and that should loaded or saved using attributes + * + */ + void addPerElemScalarAttribute(PlyElemType elemType, vcg::ply::PlyTypes propertyType, const std::string& attrName, std::string propName="") + { + if(propName=="") + propName=attrName; + + PropDescriptor p; + p.propname=propName; + p.islist = false; + p.stotype1 = propertyType; + p.memtype1 = propertyType; + + if (elemType == PlyElemVertex){ + p.elemname="vertex"; + VertDescriptorVec.push_back(p); + VertAttrNameVec.resize(VertDescriptorVec.size()); + VertAttrNameVec.back() = attrName; + } + else if (elemType == PlyElemFace){ + p.elemname="face"; + FaceDescriptorVec.push_back(p); + FaceAttrNameVec.resize(FaceDescriptorVec.size()); + FaceAttrNameVec.back() = attrName; + } + } + + void AddPerElemFloatAttribute(PlyElemType elemType, const std::string& attrName, std::string propName="") + { + addPerElemScalarAttribute(elemType, vcg::ply::T_FLOAT, attrName, propName); + } + + void AddPerElemDoubleAttribute(PlyElemType elemType, const std::string& attrName, std::string propName="") + { + addPerElemScalarAttribute(elemType, vcg::ply::T_DOUBLE, attrName, propName); + } + + void addPerVertexScalarAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") + { + addPerElemScalarAttribute(PlyInfo::PlyElemVertex, attrType, attrName,propName); + } + + void AddPerVertexFloatAttribute(const std::string& attrName, std::string propName="") + { + AddPerElemFloatAttribute(PlyInfo::PlyElemVertex,attrName,propName); + } + + void addPerFaceScalarAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") + { + addPerElemScalarAttribute(PlyInfo::PlyElemFace,attrType, attrName,propName); + } + + void AddPerFaceFloatAttribute(const std::string& attrName, std::string propName="") + { + AddPerElemFloatAttribute(PlyInfo::PlyElemFace,attrName,propName); + } + + void addPerElemPointAttribute(int elemType, vcg::ply::PlyTypes propertyType, const std::string& attrName, std::string propName="") + { + if(propName=="") + propName=attrName; + + PropDescriptor p; + p.propname=propName; + p.stotype1 = propertyType; + p.memtype1 = propertyType; + p.islist = true; + p.memtype2 = vcg::ply::PlyTypes::T_UCHAR; + p.stotype2 = vcg::ply::PlyTypes::T_UCHAR; + + if (elemType == 0){ //vertex + VertAttrNameVec.push_back(attrName); + p.elemname="vertex"; + VertDescriptorVec.push_back(p); + } + else if (elemType == 1){ //face + FaceAttrNameVec.push_back(attrName); + p.elemname="face"; + FaceDescriptorVec.push_back(p); + } + } + + void addPerVertexPoint3mAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemVertex,attrType, attrName,propName); + } + + void addPerVertexPoint3fAttribute(const std::string& attrName, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemVertex,vcg::ply::PlyTypes::T_FLOAT, attrName,propName); + } + + void addPerVertexPoint3dAttribute(const std::string& attrName, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemVertex,vcg::ply::PlyTypes::T_DOUBLE, attrName,propName); + } + + void addPerFacePoint3mAttribute(const std::string& attrName, vcg::ply::PlyTypes attrType, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemFace,attrType, attrName,propName); + } + + void addPerFacePoint3fAttribute(const std::string& attrName, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemFace,vcg::ply::PlyTypes::T_FLOAT, attrName,propName); + } + + void addPerFacePoint3dAttribute(const std::string& attrName, std::string propName="") + { + addPerElemPointAttribute(PlyInfo::PlyElemFace,vcg::ply::PlyTypes::T_DOUBLE, attrName,propName); + } + + /* Note that saving a per vertex point3 attribute is a mess. + * Actually it requires to allocate 3 float attribute and save them. And they are never deallocated... */ + template + void AddPerVertexPoint3fAttribute(MeshType &m, const std::string& attrName, std::string propName="") + { + if(propName=="") + 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]); + } + } + +}; // end PlyInfo class + +// This class holds the vectors of handles to the attributes of a given mesh type +// it is intialized with a PlyInfo object and a mesh and try to retrieve and initialize +// a set of handles for all the attributes that we want to load/save into ply elements +// It is used internally by the importer and exporter ply classes + +template class PlyAttributeHelper +{ + public: + std::vector > tchfv; + std::vector > tchdv; + std::vector > tchiv; + std::vector > tchsv; + std::vector > tchcv; + std::vector > tchuv; + std::vector > tchp3fv; + std::vector > tchp3dv; + + std::vector > tchff; + std::vector > tchdf; + std::vector > tchif; + std::vector > tchsf; + std::vector > tchcf; + std::vector > tchuf; + std::vector > tchp3ff; + std::vector > tchp3df; + + std::vector > thfv; + std::vector > thdv; + std::vector > thiv; + std::vector > thsv; + std::vector > thcv; + std::vector > thuv; + std::vector > thp3fv; + std::vector > thp3dv; + + std::vector > thff; + std::vector > thdf; + std::vector > thif; + std::vector > thsf; + std::vector > thcf; + std::vector > thuf; + std::vector > thp3ff; + std::vector > thp3df; + + /* The constructor take care of initializing the handles to the attributes of a mesh + * given a PlyInfo object and a mesh + * Note that there are two version of the constructor one for const handler (used by save) and one for non-const handlers (used by load) + */ + + PlyAttributeHelper(const PlyInfo &pi, const MeshType &m) + { + tchfv.resize(pi.VertDescriptorVec.size()); + tchdv.resize(pi.VertDescriptorVec.size()); + tchiv.resize(pi.VertDescriptorVec.size()); + tchsv.resize(pi.VertDescriptorVec.size()); + tchcv.resize(pi.VertDescriptorVec.size()); + tchuv.resize(pi.VertDescriptorVec.size()); + tchp3fv.resize(pi.VertDescriptorVec.size()); + tchp3dv.resize(pi.VertDescriptorVec.size()); + + for(size_t i=0;i::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_DOUBLE : tchdv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_INT : tchiv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_SHORT : tchsv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_CHAR : tchcv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_UCHAR : tchuv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + default : assert(0); + } + } + else { + switch (pi.VertDescriptorVec[i].stotype1) + { + case ply::T_FLOAT : tchp3fv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_DOUBLE : tchp3dv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + default : assert(0); + } + } + } + } + + + tchff.resize(pi.FaceDescriptorVec.size()); + tchdf.resize(pi.FaceDescriptorVec.size()); + tchif.resize(pi.FaceDescriptorVec.size()); + tchsf.resize(pi.FaceDescriptorVec.size()); + tchcf.resize(pi.FaceDescriptorVec.size()); + tchuf.resize(pi.FaceDescriptorVec.size()); + tchp3ff.resize(pi.FaceDescriptorVec.size()); + tchp3df.resize(pi.FaceDescriptorVec.size()); + + for(size_t i=0;i::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_DOUBLE : tchdf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_INT : tchif[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_SHORT : tchsf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_CHAR : tchcf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_UCHAR : tchuf[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + default : assert(0); + } + } + else { + switch (pi.FaceDescriptorVec[i].stotype1) + { + case ply::T_FLOAT : tchp3ff[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_DOUBLE : tchp3df[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + default : assert(0); + } + } + } + } + } + + // Second version of the constructor + // This one is used when we want to load attributes from a ply file and we need non const handles to the attributes + PlyAttributeHelper(const PlyInfo &pi, MeshType &m) + { + thfv.resize(pi.VertDescriptorVec.size()); + thdv.resize(pi.VertDescriptorVec.size()); + thiv.resize(pi.VertDescriptorVec.size()); + thsv.resize(pi.VertDescriptorVec.size()); + thcv.resize(pi.VertDescriptorVec.size()); + thuv.resize(pi.VertDescriptorVec.size()); + thp3fv.resize(pi.VertDescriptorVec.size()); + thp3dv.resize(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); + } + } + else { + switch (pi.VertDescriptorVec[i].stotype1) + { + case ply::T_FLOAT : thp3fv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + case ply::T_DOUBLE : thp3dv[i] = vcg::tri::Allocator::template FindPerVertexAttribute(m,pi.VertAttrNameVec[i]); break; + default : assert(0); + } + } + } + } + + + thff.resize(pi.FaceDescriptorVec.size()); + thdf.resize(pi.FaceDescriptorVec.size()); + thif.resize(pi.FaceDescriptorVec.size()); + thsf.resize(pi.FaceDescriptorVec.size()); + thcf.resize(pi.FaceDescriptorVec.size()); + thuf.resize(pi.FaceDescriptorVec.size()); + thp3ff.resize(pi.FaceDescriptorVec.size()); + thp3df.resize(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); + } + } + else { + switch (pi.FaceDescriptorVec[i].stotype1) + { + case ply::T_FLOAT : thp3ff[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + case ply::T_DOUBLE : thp3df[i] = vcg::tri::Allocator::template FindPerFaceAttribute(m,pi.FaceAttrNameVec[i]); break; + default : assert(0); + } + } + } + } + } + +}; // end PlyAttributeHelper class + -}; // end class } // end namespace tri } // end namespace io } // end namespace vcg