1 #include <iostream>
2 #include <limits>
3 #include "vnl/vnl_math.h"
4 #include "boxm2_export_oriented_point_cloud_function.h"
5 //:
6 // \file
7
8 #include <cassert>
9 #ifdef _MSC_VER
10 # include "vcl_msvc_warnings.h"
11 #endif
12 #include <vnl/algo/vnl_symmetric_eigensystem.h>
13
14 #include <rply.h> //.ply parser
15
16 #include <boxm2/cpp/algo/boxm2_mog3_grey_processor.h>
17
18
exportPointCloudXYZ(const boxm2_scene_sptr & scene,const boxm2_block_metadata &,boxm2_block * blk,boxm2_data_base * alpha,boxm2_data_base * vis,boxm2_data_base * vis_sum,boxm2_data_base * exp,boxm2_data_base * nobs,boxm2_data_base * points,boxm2_data_base * normals,boxm2_data_base * ray_dir_sum,std::ofstream & file,bool output_aux,float vis_t,float nmag_t,float prob_t,float exp_t,vgl_box_3d<double> bb)19 void boxm2_export_oriented_point_cloud_function::exportPointCloudXYZ(const boxm2_scene_sptr& scene, const boxm2_block_metadata& /*data*/, boxm2_block* blk,
20 boxm2_data_base* alpha, boxm2_data_base* vis, boxm2_data_base* vis_sum, boxm2_data_base* exp,boxm2_data_base* nobs,
21 boxm2_data_base* points, boxm2_data_base* normals,
22 boxm2_data_base* ray_dir_sum, std::ofstream& file,
23 bool output_aux, float vis_t, float nmag_t, float prob_t, float exp_t, vgl_box_3d<double> bb)
24 {
25 auto * alpha_data = (boxm2_data_traits<BOXM2_ALPHA>::datatype*) alpha->data_buffer();
26 auto * points_data = (boxm2_data_traits<BOXM2_POINT>::datatype*) points->data_buffer();
27 auto * normals_data = (boxm2_data_traits<BOXM2_NORMAL>::datatype*) normals->data_buffer();
28 auto * vis_data = (boxm2_data_traits<BOXM2_VIS_SCORE>::datatype*) vis->data_buffer();
29 auto * vis_sum_data = (boxm2_data_traits<BOXM2_VIS_SCORE>::datatype*) vis_sum->data_buffer();
30 auto * exp_data = (boxm2_data_traits<BOXM2_EXPECTATION>::datatype*) exp->data_buffer();
31 auto * nobs_data = (boxm2_data_traits<BOXM2_NUM_OBS_SINGLE_INT>::datatype*) nobs->data_buffer();
32 auto * ray_dir_sum_data = (boxm2_data_traits<BOXM2_RAY_DIR>::datatype*) ray_dir_sum->data_buffer();
33
34 file << std::fixed;
35 int pointTypeSize = (int)boxm2_data_info::datasize(boxm2_data_traits<BOXM2_POINT>::prefix());
36 //check for invalid parameters
37 if( pointTypeSize == 0 ) //This should never happen, it will result in division by zero later
38 {
39 std::cerr << "ERROR: Division by zero in " << __FILE__ << __LINE__ << std::endl;
40 throw 0;
41 }
42
43 for (unsigned currIdx=0; currIdx < (points->buffer_length()/pointTypeSize) ; currIdx++) {
44 //check normal magnitude and vis score and that point data is valid
45 if (normals_data[currIdx][3] >= nmag_t && vis_data[currIdx] >= vis_t && points_data[currIdx][3] != -1)
46 {
47 float prob;
48 if (!calculateProbOfPoint(scene, blk, points_data[currIdx], alpha_data[currIdx], prob))
49 continue;
50
51 //check prob
52 if (prob >= prob_t && exp_data[currIdx] >= exp_t)
53 {
54 //check bounding box
55 if (bb.is_empty() || bb.contains(points_data[currIdx][0] ,points_data[currIdx][1] ,points_data[currIdx][2]) )
56 {
57 file << points_data[currIdx][0] << ' ' << points_data[currIdx][1] << ' ' << points_data[currIdx][2] << ' '
58 << normals_data[currIdx][0] << ' ' << normals_data[currIdx][1] << ' ' << normals_data[currIdx][2] << ' ';
59
60 if (output_aux) {
61 file << prob << ' ' << normals_data[currIdx][3] << ' ' << vis_data[currIdx] << ' ' << vis_sum_data[currIdx];
62 file << ' ' << ray_dir_sum_data[currIdx][0] << " " << ray_dir_sum_data[currIdx][1] << " " << ray_dir_sum_data[currIdx][2] << " ";
63 file << ' ' << exp_data[currIdx] << ' ' << nobs_data[currIdx];
64 }
65 file << std::endl;
66 }
67 }
68 }
69 }
70 }
71
exportPointCloudPLY(const boxm2_scene_sptr & scene,const boxm2_block_metadata &,boxm2_block * blk,boxm2_data_base * alpha,boxm2_data_base * vis,boxm2_data_base * points,boxm2_data_base * normals,std::ofstream & file,bool output_aux,float vis_t,float nmag_t,float prob_t,vgl_box_3d<double> bb,unsigned & num_vertices)72 void boxm2_export_oriented_point_cloud_function::exportPointCloudPLY(const boxm2_scene_sptr& scene, const boxm2_block_metadata& /*data*/, boxm2_block* blk,
73 boxm2_data_base* alpha, boxm2_data_base* vis,
74 boxm2_data_base* points, boxm2_data_base* normals,
75 std::ofstream& file,
76 bool output_aux, float vis_t, float nmag_t, float prob_t, vgl_box_3d<double> bb, unsigned& num_vertices)
77 {
78 auto * alpha_data = (boxm2_data_traits<BOXM2_ALPHA>::datatype*) alpha->data_buffer();
79 auto * points_data = (boxm2_data_traits<BOXM2_POINT>::datatype*) points->data_buffer();
80 auto * normals_data = (boxm2_data_traits<BOXM2_NORMAL>::datatype*) normals->data_buffer();
81 auto * vis_data = (boxm2_data_traits<BOXM2_VIS_SCORE>::datatype*) vis->data_buffer();
82
83 file << std::fixed;
84 int pointTypeSize = (int)boxm2_data_info::datasize(boxm2_data_traits<BOXM2_POINT>::prefix());
85 //check for invalid parameters
86 if( pointTypeSize == 0 ) //This should never happen, it will result in division by zero later
87 {
88 std::cerr << "ERROR: Division by 0 in " << __FILE__ << __LINE__ << std::endl;
89 throw 0;
90 }
91
92 for (unsigned currIdx=0; currIdx < (points->buffer_length()/pointTypeSize) ; currIdx++) {
93 //check normal magnitude and vis score and that point data is valid
94 if (normals_data[currIdx][3] >= nmag_t && vis_data[currIdx] >= vis_t && points_data[currIdx][3] != -1)
95 {
96 float prob;
97 if (!calculateProbOfPoint(scene, blk, points_data[currIdx], alpha_data[currIdx], prob))
98 continue;
99
100 //check prob
101 if (prob >= prob_t )
102 {
103 //check bounding box
104 if (bb.is_empty() || bb.contains(points_data[currIdx][0] ,points_data[currIdx][1] ,points_data[currIdx][2]) )
105 {
106 file << points_data[currIdx][0] << ' ' << points_data[currIdx][1] << ' ' << points_data[currIdx][2];
107 num_vertices++;
108
109 if (output_aux){
110 file << ' ' << normals_data[currIdx][0] << ' ' << normals_data[currIdx][1] << ' ' << normals_data[currIdx][2] << ' ' << prob << ' ' << vis_data[currIdx] << ' ' << normals_data[currIdx][3];
111 }
112 file << std::endl;
113 }
114 }
115 }
116 }
117 }
118
exportPointCloudPLY(const boxm2_scene_sptr &,const boxm2_block_metadata &,boxm2_block *,boxm2_data_base * mog,boxm2_data_base * alpha,boxm2_data_base * points,boxm2_data_base * covariances,std::ofstream & file,float prob_t,float LE_t,float CE_t,vgl_box_3d<double> bb,unsigned & num_vertices,const std::string & datatype)119 void boxm2_export_oriented_point_cloud_function::exportPointCloudPLY(const boxm2_scene_sptr& /*scene*/, const boxm2_block_metadata& /*data*/, boxm2_block* /*blk*/,
120 boxm2_data_base* mog, boxm2_data_base* alpha,
121 boxm2_data_base* points, boxm2_data_base* covariances, std::ofstream& file,
122 float prob_t, float LE_t, float CE_t, vgl_box_3d<double> bb, unsigned& num_vertices, const std::string& datatype)
123 {
124 auto * points_data = (boxm2_data_traits<BOXM2_POINT>::datatype*) points->data_buffer();
125 auto * covs_data = (boxm2_data_traits<BOXM2_COVARIANCE>::datatype*) covariances->data_buffer();
126 auto * alpha_data = (boxm2_data_traits<BOXM2_ALPHA>::datatype*) alpha->data_buffer();
127
128 file << std::fixed;
129 int pointTypeSize = (int)boxm2_data_info::datasize(boxm2_data_traits<BOXM2_POINT>::prefix());
130 //check for invalid parameters
131 if( pointTypeSize == 0 ) //This should never happen, it will result in division by zero later
132 {
133 std::cerr << "ERROR: Division by 0 in " << __FILE__ << __LINE__ << std::endl;
134 throw 0;
135 }
136
137 for (unsigned currIdx=0; currIdx < (points->buffer_length()/pointTypeSize) ; currIdx++) {
138 //check if the point data is valid
139 //if (covs_data[currIdx][0] >= 0.0)
140 //{
141
142 //check bounding box
143 if (bb.is_empty() || bb.contains(points_data[currIdx][0] ,points_data[currIdx][1] ,points_data[currIdx][2]) )
144 {
145
146 //float prob = 0.0f;
147 float prob = points_data[currIdx][3]; // during extractPointCloud process the prob of this point should be saved in this field
148 // that process actually also checks whether the prob is below threshold and marks this field as -1.0
149
150 if (prob >= prob_t)
151 {
152
153 vnl_vector_fixed<double, 3> axes;
154 //vnl_vector_fixed<double, 3> eval;
155 double LE, CE, exp_color;
156 //if (!calculateProbOfPoint(scene, blk, points_data[currIdx], covs_data[currIdx], alpha_data[currIdx], prob, exp_color, axes, LE, CE))
157 // continue;
158 if (!calculateLECEofPoint(covs_data[currIdx], axes, LE, CE))
159 continue;
160
161 if (LE >= LE_t || CE >= CE_t)
162 continue;
163
164 file << points_data[currIdx][0] << ' ' << points_data[currIdx][1] << ' ' << points_data[currIdx][2] << ' ';
165
166 if(datatype == boxm2_data_traits<BOXM2_MOG3_GREY>::prefix() )
167 {
168 auto * mog_data = (boxm2_data_traits<BOXM2_MOG3_GREY>::datatype*) mog->data_buffer();
169 exp_color = boxm2_processor_type<BOXM2_MOG3_GREY>::type::expected_color(mog_data[currIdx]);
170 int col = (int)(exp_color*255);
171 col = col > 255 ? 255 : col;
172 file << col << ' ' << col << ' ' << col << ' ';
173 }
174 else if ( datatype == boxm2_data_traits<BOXM2_GAUSS_RGB>::prefix() )
175 {
176 auto *color_data = (boxm2_data_traits<BOXM2_GAUSS_RGB>::datatype*) mog->data_buffer();
177 vnl_vector_fixed<float,3> exp_color = boxm2_processor_type<BOXM2_GAUSS_RGB>::type::expected_color(color_data[currIdx]);
178
179 int col0 = (int)(exp_color[0]*255);
180 col0 = col0 > 255 ? 255 : col0;
181 int col1 = (int)(exp_color[1]*255);
182 col1 = col1 > 255 ? 255 : col1;
183 int col2 = (int)(exp_color[2]*255);
184 col2 = col2 > 255 ? 255 : col2;
185 file << col0 << ' ' << col1 << ' ' << col2 << ' ';
186 }
187 else
188 {
189 file << 0 << ' ' << 0 << ' ' << 0 << ' ';
190 }
191 file << axes[0] << ' ' << axes[1] << ' ' << axes[2] << ' '
192 << LE << ' ' << CE << ' ' << prob << std::endl;
193 num_vertices++;
194 }
195 }
196 //}
197 }
198 }
exportColorPointCloudPLY(const boxm2_scene_sptr &,const boxm2_block_metadata &,boxm2_block *,boxm2_data_base * mog,boxm2_data_base * alpha,const std::string & datatype,boxm2_data_base * points,std::ofstream & file,float prob_t,vgl_box_3d<double> bb,unsigned & num_vertices)199 void boxm2_export_oriented_point_cloud_function::exportColorPointCloudPLY(const boxm2_scene_sptr& /*scene*/, const boxm2_block_metadata& /*data*/, boxm2_block* /*blk*/,
200 boxm2_data_base* mog, boxm2_data_base* alpha,const std::string& datatype ,
201 boxm2_data_base* points,std::ofstream& file,float prob_t,vgl_box_3d<double> bb, unsigned& num_vertices)
202 {
203 auto * points_data = (boxm2_data_traits<BOXM2_POINT>::datatype*) points->data_buffer();
204
205 auto * alpha_data = (boxm2_data_traits<BOXM2_ALPHA>::datatype*) alpha->data_buffer();
206 file << std::fixed;
207 int pointTypeSize = (int)boxm2_data_info::datasize(boxm2_data_traits<BOXM2_POINT>::prefix());
208 //check for invalid parameters
209 if( pointTypeSize == 0 ) //This should never happen, it will result in division by zero later
210 {
211 std::cerr << "ERROR: Division by 0 in " << __FILE__ << __LINE__ << std::endl;
212 throw 0;
213 }
214 for (unsigned currIdx=0; currIdx < (points->buffer_length()/pointTypeSize) ; currIdx++) {
215 float prob = points_data[currIdx][3]; // during extractPointCloud process the prob of this point should be saved in this field
216 // that process also checks whether the prob is below threshold and marks this field as -1.0
217 // the probability check should have already been done by ExtractPointCloud processes
218 //if (!calculateProbOfPoint(scene, blk, points_data[currIdx], alpha_data[currIdx], prob))
219 // continue;
220 if (prob >= prob_t)
221 {
222 //check bounding box
223 if (bb.is_empty() || bb.contains(points_data[currIdx][0] ,points_data[currIdx][1] ,points_data[currIdx][2]) )
224 {
225 file << points_data[currIdx][0] << ' ' << points_data[currIdx][1] << ' ' << points_data[currIdx][2] << ' ';
226
227 if(datatype == boxm2_data_traits<BOXM2_MOG3_GREY>::prefix() )
228 {
229 auto * mog_data = (boxm2_data_traits<BOXM2_MOG3_GREY>::datatype*) mog->data_buffer();
230 float exp_color = boxm2_processor_type<BOXM2_MOG3_GREY>::type::expected_color(mog_data[currIdx]);
231 int col = (int)(exp_color*255);
232 col = col > 255 ? 255 : col;
233 file << col << ' ' << col << ' ' << col;
234 }
235 else if ( datatype == boxm2_data_traits<BOXM2_GAUSS_RGB>::prefix() )
236 {
237 auto * color_data = (boxm2_data_traits<BOXM2_GAUSS_RGB>::datatype*) mog->data_buffer();
238 vnl_vector_fixed<float,3> exp_color = boxm2_processor_type<BOXM2_GAUSS_RGB>::type::expected_color(color_data[currIdx]);
239
240 int col0 = (int)(exp_color[0]*255);
241 col0 = col0 > 255 ? 255 : col0;
242 int col1 = (int)(exp_color[1]*255);
243 col1 = col1 > 255 ? 255 : col1;
244 int col2 = (int)(exp_color[2]*255);
245 col2 = col2 > 255 ? 255 : col2;
246 file << col0 << ' ' << col1 << ' ' << col2;
247
248 }
249 else{
250 file << 0 << ' ' << 0 << ' ' << 0;
251 }
252
253 file << ' ' << prob << ' ' <<"\n";
254
255 num_vertices++;
256 }
257 }
258 }
259 }
calculateProbOfPoint(const boxm2_scene_sptr & scene,boxm2_block * blk,const vnl_vector_fixed<float,4> & point,const vnl_vector_fixed<float,9> & cov,const float & alpha,float & prob,double &,vnl_vector_fixed<double,3> & axes,double & LE,double & CE)260 bool boxm2_export_oriented_point_cloud_function::calculateProbOfPoint(const boxm2_scene_sptr& scene, boxm2_block * blk,
261 const vnl_vector_fixed<float, 4>& point,
262 const vnl_vector_fixed<float, 9>& cov,
263 const float& alpha,
264 float& prob, double& /*color*/, vnl_vector_fixed<double, 3>& axes, double& LE, double& CE)
265 {
266 boxm2_block_id id;
267
268 vgl_point_3d<double> vgl_point(point[0],point[1],point[2]);
269
270 //the following method checks whether the scene contains the point or not
271 if (!calculateProbOfPoint(scene, blk, point, alpha, prob))
272 return false;
273
274 if (!calculateLECEofPoint(cov, axes, LE, CE))
275 return false;
276
277 return true;
278 }
279
calculateLECEofPoint(const vnl_vector_fixed<float,9> & cov,vnl_vector_fixed<double,3> & axes,double & LE,double & CE)280 bool boxm2_export_oriented_point_cloud_function::calculateLECEofPoint(const vnl_vector_fixed<float, 9>& cov,
281 vnl_vector_fixed<double, 3>&axes, double& LE, double& CE)
282 {
283 if (vnl_math::isinf(cov[0]) || vnl_math::isnan(cov[0])) // the covariance matrices with such values cause problems for eigen value calculation, skip these points!
284 // if the covariance has invalid values, then over or under flows might have happened during cov computation using float point precision
285 // ideally we should switch to double point precision during covariance calculations
286 return false;
287
288 // compute the eigenvalues
289 vnl_matrix<double> pt_cov(3,3,0.0);
290 pt_cov[0][0] = cov[0];
291 pt_cov[0][1] = cov[1];
292 pt_cov[0][2] = cov[2];
293
294 pt_cov[1][0] = cov[3];
295 pt_cov[1][1] = cov[4];
296 pt_cov[1][2] = cov[5];
297
298 pt_cov[2][0] = cov[6];
299 pt_cov[2][1] = cov[7];
300 pt_cov[2][2] = cov[8];
301
302 vnl_matrix<double> V(3,3,0.0); vnl_vector<double> eigs(3);
303 if (!vnl_symmetric_eigensystem_compute(pt_cov, V, eigs))
304 return false;
305
306 // place from the longest axis to the shortest, largest eigen value is in eigs[2]
307 axes[0] =2*std::sqrt(eigs[2])*2.5; // to find 90% confidence ellipsoid, scale the eigenvalues, see pg. 416 on Intro To Modern Photogrammetry, Mikhail, et. al.
308 axes[1] =2*std::sqrt(eigs[1])*2.5;
309 axes[2] =2*std::sqrt(eigs[0])*2.5;
310 // check if values are valid (AND is the only way to detect invalid value, do not change into ORs
311 if (!(axes[0] < std::numeric_limits<double>::max() && axes[0] > std::numeric_limits<double>::min() &&
312 axes[1] < std::numeric_limits<double>::max() && axes[1] > std::numeric_limits<double>::min() &&
313 axes[2] < std::numeric_limits<double>::max() && axes[2] > std::numeric_limits<double>::min()))
314 return false;
315
316 // now find LE (vertical error) using the eigenvector that corresponds to major axis
317 vnl_vector<double> major = V.get_column(2);
318
319 // create the vector that corresponds to error ellipsoid
320 vnl_vector<double> major_ellipsoid = axes[0]*major;
321
322
323 LE = std::abs(major_ellipsoid.get(2));
324 double CEx = std::abs(major_ellipsoid.get(0));
325 double CEy = std::abs(major_ellipsoid.get(1));
326
327 CE = CEx > CEy ? CEx : CEy;
328
329 return true;
330 }
331
calculateProbOfPoint(const boxm2_scene_sptr & scene,boxm2_block * blk,const vnl_vector_fixed<float,4> & point,const float & alpha,float & prob)332 bool boxm2_export_oriented_point_cloud_function::calculateProbOfPoint(const boxm2_scene_sptr& scene, boxm2_block * blk,
333 const vnl_vector_fixed<float, 4>& point,
334 const float& alpha, float& prob)
335 {
336 vgl_point_3d<double> local;
337 boxm2_block_id id;
338 vgl_point_3d<double> vgl_point(point[0],point[1],point[2]);
339 //boxm2_block_id id = blk->block_id();
340 //if (!scene->block_contains(vgl_point, id, local))
341 // return false;
342
343 //if the scene doesn't contain point,
344 if (!scene->contains(vgl_point, id, local)) {
345 return false;
346 }
347 //if the block passed isn't the block that contains the point, there is something wrong...
348 //this happens when the point data is empty (0,0,0,0) for instance, or simply wrong.
349 /*if (blk->block_id() != id)
350 return false;
351 */
352 int index_x=(int)std::floor(local.x());
353 int index_y=(int)std::floor(local.y());
354 int index_z=(int)std::floor(local.z());
355
356 boxm2_block_metadata mdata = scene->get_block_metadata_const(id);
357 vnl_vector_fixed<unsigned char,16> treebits=blk->trees()(index_x,index_y,index_z);
358 boct_bit_tree tree(treebits.data_block(),mdata.max_level_);
359 int bit_index=tree.traverse(local);
360 int depth=tree.depth_at(bit_index);
361 auto side_len=static_cast<float>(mdata.sub_block_dim_.x()/((float)(1<<depth)));
362
363 prob=1.0f-std::exp(-alpha*side_len);
364 return true;
365 }
366
writePLYHeader(std::ofstream & file,unsigned num_vertices,std::stringstream & ss,bool output_aux)367 void boxm2_export_oriented_point_cloud_function::writePLYHeader(std::ofstream& file, unsigned num_vertices,std::stringstream& ss, bool output_aux)
368 {
369 file << "ply\nformat ascii 1.0\nelement vertex " << num_vertices;
370 file << "\nproperty float32 x\nproperty float32 y\nproperty float32 z";
371 if (output_aux) {
372 //file << "\nproperty float x\nproperty float y\nproperty float z\nproperty float nx\nproperty float ny\nproperty float nz\n" << "property float prob\nproperty float vis_score\n";
373 file << "\nproperty float nx\nproperty float ny\nproperty float nz\n" << "property float prob\nproperty float vis_score\nproperty float nmag";
374 }
375 file << "\nend_header\n"
376 << ss.str();
377 }
378
writePLYHeaderOnlyPoints(std::ofstream & file,unsigned num_vertices,std::stringstream & ss)379 void boxm2_export_oriented_point_cloud_function::writePLYHeaderOnlyPoints(std::ofstream& file, unsigned num_vertices, std::stringstream& ss)
380 {
381 file << "ply\nformat ascii 1.0\nelement vertex " << num_vertices
382 << "\nproperty float x\nproperty float y\nproperty float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\n"
383 << "property float axes_a\nproperty float axes_b\nproperty float axes_c\n"
384 // << "property float eval_x\nproperty float eval_y\nproperty eval_z\n"
385 << "property float le\nproperty float ce\n"
386 << "property float prob\n"
387 << "end_header\n"
388 << ss.str();
389 }
390
391 //helper class to read in bb from file
392 class ply_bb_reader
393 {
394 public:
395 vgl_box_3d<double> bbox;
396 double p[3];
397 std::vector<int > vertex_indices;
398 };
399
400
401 //: Call-back function for a "vertex" element
boxm2_plyio_vertex_cb(p_ply_argument argument)402 int boxm2_plyio_vertex_cb(p_ply_argument argument)
403 {
404 long index;
405 void* temp;
406 ply_get_argument_user_data(argument, &temp, &index);
407
408 auto* parsed_ply = (ply_bb_reader*) temp;
409
410 switch (index)
411 {
412 case 0: // "x" coordinate
413 parsed_ply->p[0] = ply_get_argument_value(argument);
414 break;
415 case 1: // "y" coordinate
416 parsed_ply->p[1] = ply_get_argument_value(argument);
417 break;
418 case 2: // "z" coordinate
419 parsed_ply->p[2] = ply_get_argument_value(argument);
420 // INSERT VERTEX INTO THE MESH
421 parsed_ply->bbox.add(vgl_point_3d<double>(parsed_ply->p));
422 break;
423 default:
424 assert(!"This should not happen: index out of range");
425 }
426 return 1;
427 }
428
429
readBBFromPLY(const std::string & filename,vgl_box_3d<double> & box)430 void boxm2_export_oriented_point_cloud_function::readBBFromPLY(const std::string& filename, vgl_box_3d<double>& box)
431 {
432 ply_bb_reader parsed_ply;
433 parsed_ply.bbox = box;
434
435 p_ply ply = ply_open(filename.c_str(), nullptr, 0, nullptr);
436 if (!ply) {
437 std::cout << "File " << filename << " doesn't exist.";
438 }
439 if (!ply_read_header(ply))
440 std::cout << "File " << filename << " doesn't have header.";
441
442 // vertex
443 ply_set_read_cb(ply, "vertex", "x", boxm2_plyio_vertex_cb, (void*) (&parsed_ply), 0);
444 ply_set_read_cb(ply, "vertex", "y", boxm2_plyio_vertex_cb, (void*) (&parsed_ply), 1);
445 ply_set_read_cb(ply, "vertex", "z", boxm2_plyio_vertex_cb, (void*) (&parsed_ply), 2);
446
447 // Read DATA
448 ply_read(ply);
449
450 // CLOSE file
451 ply_close(ply);
452
453 box=parsed_ply.bbox;
454 }
455