1 // This file is part of libigl, a simple c++ geometry processing library.
2 //
3 // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public License
6 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
7 // obtain one at http://mozilla.org/MPL/2.0/.
8 #include "readPLY.h"
9 #include "list_to_matrix.h"
10 #include "ply.h"
11 #include <iostream>
12 
13 template <
14   typename Vtype,
15   typename Ftype,
16   typename Ntype,
17   typename UVtype>
readPLY(const std::string filename,std::vector<std::vector<Vtype>> & V,std::vector<std::vector<Ftype>> & F,std::vector<std::vector<Ntype>> & N,std::vector<std::vector<UVtype>> & UV)18 IGL_INLINE bool igl::readPLY(
19   const std::string filename,
20   std::vector<std::vector<Vtype> > & V,
21   std::vector<std::vector<Ftype> > & F,
22   std::vector<std::vector<Ntype> > & N,
23   std::vector<std::vector<UVtype> >  & UV)
24 {
25   using namespace std;
26   // Largely follows ply2iv.c
27   FILE * ply_file = fopen(filename.c_str(),"r");
28   if(ply_file == NULL)
29   {
30     return false;
31   }
32   return readPLY(ply_file,V,F,N,UV);
33 }
34 
35 template <
36   typename Vtype,
37   typename Ftype,
38   typename Ntype,
39   typename UVtype>
readPLY(FILE * ply_file,std::vector<std::vector<Vtype>> & V,std::vector<std::vector<Ftype>> & F,std::vector<std::vector<Ntype>> & N,std::vector<std::vector<UVtype>> & UV)40 IGL_INLINE bool igl::readPLY(
41   FILE * ply_file,
42   std::vector<std::vector<Vtype> > & V,
43   std::vector<std::vector<Ftype> > & F,
44   std::vector<std::vector<Ntype> > & N,
45   std::vector<std::vector<UVtype> >  & UV)
46 {
47   using namespace std;
48    typedef struct Vertex {
49      double x,y,z;          /* position */
50      double nx,ny,nz;         /* surface normal */
51      double s,t;              /* texture coordinates */
52      void *other_props;       /* other properties */
53    } Vertex;
54 
55    typedef struct Face {
56      unsigned char nverts;    /* number of vertex indices in list */
57      int *verts;              /* vertex index list */
58      void *other_props;       /* other properties */
59    } Face;
60 
61   igl::ply::PlyProperty vert_props[] = { /* list of property information for a vertex */
62     {"x", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,x), 0, 0, 0, 0},
63     {"y", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,y), 0, 0, 0, 0},
64     {"z", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,z), 0, 0, 0, 0},
65     {"nx", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nx), 0, 0, 0, 0},
66     {"ny", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,ny), 0, 0, 0, 0},
67     {"nz", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nz), 0, 0, 0, 0},
68     {"s", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,s), 0, 0, 0, 0},
69     {"t", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,t), 0, 0, 0, 0},
70   };
71 
72   igl::ply::PlyProperty face_props[] = { /* list of property information for a face */
73     {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
74       1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
75   };
76 
77   int nelems;
78   char ** elem_names;
79   igl::ply::PlyFile * in_ply = igl::ply::ply_read(ply_file,&nelems,&elem_names);
80   if(in_ply==NULL)
81   {
82     return false;
83   }
84 
85   bool has_normals = false;
86   bool has_texture_coords = false;
87   igl::ply::PlyProperty **plist;
88   int nprops;
89   int elem_count;
90   plist = ply_get_element_description (in_ply,"vertex", &elem_count, &nprops);
91   int native_binary_type = igl::ply::get_native_binary_type2();
92   if (plist != NULL)
93   {
94     /* set up for getting vertex elements */
95     ply_get_property (in_ply,"vertex",&vert_props[0]);
96     ply_get_property (in_ply,"vertex",&vert_props[1]);
97     ply_get_property (in_ply,"vertex",&vert_props[2]);
98     for (int j = 0; j < nprops; j++)
99     {
100       igl::ply::PlyProperty * prop = plist[j];
101       if (igl::ply::equal_strings ("nx", prop->name)
102         || igl::ply::equal_strings ("ny", prop->name)
103         || igl::ply::equal_strings ("nz", prop->name))
104       {
105         ply_get_property (in_ply,"vertex",&vert_props[3]);
106         ply_get_property (in_ply,"vertex",&vert_props[4]);
107         ply_get_property (in_ply,"vertex",&vert_props[5]);
108         has_normals = true;
109       }
110       if (igl::ply::equal_strings ("s", prop->name) ||
111         igl::ply::equal_strings ("t", prop->name))
112       {
113         ply_get_property(in_ply,"vertex",&vert_props[6]);
114         ply_get_property(in_ply,"vertex",&vert_props[7]);
115         has_texture_coords = true;
116       }
117     }
118     // Is this call necessary?
119     ply_get_other_properties(in_ply,"vertex",
120 				     offsetof(Vertex,other_props));
121     V.resize(elem_count,std::vector<Vtype>(3));
122     if(has_normals)
123     {
124       N.resize(elem_count,std::vector<Ntype>(3));
125     }else
126     {
127       N.resize(0);
128     }
129     if(has_texture_coords)
130     {
131       UV.resize(elem_count,std::vector<UVtype>(2));
132     }else
133     {
134       UV.resize(0);
135     }
136 
137 	for(int j = 0;j<elem_count;j++)
138     {
139       Vertex v;
140       ply_get_element_setup(in_ply,"vertex",3,vert_props);
141       ply_get_element(in_ply,(void*)&v, &native_binary_type);
142       V[j][0] = v.x;
143       V[j][1] = v.y;
144       V[j][2] = v.z;
145       if(has_normals)
146       {
147         N[j][0] = v.nx;
148         N[j][1] = v.ny;
149         N[j][2] = v.nz;
150       }
151       if(has_texture_coords)
152       {
153         UV[j][0] = v.s;
154         UV[j][1] = v.t;
155       }
156     }
157   }
158   plist = ply_get_element_description (in_ply,"face", &elem_count, &nprops);
159   if (plist != NULL)
160   {
161     F.resize(elem_count);
162     ply_get_property(in_ply,"face",&face_props[0]);
163     for (int j = 0; j < elem_count; j++)
164     {
165       Face f;
166       ply_get_element(in_ply, (void *) &f, &native_binary_type);
167       for(size_t c = 0;c<f.nverts;c++)
168       {
169         F[j].push_back(f.verts[c]);
170       }
171     }
172   }
173   ply_close(in_ply);
174   return true;
175 }
176 
177 template <
178   typename DerivedV,
179   typename DerivedF,
180   typename DerivedN,
181   typename DerivedUV>
readPLY(const std::string filename,Eigen::PlainObjectBase<DerivedV> & V,Eigen::PlainObjectBase<DerivedF> & F,Eigen::PlainObjectBase<DerivedN> & N,Eigen::PlainObjectBase<DerivedUV> & UV)182 IGL_INLINE bool igl::readPLY(
183   const std::string filename,
184   Eigen::PlainObjectBase<DerivedV> & V,
185   Eigen::PlainObjectBase<DerivedF> & F,
186   Eigen::PlainObjectBase<DerivedN> & N,
187   Eigen::PlainObjectBase<DerivedUV> & UV)
188 {
189   std::vector<std::vector<typename DerivedV::Scalar> > vV;
190   std::vector<std::vector<typename DerivedF::Scalar> > vF;
191   std::vector<std::vector<typename DerivedN::Scalar> > vN;
192   std::vector<std::vector<typename DerivedUV::Scalar> > vUV;
193   if(!readPLY(filename,vV,vF,vN,vUV))
194   {
195     return false;
196   }
197   return
198     list_to_matrix(vV,V) &&
199     list_to_matrix(vF,F) &&
200     list_to_matrix(vN,N) &&
201     list_to_matrix(vUV,UV);
202 }
203 
204 template <
205   typename DerivedV,
206   typename DerivedF>
readPLY(const std::string filename,Eigen::PlainObjectBase<DerivedV> & V,Eigen::PlainObjectBase<DerivedF> & F)207 IGL_INLINE bool igl::readPLY(
208   const std::string filename,
209   Eigen::PlainObjectBase<DerivedV> & V,
210   Eigen::PlainObjectBase<DerivedF> & F)
211 {
212   Eigen::MatrixXd N,UV;
213   return readPLY(filename,V,F,N,UV);
214 }
215 
216 #ifdef IGL_STATIC_LIBRARY
217 // Explicit template instantiation
218 template bool igl::readPLY<double, int, double, double>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
219 
220 template bool igl::readPLY<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &);
221 
222 template bool igl::readPLY<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> > &);
223 template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
224 #endif
225