Code_TYMPAN  4.4.0
Industrial site acoustic simulation
altimetry_file_reader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
24 #include <cassert>
25 
26 #include <boost/foreach.hpp>
27 #include <boost/exception/errinfo_file_name.hpp>
28 #include <boost/exception/errinfo_at_line.hpp>
29 #include <boost/exception/errinfo_errno.hpp>
30 
31 #include "rply.h"
32 #include "rplyfile.h"
33 
35 
36 // section with C linkage for RPLY callbacks
37 extern "C"
38 {
39  static int vertex_cb(p_ply_argument argument);
40  static int face_cb(p_ply_argument argument);
41  static int material_cb(p_ply_argument argument);
42  static void error_cb(p_ply ply, const char* message);
43 } // extern C
44 
45 static const double NaN = std::numeric_limits<double>::quiet_NaN();
46 
47 namespace tympan
48 {
49 
50 //========== Implementation of free functions ==========
51 
52 std::unique_ptr<IMeshReader> make_altimetry_ply_reader(const std::string filename)
53 {
54  FILE* fp = fopen(filename.c_str(), "rb");
55  if (fp == nullptr)
56  throw mesh_io_error("Opening PLY file") << tympan_source_loc;
57  return std::unique_ptr<IMeshReader>(new AltimetryPLYReader(fp));
58 } // make_altimetry_ply_reader
59 
60 //========== Implementation of AltimetryPLYReader methods ==========
61 
63  : _fp(fp), _ply(nullptr), _nvertices(-1), _nfaces(-1), _nmaterials(-1)
64 {
65  // Opens the PLY file, no error callback is given
66 
67  _ply = ply_open_from_file(_fp, ::error_cb, 0 /*unused*/, this);
68  if (_ply == nullptr)
69  throw mesh_io_error("Opening PLY file") << tympan_source_loc;
70  // Reads the header
71  if (!ply_read_header(_ply))
72  throw mesh_io_error("Reading the PLY header") << tympan_source_loc;
73 }
74 
76 {
77  ply_close(_ply);
78 }
79 
81 {
83  init_data();
84  read_data();
86 }
87 
89 {
90  long n = 0;
91  assert(_nvertices == -1 && _nfaces == -1);
92  n = ply_set_read_cb(_ply, "vertex", "x", ::vertex_cb, this, X);
93  _nvertices = n;
94  n = ply_set_read_cb(_ply, "vertex", "y", ::vertex_cb, this, Y);
95  assert(n == _nvertices);
96  n = ply_set_read_cb(_ply, "vertex", "z", ::vertex_cb, this, Z);
97  assert(n == _nvertices);
98  n = ply_set_read_cb(_ply, "face", "vertex_indices", ::face_cb, this, VertexIndices);
99  _nfaces = n;
100  n = ply_set_read_cb(_ply, "face", "material_index", ::face_cb, this, MaterialIndex);
101  assert(n == _nfaces);
102  _nmaterials = ply_set_read_cb(_ply, "material", "id", ::material_cb, this, MaterialID);
103 }
104 
106 {
107  _material_indices.resize(_nfaces, -1);
108 }
109 
111 {
112  if (!ply_read(_ply))
113  throw mesh_io_error("Reading the PLY data") << tympan_source_loc;
114 }
115 
117 {
118  assert(_material_by_face.empty());
119  assert(_material_indices.size() == _nfaces);
120  assert(_faces.size() == _nfaces);
121  BOOST_FOREACH (int material_index, _material_indices)
122  {
123  if (material_index == -1) // No material attributed
124  _material_by_face.push_back("");
125  else if (material_index < _nmaterials)
126  _material_by_face.push_back(_materials[material_index]);
127  else
128  throw mesh_io_error("Invalid material index") << tympan_source_loc;
129  }
130  assert(_material_by_face.size() == _nfaces);
131 }
132 
133 bool AltimetryPLYReader::vertex_cb(vertex_properties property, unsigned vertex_index, double value)
134 {
135  switch (property)
136  {
137  case X:
138  // Insert a new point
139  _points.push_back(OPoint3D(NaN, NaN, NaN));
140  // Deliberate fall-through
141  case Y:
142  case Z:
143  // Store the coordinate
144  // NB the numerical value of ``property`` is the index of the vertex
145  assert(_points.size() - 1 == vertex_index); // Index consistency
146  _points.back()._value[(unsigned)property] = value;
147  break;
148  default:
149  return false;
150  }
151  return true;
152 }
153 
154 bool AltimetryPLYReader::face_cb(face_properties property, unsigned face_index, unsigned nproperties,
155  int property_index, double value)
156 {
157  switch (property)
158  {
159  case VertexIndices:
160  // Reading vertices index for the face, expected to be a triangle
161  if (nproperties != 3)
162  {
163  // Should probably NOT raise a exception from within a C callback
164  // TODO properly report, e.g. with an error status in the reader
165  return false;
166  }
167  if (property_index == -1)
168  { // RPLY is giving us the length
169  assert(value == 3.0); // Value should be equal to length
170  _faces.push_back(OTriangle(-1, -1, -1));
171  }
172  else
173  {
174  assert(property_index < 3);
175  assert(_faces.size() - 1 == face_index); // Index consistency
176  const unsigned vertex_index = (unsigned)value;
177  OTriangle& triangle = _faces.back();
178  triangle.index(property_index) = vertex_index;
179  // Ensure consistency of the OTriangle redundant representation
180  triangle.vertex(property_index) = _points[vertex_index];
181  }
182  break;
183  case MaterialIndex:
184  assert(_material_indices[face_index] == -1);
185  _material_indices[face_index] = (unsigned)value;
186  break;
187  default:
188  return false;
189  }
190  return true;
191 }
192 
193 bool AltimetryPLYReader::material_cb(material_properties property, unsigned material_index,
194  unsigned nproperties, int property_index, double value)
195 {
196  switch (property)
197  {
198  case MaterialID:
199  if (property_index == -1)
200  { // RPLY is giving us the length of the ID
201  assert(value == nproperties); // Value should be equal to length
202  _materials.push_back(std::string(nproperties, '-'));
203  }
204  else
205  {
206  assert((unsigned)property_index < nproperties);
207  assert(_materials.size() - 1 == material_index); // Index consistency
208  _materials.back()[property_index] = (unsigned char)value;
209  }
210  break;
211  default:
212  return false;
213  }
214  return true;
215 }
216 
217 void AltimetryPLYReader::error_cb(p_ply ply, const char* message)
218 {
219  assert(_ply == NULL || ply == _ply);
220  throw mesh_io_error(message) << tympan_source_loc;
221 }
222 
223 }; // namespace tympan
224 
225 //========== C callback must be defined outside the namespace tympan ==========
226 
227 // using namespace tympan;
228 
232 #define DECLARE_AND_FETCH_PLY_CALLBACK_INFO \
233  long idata; \
234  void* pdata; \
235  tympan::AltimetryPLYReader* p_reader; \
236  long instance_index; \
237  p_ply_element element; \
238  double value; \
239  ply_get_argument_user_data(argument, &pdata, &idata); \
240  p_reader = (tympan::AltimetryPLYReader*)pdata; \
241  ply_get_argument_element(argument, &element, &instance_index); \
242  value = ply_get_argument_value(argument);
243 // END OF DECLARE_AND_FETCH_PLY_CALLBACK_INFO
244 
247 static int vertex_cb(p_ply_argument argument)
248 {
251  assert(0 <= idata && idata < tympan::AltimetryPLYReader::NUM_vertex_properties);
252  vertex_property = (tympan::AltimetryPLYReader::vertex_properties)idata;
253  return p_reader->vertex_cb(vertex_property, instance_index, value);
254 }
255 
258 static int face_cb(p_ply_argument argument)
259 {
262  assert(0 <= idata && idata < tympan::AltimetryPLYReader::NUM_face_properties);
263  face_property = (tympan::AltimetryPLYReader::face_properties)idata;
264  // Access to property list
265  long length = 0, value_index = 0;
266  p_ply_property property = nullptr;
267  ply_get_argument_property(argument, &property, &length, &value_index);
268  return p_reader->face_cb(face_property, instance_index, length, value_index, value);
269 }
270 
273 static int material_cb(p_ply_argument argument)
274 {
277  assert(0 <= idata && idata < tympan::AltimetryPLYReader::NUM_material_properties);
278  material_property = (tympan::AltimetryPLYReader::material_properties)idata;
279  // Access to property list
280  long length = 0, value_index = 0;
281  p_ply_property property = nullptr;
282  ply_get_argument_property(argument, &property, &length, &value_index);
283  return p_reader->material_cb(material_property, instance_index, length, value_index, value);
284 }
285 
287 static void error_cb(p_ply ply, const char* message)
288 {
289  long idata = 0;
290  void* pdata = nullptr;
291  tympan::AltimetryPLYReader* p_reader = nullptr;
292  if (ply)
293  {
294  ply_get_ply_user_data(ply, &pdata, &idata);
295  p_reader = (tympan::AltimetryPLYReader*)pdata;
296  p_reader->error_cb(ply, message);
297  }
298 }
#define DECLARE_AND_FETCH_PLY_CALLBACK_INFO
macro which extract all relevant callback information form RPLY
Implementation details header for altimetry_reader.cpp.
struct t_ply_ * p_ply
The 3D point class.
Definition: 3d.h:487
Triangle class.
Definition: triangle.h:28
read an Altimetry from a PLY file.
std::vector< unsigned > _material_indices
bool vertex_cb(vertex_properties property, unsigned vertex_index, double value)
virtual void read()
read the file whose name was given at reader's construction time
bool face_cb(face_properties property, unsigned face_index, unsigned nproperties, int property_index, double value)
void error_cb(p_ply ply, const char *message)
bool material_cb(material_properties property, unsigned material_index, unsigned nproperties, int property_index, double value)
#define tympan_source_loc
This macro build a source_loc object to be attached to a tympan::Exception.
Definition: exceptions.h:91
std::unique_ptr< IMeshReader > make_altimetry_ply_reader(const std::string filename)
@ Makes a reader for the file name given as argument