MEPP2 Project
PlyFileReader.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 #pragma once
12 
13 #include <iostream>
14 #include <vector>
15 #include <cassert>
16 #include <cstdio>
17 #include <string>
18 #include <exception>
19 
22 
23 namespace FEVV {
24 namespace IO {
25 
26 using namespace StrUtils;
27 using namespace FileUtils;
28 
29 
31 
35 template< typename CoordType,
36  typename CoordNType,
37  typename CoordTType,
38  typename CoordCType,
39  typename IndexType >
40 void
41 read_ply_file(std::string file_path,
42  std::vector< std::vector< CoordType > > &points_coords,
43  std::vector< std::vector< CoordNType > > &normals_coords,
44  std::vector< std::vector< CoordTType > > &texture_coords,
45  std::vector< std::vector< CoordCType > > &vertex_color_coords,
46  std::vector< std::vector< IndexType > > &face_indices,
47  std::vector< std::vector< IndexType > > &texture_face_indices)
48 {
49  points_coords.clear();
50  normals_coords.clear();
51  texture_coords.clear();
52  vertex_color_coords.clear();
53  face_indices.clear();
54  texture_face_indices.clear();
55 
56  std::ifstream file(file_path);
57 
58  if(file.is_open())
59  {
60  std::string line;
61  size_t tokens_size;
62  std::vector< std::string > tokens;
63 
65  bool vertices_have_color = false, vertices_have_alpha = false,
66  vertices_have_normal = false, faces_have_texture = false;
67 
68  unsigned int vertex_dim = 3u, normal_dim = 3u, color_dim = 3u,
69  alpha_dim = 3u, tex_dim = 2u, offset, face_degree;
70 
71  unsigned long nb_read_vertices = 0ul, nb_total_vertices = 0ul,
72  nb_read_edges = 0ul, nb_total_edges = 0ul,
73  nb_read_faces = 0ul, nb_total_faces = 0ul,
74  nb_face_texture_point = 0u;
75 
76  CoordType coord;
77  CoordNType n_coord;
78  CoordTType t_coord;
79  CoordCType c_coord;
80  IndexType f_ind;
81 
82  // HEADER READ
83  while(safe_getline(file, line))
84  {
85  tokens = split(line, "\t ");
86  tokens_size = tokens.size();
87 
88  if(tokens_size == 0) // Nothing on the line
89  continue;
90  else
91  {
92  if(tokens[0].compare("element") == 0)
93  {
94  if(tokens_size > 2)
95  {
96  if(tokens[1].compare("vertex") == 0)
97  {
98  convert(tokens[2], nb_total_vertices);
99  prop = VERTEX_PROPERTY;
100  }
101  else if(tokens[1].compare("edge") == 0)
102  {
103  convert(tokens[2], nb_total_edges);
104  prop = EDGE_PROPERTY;
105  }
106  else if(tokens[1].compare("face") == 0)
107  {
108  convert(tokens[2], nb_total_faces);
109  prop = FACE_PROPERTY;
110  }
111  }
112  else
113  throw std::runtime_error("Reader::read_ply_file -> wrong tokens "
114  "number for header line.");
115  }
116  else if(tokens[0].compare("property") == 0)
117  {
118  if(tokens_size > 2)
119  {
120  switch(prop) // TODO : we can do a better properties handling (and
121  // add material properties handling)
122  {
123  case VERTEX_PROPERTY:
124  if(tokens[2].compare("nx") == 0) // eg : property float nx
125  vertices_have_normal = true;
126  if(tokens[2].compare("red") == 0) // eg : property uchar red
127  vertices_have_color = true;
128  if(tokens[2].compare("alpha") == 0) // eg : property uchar alpha
129  vertices_have_alpha = true;
130  break;
131  case EDGE_PROPERTY:
132  // No edge properties handle yet
133  break;
134  case FACE_PROPERTY:
135  if(tokens_size > 4) // eg : property uint8 float texcoord
136  {
137  if(tokens[4].compare("texcoord") == 0)
138  faces_have_texture = true;
139  }
140  break;
141  }
142  }
143  else
144  throw std::runtime_error("Reader::read_ply_file -> wrong tokens "
145  "number for header line.");
146  }
147  else if((tokens[0].compare("end_header") == 0))
148  break;
149  }
150  }
151 
152  // VERTICES READ
153  while(nb_read_vertices < nb_total_vertices)
154  {
155  if((safe_getline(file, line)))
156  {
157  tokens = split(line, "\t ");
158  tokens_size = tokens.size();
159  unsigned int i = 0u;
160 
161  if(tokens_size == 0) // Nothing on the line (the comment line case is
162  // not detected, as the comment tag is a full
163  // string, it would have decrease the performance)
164  continue;
165  else if(tokens_size == vertex_dim +
166  (vertices_have_normal ? normal_dim : 0) +
167  (vertices_have_color ? color_dim : 0) +
168  (vertices_have_alpha ? alpha_dim : 0))
169  {
170  std::vector< CoordType > point;
171  for(; i < vertex_dim; ++i)
172  {
173  convert(tokens[i], coord);
174  point.push_back(coord);
175  }
176  points_coords.push_back(point);
177 
178  if(vertices_have_normal)
179  {
180  std::vector< CoordNType > normal;
181  offset = vertex_dim + normal_dim;
182  for(; i < offset; ++i)
183  {
184  convert(tokens[i], n_coord);
185  normal.push_back(n_coord);
186  }
187  normals_coords.push_back(normal);
188  }
189 
190  if(vertices_have_color)
191  {
192  std::vector< CoordCType > color;
193  offset = vertex_dim + (vertices_have_normal ? normal_dim : 0) +
194  color_dim +
195  (vertices_have_alpha ? alpha_dim
196  : 0); // corrected by Vincent V.
197  for(; i < offset; ++i)
198  {
199  convert(tokens[i], c_coord);
200  color.push_back(c_coord);
201  }
202  vertex_color_coords.push_back(color);
203  }
204 
205  nb_read_vertices++;
206  }
207  else
208  {
209  // DBG std::cout << "tokensSize=" << tokensSize << " vertexDim=" <<
210  // vertexDim << " verticesHaveNormal=" << verticesHaveNormal << "
211  // normalDim=" << normalDim << " verticesHaveColor=" <<
212  // verticesHaveColor << " colorDim=" << colorDim << "
213  // verticesHaveAlpha=" << verticesHaveAlpha << " alphaDim=" << alphaDim
214  // << std::endl;
215  // TODO-elo vertex texture coordinates not yet supported in this PLY
216  // reader
217  // TODO-elo supported vertex line format:
218  // TODO-elo vt_coordinates_x_y_z [vt_normal_x_y_z]
219  // [vt_color_x_y_z [vt_color_alpha_a]]
220  throw std::runtime_error(
221  std::string("Reader::read_ply_file -> vertex line '") + line +
222  std::string("'do not fit to the format."));
223  }
224  }
225  else
226  throw std::runtime_error(
227  "Reader::read_ply_file -> wrong number of vertices specified or "
228  "read error occured while parsing vertices.");
229  }
230 
231  // FACES READ
232  while(nb_read_faces < nb_total_faces)
233  {
234  if((safe_getline(file, line)))
235  {
236  tokens = split(line, "\t ");
237  tokens_size = tokens.size();
238  unsigned int i = 1u;
239 
240  if(tokens_size == 0) // Nothing on the line (the comment line case is
241  // not detected, as the comment tag is a full
242  // string, it would have decrease the performance)
243  continue;
244  else
245  {
246  std::vector< IndexType > face;
247  convert(tokens[0], face_degree);
248  offset = face_degree + 1;
249 
250  if(tokens_size >= offset)
251  {
252  for(; i < offset; ++i)
253  {
254  convert(tokens[i], f_ind);
255  face.push_back(f_ind);
256  }
257  face_indices.push_back(face);
258 
259  if(faces_have_texture)
260  {
261  i++; // The number of tex coord is not taken into account for now
262  // (a valid number of tex coord is faceDegree*texDim)
263 
264  std::vector< IndexType > face_textures;
265  for(unsigned int j = 0; j < face_degree; ++i)
266  {
267  std::vector< CoordTType > tex_coord;
268  for(; i < tex_dim; ++i)
269  {
270  convert(tokens[i], t_coord);
271  tex_coord.push_back(t_coord);
272  }
273  texture_coords.push_back(tex_coord);
274  face_textures.push_back(nb_face_texture_point++);
275  }
276  texture_face_indices.push_back(face_textures);
277  }
278  nb_read_faces++;
279  }
280  else
281  throw std::runtime_error(
282  "Reader::read_ply_file -> face line do not fit to the format.");
283  }
284  }
285  else
286  throw std::runtime_error(
287  "Reader::read_ply_file -> wrong number of faces specified or read "
288  "error occured while parsing faces.");
289  }
290 
291  // EDGES READ
292  while(nb_read_edges < nb_total_edges)
293  {
294  if((safe_getline(file, line)))
295  {
296  tokens = split(line, "\t ");
297  tokens_size = tokens.size();
298  unsigned int i = 0u;
299 
300  if(tokens_size == 0) // Nothing on the line (the comment line case is
301  // not detected, as the comment tag is a full
302  // string, it would have decrease the performance)
303  continue;
304  else
305  {
306  std::vector< IndexType > edge;
307 
308  if(tokens_size >= 2)
309  {
310  for(; i < 2; ++i)
311  {
312  convert(tokens[i], f_ind);
313  edge.push_back(f_ind);
314  }
315  face_indices.push_back(edge); // add edge as a two vertices face
316 
317  nb_read_edges++;
318  }
319  else
320  throw std::runtime_error(
321  "Reader::read_ply_file -> edge line do not fit to the format.");
322  }
323  }
324  else
325  throw std::runtime_error(
326  "Reader::read_ply_file -> wrong number of edges specified or read "
327  "error occured while parsing edges.");
328  }
329 
330  file.close();
331  }
332  else
333  {
334  throw std::runtime_error(
335  "Reader::read_ply_file -> input file failed to open.");
336  }
337 }
338 
339 } // namespace IO
340 } // namespace FEVV
341 
FEVV::StrUtils::convert
void convert(const std::string &str, ConvertType &elem)
Definition: StringUtilities.hpp:81
FEVV::IO::VERTEX_PROPERTY
@ VERTEX_PROPERTY
Definition: PlyFileReader.h:30
FEVV::IO::read_ply_file
void read_ply_file(std::string file_path, std::vector< std::vector< CoordType > > &points_coords, std::vector< std::vector< CoordNType > > &normals_coords, std::vector< std::vector< CoordTType > > &texture_coords, std::vector< std::vector< CoordCType > > &vertex_color_coords, std::vector< std::vector< IndexType > > &face_indices, std::vector< std::vector< IndexType > > &texture_face_indices)
Definition: PlyFileReader.h:41
FEVV::FileUtils::safe_getline
std::ifstream & safe_getline(std::ifstream &input, std::string &str)
Definition: FileUtilities.hpp:208
FEVV::DataStructures::AIF::edge
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::edge_descriptor edge(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::halfedge_descriptor h, const FEVV::DataStructures::AIF::AIFMesh &sm)
Returns the edge corresponding to h and opposite(h).
Definition: Graph_traits_aif.h:345
FEVV::StrUtils::split
std::vector< std::string > split(const std::string &str, const std::string &delims, bool keep_empty_tokens=false)
Definition: StringUtilities.hpp:35
FEVV
Interfaces for plugins These interfaces will be used for different plugins.
Definition: Assert.h:16
FEVV::IO::FACE_PROPERTY
@ FACE_PROPERTY
Definition: PlyFileReader.h:30
FEVV::IO::ply_property
ply_property
Definition: PlyFileReader.h:30
StringUtilities.hpp
FEVV::DataStructures::AIF::face
boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::face_descriptor face(typename boost::graph_traits< FEVV::DataStructures::AIF::AIFMesh >::halfedge_descriptor h, const FEVV::DataStructures::AIF::AIFMesh &)
Returns the face incident to halfedge h.
Definition: Graph_traits_aif.h:664
FileUtilities.hpp
FEVV::IO::EDGE_PROPERTY
@ EDGE_PROPERTY
Definition: PlyFileReader.h:30