Main MRPT website > C++ reference for MRPT 1.9.9
PLY_import_export.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 /*
11  This file is heavily based on the RPly C library by Greg Turk (February 1994)
12  It was modified, C++'ized and STL'ized by J.L.Blanco for MRPT (Jan-Feb 2011)
13 
14  Below follows the original copyright notes by Greg Turk:
15  ======================================================================
16 The interface routines for reading and writing PLY polygon files.
17 
18 Greg Turk, February 1994
19 
20 ---------------------------------------------------------------
21 
22 A PLY file contains a single polygonal _object_.
23 
24 An object is composed of lists of _elements_. Typical elements are
25 vertices, faces, edges and materials.
26 
27 Each type of element for a given object has one or more _properties_
28 associated with the element type. For instance, a vertex element may
29 have as properties the floating-point values x,y,z and the three unsigned
30 chars representing red, green and blue.
31 
32 ---------------------------------------------------------------
33 
34 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
35 Junior University. All rights reserved.
36 
37 Permission to use, copy, modify and distribute this software and its
38 documentation for any purpose is hereby granted without fee, provided
39 that the above copyright notice and this permission notice appear in
40 all copies of this software and that you do not sell the software.
41 
42 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
43 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
44 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
45 
46 */
47 
48 #include "base-precomp.h" // Precompiled headers
49 
52 #include <stdio.h>
53 
54 using namespace std;
55 using namespace mrpt;
56 using namespace mrpt::utils;
57 using namespace mrpt::math;
58 
59 #define PLY_ASCII 1 /* ascii PLY file */
60 #define PLY_BINARY_BE 2 /* binary PLY file, big endian */
61 #define PLY_BINARY_LE 3 /* binary PLY file, little endian */
62 
63 //#define PLY_OKAY 0 /* ply routine worked okay */
64 //#define PLY_ERROR -1 /* error in ply routine */
65 
66 /* scalar data types supported by PLY format */
67 
68 enum
69 {
71  PLY_CHAR = 1,
72  PLY_SHORT = 2,
73  PLY_INT = 3,
74  PLY_UCHAR = 4,
76  PLY_UINT = 6,
77  PLY_FLOAT = 7,
80 };
81 
82 //#define PLY_SCALAR 0
83 //#define PLY_LIST 1
84 
85 const int NO_OTHER_PROPS = -1;
86 
87 const char DONT_STORE_PROP = 0;
88 const char STORE_PROP = 1;
89 
90 const char OTHER_PROP = 0;
91 const char NAMED_PROP = 1;
92 
93 typedef struct PlyProperty
94 { /* description of a property */
95 
96  std::string name; /* property name */
97  int external_type; /* file's data type */
98  int internal_type; /* program's data type */
99  int offset; /* offset bytes of prop in a struct */
100 
101  int is_list; /* 1 = list, 0 = scalar */
102  int count_external; /* file's count type */
103  int count_internal; /* program's count type */
104  int count_offset; /* offset byte for list count */
105 
106 } PlyProperty;
107 
108 typedef struct PlyElement
109 { /* description of an element */
110  PlyElement() : num(0), size(0), other_offset(NO_OTHER_PROPS) {}
111  string name; /* element name */
112  int num; /* number of elements in this object */
113  int size; /* size of element (bytes) or -1 if variable */
114  vector<PlyProperty> props; /* list of properties in the file */
115  vector<char> store_prop; /* flags: property wanted by user? */
116  int other_offset; /* offset to un-asked-for props, or -1 if none*/
117  int other_size; /* size of other_props structure */
118 } PlyElement;
119 
120 struct PlyFile
121 { /* description of PLY file */
122  PlyFile(FILE* _fp = nullptr)
123  : fp(_fp), file_type(0), version(0), which_elem(nullptr)
124  {
125  }
126 
127  FILE* fp; /* file pointer */
128  int file_type; /* ascii or binary */
129  float version; /* version number of file */
130  vector<PlyElement> elems; /* list of elements */
131  vector<string> comments; /* list of comments */
132  vector<string> obj_info; /* list of object info items */
133  PlyElement* which_elem; /* which element we're currently writing */
134 };
135 
137  string("invalid"), string("char"), string("short"),
138  string("int"), string("uchar"), string("ushort"),
139  string("uint"), string("float"), string("double"),
140 };
141 const int ply_type_size[] = {0, 1, 2, 4, 1, 2, 4, 4, 8};
142 
143 /* find an element in a plyfile's list */
145 
146 /* find a property in an element's list */
148 
149 /* write to a file the word describing a PLY file data type */
150 void write_scalar_type(FILE*, int);
151 
152 /* read a line from a file and break it up into separate words */
153 vector<string> get_words(FILE*, string&);
154 
155 /* write an item to a file */
156 void write_binary_item(FILE*, int, unsigned int, double, int);
157 void write_ascii_item(FILE*, int, unsigned int, double, int);
158 
159 /* add information to a PLY file descriptor */
160 void add_element(PlyFile*, const vector<string>&);
161 void add_property(PlyFile*, const vector<string>&);
162 void add_comment(PlyFile*, const string&);
163 void add_obj_info(PlyFile*, const string&);
164 
165 /* copy a property */
166 void copy_property(PlyProperty*, const PlyProperty*);
167 
168 /* store a value into where a pointer and a type specify */
169 void store_item(char*, int, int, unsigned int, double);
170 
171 /* return the value of a stored item */
172 void get_stored_item(void*, int, int*, unsigned int*, double*);
173 
174 /* return the value stored in an item, given ptr to it and its type */
175 double get_item_value(const char*, int);
176 
177 /* get binary or ascii item and store it according to ptr and type */
178 void get_ascii_item(const char*, int, int*, unsigned int*, double*);
179 int get_binary_item(
180  FILE*, int, int, int*, unsigned int*, double*); // return 0 on error
181 
182 /* get a bunch of elements from a file */
183 void ascii_get_element(PlyFile*, char*);
184 void binary_get_element(PlyFile*, char*);
185 
186 /*************/
187 /* Writing */
188 /*************/
189 
190 /******************************************************************************
191 Given a file pointer, get ready to write PLY data to the file.
192 
193 Entry:
194  fp - the given file pointer
195  nelems - number of elements in object
196  elem_names - list of element names
197  file_type - file type, either ascii or binary
198 
199 Exit:
200  returns a pointer to a PlyFile, used to refer to this file, or nullptr if
201 error
202 ******************************************************************************/
203 
204 PlyFile* ply_write(FILE* fp, const vector<string>& elem_names, int file_type)
205 {
206  /* check for nullptr file pointer */
207  if (fp == nullptr) return (nullptr);
208 
209  /* create a record for this object */
210  PlyFile* plyfile = new PlyFile(fp);
211 
212  plyfile->file_type = file_type;
213  plyfile->version = 1.0;
214  // plyfile->other_elems = nullptr;
215 
216  /* tuck aside the names of the elements */
217 
218  plyfile->elems.resize(elem_names.size());
219  for (size_t i = 0; i < elem_names.size(); i++)
220  {
221  plyfile->elems[i].name = elem_names[i];
222  }
223 
224  /* return pointer to the file descriptor */
225  return (plyfile);
226 }
227 
228 /******************************************************************************
229 Open a polygon file for writing.
230 
231 Entry:
232  filename - name of file to read from
233  nelems - number of elements in object
234  elem_names - list of element names
235  file_type - file type, either ascii or binary
236 
237 Exit:
238  version - version number of PLY file
239  returns a file identifier, used to refer to this file, or nullptr if error
240 ******************************************************************************/
241 
243  const char* name, const vector<string>& elem_names, int file_type,
244  float* version)
245 {
246  PlyFile* plyfile;
247  FILE* fp;
248 
249  /* open the file for writing */
250 
251  fp = fopen(name, "w");
252  if (fp == nullptr)
253  {
254  return (nullptr);
255  }
256 
257  /* create the actual PlyFile structure */
258 
259  plyfile = ply_write(fp, elem_names, file_type);
260  if (plyfile == nullptr) return (nullptr);
261 
262  /* say what PLY file version number we're writing */
263  *version = plyfile->version;
264 
265  /* return pointer to the file descriptor */
266  return (plyfile);
267 }
268 
269 /******************************************************************************
270 Describe an element, including its properties and how many will be written
271 to the file.
272 
273 Entry:
274  plyfile - file identifier
275  elem_name - name of element that information is being specified about
276  nelems - number of elements of this type to be written
277  nprops - number of properties contained in the element
278  prop_list - list of properties
279 ******************************************************************************/
280 
282  PlyFile* plyfile, const string& elem_name, int nelems,
283  vector<PlyProperty>& prop_list)
284 {
285  /* look for appropriate element */
286  PlyElement* elem = find_element(plyfile, elem_name);
287  if (elem == nullptr)
288  throw std::runtime_error(
289  format(
290  "ply_describe_element: can't find element '%s'",
291  elem_name.c_str()));
292 
293  elem->num = nelems;
294 
295  /* copy the list of properties */
296 
297  const size_t nprops = prop_list.size();
298  elem->props.resize(nprops);
299  elem->store_prop.resize(nprops);
300 
301  for (size_t i = 0; i < nprops; i++)
302  {
303  elem->props[i] = prop_list[i];
304  elem->store_prop[i] = NAMED_PROP;
305  }
306 }
307 
308 /******************************************************************************
309 Describe a property of an element.
310 
311 Entry:
312  plyfile - file identifier
313  elem_name - name of element that information is being specified about
314  prop - the new property
315 ******************************************************************************/
316 
318  PlyFile* plyfile, const char* elem_name, const PlyProperty* prop)
319 {
320  /* look for appropriate element */
321  PlyElement* elem = find_element(plyfile, elem_name);
322  if (elem == nullptr)
323  {
324  fprintf(
325  stderr, "ply_describe_property: can't find element '%s'\n",
326  elem_name);
327  return;
328  }
329 
330  /* copy the new property */
331  elem->props.push_back(*prop);
332  elem->store_prop.push_back(NAMED_PROP);
333 }
334 
335 /******************************************************************************
336 State how many of a given element will be written.
337 
338 Entry:
339  plyfile - file identifier
340  elem_name - name of element that information is being specified about
341  nelems - number of elements of this type to be written
342 ******************************************************************************/
343 
344 void ply_element_count(PlyFile* plyfile, const string& elem_name, int nelems)
345 {
346  // int i;
347  PlyElement* elem;
348  // PlyProperty *prop;
349 
350  /* look for appropriate element */
351  elem = find_element(plyfile, elem_name);
352  if (elem == nullptr)
353  throw std::runtime_error(
354  format(
355  "ply_element_count: can't find element '%s'",
356  elem_name.c_str()));
357 
358  elem->num = nelems;
359 }
360 
361 /******************************************************************************
362 Signal that we've described everything a PLY file's header and that the
363 header should be written to the file.
364 
365 Entry:
366  plyfile - file identifier
367 ******************************************************************************/
368 
370 {
371  FILE* fp = plyfile->fp;
372 
373  fprintf(fp, "ply\n");
374 
375  switch (plyfile->file_type)
376  {
377  case PLY_ASCII:
378  fprintf(fp, "format ascii 1.0\n");
379  break;
380  case PLY_BINARY_BE:
381  fprintf(fp, "format binary_big_endian 1.0\n");
382  break;
383  case PLY_BINARY_LE:
384  fprintf(fp, "format binary_little_endian 1.0\n");
385  break;
386  default:
387  throw std::runtime_error(
388  format(
389  "ply_header_complete: bad file type = %d",
390  plyfile->file_type));
391  }
392 
393  /* write out the comments */
394 
395  for (size_t i = 0; i < plyfile->comments.size(); i++)
396  fprintf(fp, "comment %s\n", plyfile->comments[i].c_str());
397 
398  /* write out object information */
399 
400  for (size_t i = 0; i < plyfile->obj_info.size(); i++)
401  fprintf(fp, "obj_info %s\n", plyfile->obj_info[i].c_str());
402 
403  /* write out information about each element */
404 
405  for (size_t i = 0; i < plyfile->elems.size(); i++)
406  {
407  const PlyElement* elem = &plyfile->elems[i];
408  fprintf(fp, "element %s %d\n", elem->name.c_str(), elem->num);
409 
410  /* write out each property */
411  for (size_t j = 0; j < elem->props.size(); j++)
412  {
413  const PlyProperty* prop = &elem->props[j];
414  if (prop->is_list)
415  {
416  fprintf(fp, "property list ");
418  fprintf(fp, " ");
419  write_scalar_type(fp, prop->external_type);
420  fprintf(fp, " %s\n", prop->name.c_str());
421  }
422  else
423  {
424  fprintf(fp, "property ");
425  write_scalar_type(fp, prop->external_type);
426  fprintf(fp, " %s\n", prop->name.c_str());
427  }
428  }
429  }
430 
431  fprintf(fp, "end_header\n");
432 }
433 
434 /******************************************************************************
435 Specify which elements are going to be written. This should be called
436 before a call to the routine ply_put_element().
437 
438 Entry:
439  plyfile - file identifier
440  elem_name - name of element we're talking about
441 ******************************************************************************/
442 
443 void ply_put_element_setup(PlyFile* plyfile, const string& elem_name)
444 {
445  PlyElement* elem;
446 
447  elem = find_element(plyfile, elem_name);
448  if (elem == nullptr)
449  throw std::runtime_error(
450  format(
451  "ply_elements_setup: can't find element '%s'",
452  elem_name.c_str()));
453 
454  plyfile->which_elem = elem;
455 }
456 
457 /******************************************************************************
458 Write an element to the file. This routine assumes that we're
459 writing the type of element specified in the last call to the routine
460 ply_put_element_setup().
461 
462 Entry:
463  plyfile - file identifier
464  elem_ptr - pointer to the element
465 ******************************************************************************/
466 
467 void ply_put_element(PlyFile* plyfile, void* elem_ptr)
468 {
469  FILE* fp = plyfile->fp;
470  char *elem_data, *item;
471  char** item_ptr;
472  int item_size;
473  int int_val;
474  unsigned int uint_val;
475  double double_val;
476  char** other_ptr;
477 
478  PlyElement* elem = plyfile->which_elem;
479  elem_data = (char*)elem_ptr;
480  other_ptr = (char**)(((char*)elem_ptr) + elem->other_offset);
481 
482  /* write out either to an ascii or binary file */
483 
484  if (plyfile->file_type == PLY_ASCII)
485  {
486  /* write an ascii file */
487 
488  /* write out each property of the element */
489  for (size_t j = 0; j < elem->props.size(); j++)
490  {
491  const PlyProperty* prop = &elem->props[j];
492  if (elem->store_prop[j] == OTHER_PROP)
493  elem_data = *other_ptr;
494  else
495  elem_data = (char*)elem_ptr;
496  if (prop->is_list)
497  {
498  item = elem_data + prop->count_offset;
500  (void*)item, prop->count_internal, &int_val, &uint_val,
501  &double_val);
503  fp, int_val, uint_val, double_val, prop->count_external);
504  const size_t list_count = uint_val;
505  item_ptr = (char**)(elem_data + prop->offset);
506  item = item_ptr[0];
507  item_size = ply_type_size[prop->internal_type];
508  for (size_t k = 0; k < list_count; k++)
509  {
511  (void*)item, prop->internal_type, &int_val, &uint_val,
512  &double_val);
514  fp, int_val, uint_val, double_val, prop->external_type);
515  item += item_size;
516  }
517  }
518  else
519  {
520  item = elem_data + prop->offset;
522  (void*)item, prop->internal_type, &int_val, &uint_val,
523  &double_val);
525  fp, int_val, uint_val, double_val, prop->external_type);
526  }
527  }
528 
529  fprintf(fp, "\n");
530  }
531  else
532  {
533  /* write a binary file */
534 
535  /* write out each property of the element */
536  for (size_t j = 0; j < elem->props.size(); j++)
537  {
538  const PlyProperty* prop = &elem->props[j];
539  if (elem->store_prop[j] == OTHER_PROP)
540  elem_data = *other_ptr;
541  else
542  elem_data = (char*)elem_ptr;
543  if (prop->is_list)
544  {
545  item = elem_data + prop->count_offset;
546  item_size = ply_type_size[prop->count_internal];
548  (void*)item, prop->count_internal, &int_val, &uint_val,
549  &double_val);
551  fp, int_val, uint_val, double_val, prop->count_external);
552  const size_t list_count = uint_val;
553  item_ptr = (char**)(elem_data + prop->offset);
554  item = item_ptr[0];
555  item_size = ply_type_size[prop->internal_type];
556  for (size_t k = 0; k < list_count; k++)
557  {
559  (void*)item, prop->internal_type, &int_val, &uint_val,
560  &double_val);
562  fp, int_val, uint_val, double_val, prop->external_type);
563  item += item_size;
564  }
565  }
566  else
567  {
568  item = elem_data + prop->offset;
569  item_size = ply_type_size[prop->internal_type];
571  (void*)item, prop->internal_type, &int_val, &uint_val,
572  &double_val);
574  fp, int_val, uint_val, double_val, prop->external_type);
575  }
576  }
577  }
578 }
579 
580 /******************************************************************************
581 Specify a comment that will be written in the header.
582 
583 Entry:
584  plyfile - file identifier
585  comment - the comment to be written
586 ******************************************************************************/
587 
588 void ply_put_comment(PlyFile* plyfile, const string& comment)
589 {
590  plyfile->comments.push_back(comment);
591 }
592 
593 /******************************************************************************
594 Specify a piece of object information (arbitrary text) that will be written
595 in the header.
596 
597 Entry:
598  plyfile - file identifier
599  obj_info - the text information to be written
600 ******************************************************************************/
601 
602 void ply_put_obj_info(PlyFile* plyfile, const string& obj_info)
603 {
604  plyfile->obj_info.push_back(obj_info);
605 }
606 
607 /*************/
608 /* Reading */
609 /*************/
610 
611 /******************************************************************************
612 Given a file pointer, get ready to read PLY data from the file.
613 
614 Entry:
615  fp - the given file pointer
616 
617 Exit:
618  nelems - number of elements in object
619  elem_names - list of element names
620  returns a pointer to a PlyFile, used to refer to this file, or nullptr if
621 error
622 ******************************************************************************/
623 
624 PlyFile* ply_read(FILE* fp, vector<string>& elem_names)
625 {
626  // int found_format = 0;
627 
628  /* check for nullptr file pointer */
629  if (fp == nullptr) return (nullptr);
630 
631  /* create record for this object */
632  PlyFile* plyfile = new PlyFile(fp);
633 
634  /* read and parse the file's header */
635  string orig_line;
636  vector<string> words = get_words(plyfile->fp, orig_line);
637 
638  if (words.empty() || words[0] != "ply") return nullptr;
639 
640  while (!words.empty())
641  {
642  /* parse words */
643 
644  if (words[0] == "format")
645  {
646  if (words.size() != 3) return (nullptr);
647  if (words[1] == "ascii")
648  plyfile->file_type = PLY_ASCII;
649  else if (words[1] == "binary_big_endian")
650  plyfile->file_type = PLY_BINARY_BE;
651  else if (words[1] == "binary_little_endian")
652  plyfile->file_type = PLY_BINARY_LE;
653  else
654  return (nullptr);
655  plyfile->version = atof(words[2].c_str());
656  // found_format = 1;
657  }
658  else if (words[0] == "element")
659  add_element(plyfile, words);
660  else if (words[0] == "property")
661  add_property(plyfile, words);
662  else if (words[0] == "comment")
663  add_comment(plyfile, orig_line);
664  else if (words[0] == "obj_info")
665  add_obj_info(plyfile, orig_line);
666  else if (words[0] == "end_header")
667  break;
668 
669  words = get_words(plyfile->fp, orig_line);
670  }
671 
672  /* create tags for each property of each element, to be used */
673  /* later to say whether or not to store each property for the user */
674 
675  for (size_t i = 0; i < plyfile->elems.size(); i++)
676  {
677  PlyElement* elem = &plyfile->elems[i];
678 
679  elem->store_prop.assign(elem->props.size(), DONT_STORE_PROP);
680  elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
681  }
682 
683  /* set return values about the elements */
684  elem_names.clear();
685  for (size_t i = 0; i < plyfile->elems.size(); i++)
686  elem_names.push_back(plyfile->elems[i].name);
687 
688  /* return a pointer to the file's information */
689 
690  return (plyfile);
691 }
692 
693 /******************************************************************************
694 Open a polygon file for reading.
695 
696 Entry:
697  filename - name of file to read from
698 
699 Exit:
700  nelems - number of elements in object
701  elem_names - list of element names
702  file_type - file type, either ascii or binary
703  version - version number of PLY file
704  returns a file identifier, used to refer to this file, or nullptr if error
705 ******************************************************************************/
706 
708  const char* filename, vector<string>& elem_names, int* file_type,
709  float* version)
710 {
711  FILE* fp;
712  PlyFile* plyfile;
713 
714  /* open the file for reading */
715 
716  fp = fopen(filename, "r");
717  if (fp == nullptr) return (nullptr);
718 
719  /* create the PlyFile data structure */
720 
721  plyfile = ply_read(fp, elem_names);
722 
723  /* determine the file type and version */
724  if (plyfile)
725  {
726  *file_type = plyfile->file_type;
727  *version = plyfile->version;
728  }
729 
730  /* return a pointer to the file's information */
731 
732  return (plyfile);
733 }
734 
735 /******************************************************************************
736 Get information about a particular element.
737 
738 Entry:
739  plyfile - file identifier
740  elem_name - name of element to get information about
741 
742 Exit:
743  nelems - number of elements of this type in the file
744  nprops - number of properties
745  returns a list of properties, or nullptr if the file doesn't contain that elem
746 ******************************************************************************/
747 
748 vector<PlyProperty> ply_get_element_description(
749  PlyFile* plyfile, const string& elem_name, int& nelems, int& nprops)
750 {
751  /* find information about the element */
752  PlyElement* elem = find_element(plyfile, elem_name);
753  if (elem == nullptr) return vector<PlyProperty>();
754 
755  nelems = elem->num;
756  nprops = elem->props.size();
757 
758  /* make a copy of the element's property list */
759  return elem->props;
760 }
761 
762 /******************************************************************************
763 Specify a property of an element that is to be returned. This should be
764 called (usually multiple times) before a call to the routine ply_get_element().
765 This routine should be used in preference to the less flexible old routine
766 called ply_get_element_setup().
767 
768 Entry:
769  plyfile - file identifier
770  elem_name - which element we're talking about
771  prop - property to add to those that will be returned
772 ******************************************************************************/
773 
775  PlyFile* plyfile, const string& elem_name, const PlyProperty* prop)
776 {
777  PlyElement* elem;
778  PlyProperty* prop_ptr;
779  int index;
780 
781  /* find information about the element */
782  elem = find_element(plyfile, elem_name);
783  plyfile->which_elem = elem;
784 
785  /* deposit the property information into the element's description */
786 
787  prop_ptr = find_property(elem, prop->name, &index);
788  if (prop_ptr == nullptr)
789  {
790  fprintf(
791  stderr, "Warning: Can't find property '%s' in element '%s'\n",
792  prop->name.c_str(), elem_name.c_str());
793  return;
794  }
795  prop_ptr->internal_type = prop->internal_type;
796  prop_ptr->offset = prop->offset;
797  prop_ptr->count_internal = prop->count_internal;
798  prop_ptr->count_offset = prop->count_offset;
799 
800  /* specify that the user wants this property */
801  elem->store_prop[index] = STORE_PROP;
802 }
803 
804 /******************************************************************************
805 Read one element from the file. This routine assumes that we're reading
806 the type of element specified in the last call to the routine
807 ply_get_element_setup().
808 
809 Entry:
810  plyfile - file identifier
811  elem_ptr - pointer to location where the element information should be put
812 ******************************************************************************/
813 
814 void ply_get_element(PlyFile* plyfile, void* elem_ptr)
815 {
816  if (plyfile->file_type == PLY_ASCII)
817  ascii_get_element(plyfile, (char*)elem_ptr);
818  else
819  binary_get_element(plyfile, (char*)elem_ptr);
820 }
821 
822 /******************************************************************************
823 Extract the comments from the header information of a PLY file.
824 
825 Entry:
826  plyfile - file identifier
827 
828 Exit:
829  num_comments - number of comments returned
830  returns a pointer to a list of comments
831 ******************************************************************************/
832 
833 void ply_get_comments(PlyFile* plyfile, vector<string>& comments)
834 {
835  comments = plyfile->comments;
836 }
837 
838 /******************************************************************************
839 Extract the object information (arbitrary text) from the header information
840 of a PLY file.
841 
842 Entry:
843  plyfile - file identifier
844 
845 Exit:
846  num_obj_info - number of lines of text information returned
847  returns a pointer to a list of object info lines
848 ******************************************************************************/
849 
850 void ply_get_obj_info(PlyFile* plyfile, vector<string>& obj_info)
851 {
852  obj_info = plyfile->obj_info;
853 }
854 
855 /*******************/
856 /* Miscellaneous */
857 /*******************/
858 
859 /******************************************************************************
860 Close a PLY file.
861 
862 Entry:
863  plyfile - identifier of file to close
864 ******************************************************************************/
865 
866 void ply_close(PlyFile* plyfile)
867 {
868  fclose(plyfile->fp);
869 
870  /* free up memory associated with the PLY file */
871  delete plyfile;
872 }
873 
874 /******************************************************************************
875 Get version number and file type of a PlyFile.
876 
877 Entry:
878  ply - pointer to PLY file
879 
880 Exit:
881  version - version of the file
882  file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
883 ******************************************************************************/
884 
885 void ply_get_info(PlyFile* ply, float* version, int* file_type)
886 {
887  if (ply == nullptr) return;
888 
889  *version = ply->version;
890  *file_type = ply->file_type;
891 }
892 
893 /******************************************************************************
894 Find an element from the element list of a given PLY object.
895 
896 Entry:
897  plyfile - file id for PLY file
898  element - name of element we're looking for
899 
900 Exit:
901  returns the element, or nullptr if not found
902 ******************************************************************************/
903 
904 PlyElement* find_element(PlyFile* plyfile, const string& element)
905 {
906  for (size_t i = 0; i < plyfile->elems.size(); i++)
907  if (element == plyfile->elems[i].name) return &plyfile->elems[i];
908 
909  return (nullptr);
910 }
911 
912 /******************************************************************************
913 Find a property in the list of properties of a given element.
914 
915 Entry:
916  elem - pointer to element in which we want to find the property
917  prop_name - name of property to find
918 
919 Exit:
920  index - index to position in list
921  returns a pointer to the property, or nullptr if not found
922 ******************************************************************************/
923 
925  PlyElement* elem, const std::string& prop_name, int* index)
926 {
927  for (size_t i = 0; i < elem->props.size(); i++)
928  if (string(prop_name) == elem->props[i].name)
929  {
930  *index = i;
931  return &elem->props[i];
932  }
933  *index = -1;
934  return (nullptr);
935 }
936 
937 /******************************************************************************
938 Read an element from an ascii file.
939 
940 Entry:
941  plyfile - file identifier
942  elem_ptr - pointer to element
943 ******************************************************************************/
944 
945 void ascii_get_element(PlyFile* plyfile, char* elem_ptr)
946 {
947  int which_word;
948  // FILE *fp = plyfile->fp;
949  char *elem_data, *item = nullptr;
950  char* item_ptr;
951  int item_size;
952  int int_val;
953  unsigned int uint_val;
954  double double_val;
955  int list_count;
956  int store_it;
957  char** store_array;
958  char* other_data = nullptr;
959  int other_flag;
960 
961  /* the kind of element we're reading currently */
962  PlyElement* elem = plyfile->which_elem;
963 
964  /* do we need to setup for other_props? */
965 
966  if (elem->other_offset != NO_OTHER_PROPS)
967  {
968  char** ptr;
969  other_flag = 1;
970  /* make room for other_props */
971  other_data = (char*)malloc(elem->other_size);
972  /* store pointer in user's structure to the other_props */
973  ptr = (char**)(elem_ptr + elem->other_offset);
974  *ptr = other_data;
975  }
976  else
977  other_flag = 0;
978 
979  /* read in the element */
980  string orig_line;
981  vector<string> words = get_words(plyfile->fp, orig_line);
982 
983  if (words.empty())
984  throw std::runtime_error(
985  format("ply_get_element: unexpected end of file"));
986 
987  which_word = 0;
988 
989  for (size_t j = 0; j < elem->props.size(); j++)
990  {
991  PlyProperty* prop = &elem->props[j];
992  store_it = (elem->store_prop[j] | other_flag);
993 
994  /* store either in the user's structure or in other_props */
995  if (elem->store_prop[j])
996  elem_data = elem_ptr;
997  else
998  elem_data = other_data;
999 
1000  if (prop->is_list)
1001  { /* a list */
1002 
1003  /* get and store the number of items in the list */
1005  words[which_word++].c_str(), prop->count_external, &int_val,
1006  &uint_val, &double_val);
1007  if (store_it)
1008  {
1009  item = elem_data + prop->count_offset;
1010  store_item(
1011  item, prop->count_internal, int_val, uint_val, double_val);
1012  }
1013 
1014  /* allocate space for an array of items and store a ptr to the array
1015  */
1016  list_count = int_val;
1017  item_size = ply_type_size[prop->internal_type];
1018  store_array = (char**)(elem_data + prop->offset);
1019 
1020  if (list_count == 0)
1021  {
1022  if (store_it) *store_array = nullptr;
1023  }
1024  else
1025  {
1026  if (store_it)
1027  {
1028  item_ptr =
1029  (char*)malloc(sizeof(char) * item_size * list_count);
1030  item = item_ptr;
1031  *store_array = item_ptr;
1032  }
1033 
1034  /* read items and store them into the array */
1035  for (int k = 0; k < list_count; k++)
1036  {
1038  words[which_word++].c_str(), prop->external_type,
1039  &int_val, &uint_val, &double_val);
1040  if (store_it)
1041  {
1042  store_item(
1043  item, prop->internal_type, int_val, uint_val,
1044  double_val);
1045  item += item_size;
1046  }
1047  }
1048  }
1049  }
1050  else
1051  { /* not a list */
1053  words[which_word++].c_str(), prop->external_type, &int_val,
1054  &uint_val, &double_val);
1055  if (store_it)
1056  {
1057  item = elem_data + prop->offset;
1058  store_item(
1059  item, prop->internal_type, int_val, uint_val, double_val);
1060  }
1061  }
1062  }
1063 }
1064 
1065 /******************************************************************************
1066 Read an element from a binary file.
1067 
1068 Entry:
1069  plyfile - file identifier
1070  elem_ptr - pointer to an element
1071 ******************************************************************************/
1072 
1073 void binary_get_element(PlyFile* plyfile, char* elem_ptr)
1074 {
1075  FILE* fp = plyfile->fp;
1076  char *elem_data, *item = nullptr;
1077  char* item_ptr;
1078  int item_size = 0;
1079  int int_val;
1080  unsigned int uint_val;
1081  double double_val;
1082  int list_count;
1083  int store_it;
1084  char** store_array;
1085  char* other_data = nullptr;
1086  int other_flag;
1087 
1088  int bin_file_type = plyfile->file_type;
1089 
1090  /* the kind of element we're reading currently */
1091  PlyElement* elem = plyfile->which_elem;
1092 
1093  /* do we need to setup for other_props? */
1094 
1095  if (elem->other_offset != NO_OTHER_PROPS)
1096  {
1097  char** ptr;
1098  other_flag = 1;
1099  /* make room for other_props */
1100  other_data = (char*)malloc(elem->other_size);
1101  /* store pointer in user's structure to the other_props */
1102  ptr = (char**)(elem_ptr + elem->other_offset);
1103  *ptr = other_data;
1104  }
1105  else
1106  other_flag = 0;
1107 
1108  /* read in a number of elements */
1109 
1110  for (size_t j = 0; j < elem->props.size(); j++)
1111  {
1112  PlyProperty* prop = &elem->props[j];
1113  store_it = (elem->store_prop[j] | other_flag);
1114 
1115  /* store either in the user's structure or in other_props */
1116  if (elem->store_prop[j])
1117  elem_data = elem_ptr;
1118  else
1119  elem_data = other_data;
1120 
1121  if (prop->is_list)
1122  { /* a list */
1123 
1124  /* get and store the number of items in the list */
1125  if (!get_binary_item(
1126  fp, bin_file_type, prop->count_external, &int_val,
1127  &uint_val, &double_val))
1128  {
1129  // Error...
1130  fprintf(
1131  stderr,
1132  "RPly::binary_get_element: Error reading binary file!\n");
1133  }
1134 
1135  if (store_it)
1136  {
1137  item = elem_data + prop->count_offset;
1138  store_item(
1139  item, prop->count_internal, int_val, uint_val, double_val);
1140  }
1141 
1142  /* allocate space for an array of items and store a ptr to the array
1143  */
1144  list_count = int_val;
1145  /* The "if" was added by Afra Zomorodian 8/22/95
1146  * so that zipper won't crash reading plies that have additional
1147  * properties.
1148  */
1149  if (store_it)
1150  {
1151  item_size = ply_type_size[prop->internal_type];
1152  }
1153  store_array = (char**)(elem_data + prop->offset);
1154  if (list_count == 0)
1155  {
1156  if (store_it) *store_array = nullptr;
1157  }
1158  else
1159  {
1160  if (store_it)
1161  {
1162  item_ptr =
1163  (char*)malloc(sizeof(char) * item_size * list_count);
1164  item = item_ptr;
1165  *store_array = item_ptr;
1166  }
1167 
1168  /* read items and store them into the array */
1169  for (int k = 0; k < list_count; k++)
1170  {
1171  if (!get_binary_item(
1172  fp, bin_file_type, prop->external_type, &int_val,
1173  &uint_val, &double_val))
1174  {
1175  // Error...
1176  fprintf(
1177  stderr,
1178  "RPly::binary_get_element: Error reading binary "
1179  "file!\n");
1180  }
1181 
1182  if (store_it)
1183  {
1184  store_item(
1185  item, prop->internal_type, int_val, uint_val,
1186  double_val);
1187  item += item_size;
1188  }
1189  }
1190  }
1191  }
1192  else
1193  { /* not a list */
1194  if (!get_binary_item(
1195  fp, bin_file_type, prop->external_type, &int_val, &uint_val,
1196  &double_val))
1197  {
1198  // Error...
1199  fprintf(
1200  stderr,
1201  "RPly::binary_get_element: Error reading binary file!\n");
1202  }
1203 
1204  if (store_it)
1205  {
1206  item = elem_data + prop->offset;
1207  store_item(
1208  item, prop->internal_type, int_val, uint_val, double_val);
1209  }
1210  }
1211  }
1212 }
1213 
1214 /******************************************************************************
1215 Write to a file the word that represents a PLY data type.
1216 
1217 Entry:
1218  fp - file pointer
1219  code - code for type
1220 ******************************************************************************/
1221 
1222 void write_scalar_type(FILE* fp, int code)
1223 {
1224  /* make sure this is a valid code */
1225 
1227  throw std::runtime_error(
1228  format("write_scalar_type: bad data code = %d", code));
1229 
1230  /* write the code to a file */
1231 
1232  fprintf(fp, "%s", type_names[code].c_str());
1233 }
1234 
1235 /******************************************************************************
1236 Get a text line from a file and break it up into words.
1237 
1238 IMPORTANT: The calling routine call "free" on the returned pointer once
1239 finished with it.
1240 
1241 Entry:
1242  fp - file to read from
1243 
1244 Exit:
1245  nwords - number of words returned
1246  orig_line - the original line of characters
1247  returns a list of words from the line, or nullptr if end-of-file
1248 ******************************************************************************/
1249 
1250 vector<string> get_words(FILE* fp, string& orig_line)
1251 {
1252 #define BIG_STRING 4096
1253  char str[BIG_STRING];
1254 
1255  vector<string> words;
1256 
1257  ASSERT_(fp != nullptr)
1258 
1259  /* read in a line */
1260  char* result = fgets(str, BIG_STRING, fp);
1261  if (result == nullptr)
1262  {
1263  orig_line = string();
1264  return words;
1265  }
1266 
1267  orig_line = string(str);
1268  mrpt::system::tokenize(orig_line, " \t\r\n", words);
1269 
1270  return words;
1271 }
1272 
1273 /******************************************************************************
1274 Return the value of an item, given a pointer to it and its type.
1275 
1276 Entry:
1277  item - pointer to item
1278  type - data type that "item" points to
1279 
1280 Exit:
1281  returns a double-precision float that contains the value of the item
1282 ******************************************************************************/
1283 
1284 double get_item_value(char* item, int type)
1285 {
1286  unsigned char* puchar;
1287  char* pchar;
1288  short int* pshort;
1289  unsigned short int* pushort;
1290  int* pint;
1291  unsigned int* puint;
1292  float* pfloat;
1293  double* pdouble;
1294  int int_value;
1295  unsigned int uint_value;
1296  double double_value;
1297 
1298  switch (type)
1299  {
1300  case PLY_CHAR:
1301  pchar = (char*)item;
1302  int_value = *pchar;
1303  return ((double)int_value);
1304  case PLY_UCHAR:
1305  puchar = (unsigned char*)item;
1306  int_value = *puchar;
1307  return ((double)int_value);
1308  case PLY_SHORT:
1309  pshort = (short int*)item;
1310  int_value = *pshort;
1311  return ((double)int_value);
1312  case PLY_USHORT:
1313  pushort = (unsigned short int*)item;
1314  int_value = *pushort;
1315  return ((double)int_value);
1316  case PLY_INT:
1317  pint = (int*)item;
1318  int_value = *pint;
1319  return ((double)int_value);
1320  case PLY_UINT:
1321  puint = (unsigned int*)item;
1322  uint_value = *puint;
1323  return ((double)uint_value);
1324  case PLY_FLOAT:
1325  pfloat = (float*)item;
1326  double_value = *pfloat;
1327  return (double_value);
1328  case PLY_DOUBLE:
1329  pdouble = (double*)item;
1330  double_value = *pdouble;
1331  return (double_value);
1332  default:
1333  throw std::runtime_error(
1334  format("get_item_value: bad type = %d", type));
1335  }
1336 }
1337 
1338 /******************************************************************************
1339 Write out an item to a file as raw binary bytes.
1340 
1341 Entry:
1342  fp - file to write to
1343  int_val - integer version of item
1344  uint_val - unsigned integer version of item
1345  double_val - double-precision float version of item
1346  type - data type to write out
1347 ******************************************************************************/
1348 
1350  FILE* fp, int int_val, unsigned int uint_val, double double_val, int type)
1351 {
1352  unsigned char uchar_val;
1353  char char_val;
1354  unsigned short ushort_val;
1355  short short_val;
1356  float float_val;
1357 
1358  switch (type)
1359  {
1360  case PLY_CHAR:
1361  char_val = int_val;
1362  fwrite(&char_val, 1, 1, fp);
1363  break;
1364  case PLY_SHORT:
1365  short_val = int_val;
1366  fwrite(&short_val, 2, 1, fp);
1367  break;
1368  case PLY_INT:
1369  fwrite(&int_val, 4, 1, fp);
1370  break;
1371  case PLY_UCHAR:
1372  uchar_val = uint_val;
1373  fwrite(&uchar_val, 1, 1, fp);
1374  break;
1375  case PLY_USHORT:
1376  ushort_val = uint_val;
1377  fwrite(&ushort_val, 2, 1, fp);
1378  break;
1379  case PLY_UINT:
1380  fwrite(&uint_val, 4, 1, fp);
1381  break;
1382  case PLY_FLOAT:
1383  float_val = double_val;
1384  fwrite(&float_val, 4, 1, fp);
1385  break;
1386  case PLY_DOUBLE:
1387  fwrite(&double_val, 8, 1, fp);
1388  break;
1389  default:
1390  throw std::runtime_error(
1391  format("write_binary_item: bad type = %d", type));
1392  }
1393 }
1394 
1395 /******************************************************************************
1396 Write out an item to a file as ascii characters.
1397 
1398 Entry:
1399  fp - file to write to
1400  int_val - integer version of item
1401  uint_val - unsigned integer version of item
1402  double_val - double-precision float version of item
1403  type - data type to write out
1404 ******************************************************************************/
1405 
1407  FILE* fp, int int_val, unsigned int uint_val, double double_val, int type)
1408 {
1409  switch (type)
1410  {
1411  case PLY_CHAR:
1412  case PLY_SHORT:
1413  case PLY_INT:
1414  fprintf(fp, "%d ", int_val);
1415  break;
1416  case PLY_UCHAR:
1417  case PLY_USHORT:
1418  case PLY_UINT:
1419  fprintf(fp, "%u ", uint_val);
1420  break;
1421  case PLY_FLOAT:
1422  case PLY_DOUBLE:
1423  fprintf(fp, "%g ", double_val);
1424  break;
1425  default:
1426  throw std::runtime_error(
1427  format("write_ascii_item: bad type = %d", type));
1428  }
1429 }
1430 
1431 /******************************************************************************
1432 Get the value of an item that is in memory, and place the result
1433 into an integer, an unsigned integer and a double.
1434 
1435 Entry:
1436  ptr - pointer to the item
1437  type - data type supposedly in the item
1438 
1439 Exit:
1440  int_val - integer value
1441  uint_val - unsigned integer value
1442  double_val - double-precision floating point value
1443 ******************************************************************************/
1444 
1446  void* ptr, int type, int* int_val, unsigned int* uint_val,
1447  double* double_val)
1448 {
1449  switch (type)
1450  {
1451  case PLY_CHAR:
1452  *int_val = *((char*)ptr);
1453  *uint_val = *int_val;
1454  *double_val = *int_val;
1455  break;
1456  case PLY_UCHAR:
1457  *uint_val = *((unsigned char*)ptr);
1458  *int_val = *uint_val;
1459  *double_val = *uint_val;
1460  break;
1461  case PLY_SHORT:
1462  *int_val = *((short int*)ptr);
1463  *uint_val = *int_val;
1464  *double_val = *int_val;
1465  break;
1466  case PLY_USHORT:
1467  *uint_val = *((unsigned short int*)ptr);
1468  *int_val = *uint_val;
1469  *double_val = *uint_val;
1470  break;
1471  case PLY_INT:
1472  *int_val = *((int*)ptr);
1473  *uint_val = *int_val;
1474  *double_val = *int_val;
1475  break;
1476  case PLY_UINT:
1477  *uint_val = *((unsigned int*)ptr);
1478  *int_val = *uint_val;
1479  *double_val = *uint_val;
1480  break;
1481  case PLY_FLOAT:
1482  *double_val = *((float*)ptr);
1483  *int_val = *double_val;
1484  *uint_val = *double_val;
1485  break;
1486  case PLY_DOUBLE:
1487  *double_val = *((double*)ptr);
1488  *int_val = *double_val;
1489  *uint_val = *double_val;
1490  break;
1491  default:
1492  throw std::runtime_error(
1493  format("get_stored_item: bad type = %d", type));
1494  }
1495 }
1496 
1497 /******************************************************************************
1498 Get the value of an item from a binary file, and place the result
1499 into an integer, an unsigned integer and a double.
1500 
1501 Entry:
1502  fp - file to get item from
1503  type - data type supposedly in the word
1504 
1505 Exit:
1506  int_val - integer value
1507  uint_val - unsigned integer value
1508  double_val - double-precision floating point value
1509 
1510 Return: 0: On error
1511 ******************************************************************************/
1512 
1514  FILE* fp, int bin_file_type, int type, int* int_val, unsigned int* uint_val,
1515  double* double_val)
1516 {
1517  char c[8];
1518  void* ptr;
1519 
1520  ptr = (void*)c;
1521 
1522  switch (type)
1523  {
1524  case PLY_CHAR:
1525  if (fread(ptr, 1, 1, fp) != 1) return 0;
1526  *int_val = *((char*)ptr);
1527  *uint_val = *int_val;
1528  *double_val = *int_val;
1529  break;
1530  case PLY_UCHAR:
1531  if (fread(ptr, 1, 1, fp) != 1) return 0;
1532  *uint_val = *((unsigned char*)ptr);
1533  *int_val = *uint_val;
1534  *double_val = *uint_val;
1535  break;
1536  case PLY_SHORT:
1537  if (fread(ptr, 2, 1, fp) != 1) return 0;
1538  *int_val = *((short int*)ptr);
1539  *uint_val = *int_val;
1540  *double_val = *int_val;
1541  break;
1542  case PLY_USHORT:
1543  if (fread(ptr, 2, 1, fp) != 1) return 0;
1544  *uint_val = *((unsigned short int*)ptr);
1545  *int_val = *uint_val;
1546  *double_val = *uint_val;
1547  break;
1548  case PLY_INT:
1549  if (fread(ptr, 4, 1, fp) != 1) return 0;
1550  *int_val = *((int*)ptr);
1551  *uint_val = *int_val;
1552  *double_val = *int_val;
1553  break;
1554  case PLY_UINT:
1555  if (fread(ptr, 4, 1, fp) != 1) return 0;
1556  *uint_val = *((unsigned int*)ptr);
1557  *int_val = *uint_val;
1558  *double_val = *uint_val;
1559  break;
1560  case PLY_FLOAT:
1561  if (fread(ptr, 4, 1, fp) != 1) return 0;
1562  *double_val = *((float*)ptr);
1563  *int_val = *double_val;
1564  *uint_val = *double_val;
1565  break;
1566  case PLY_DOUBLE:
1567  if (fread(ptr, 8, 1, fp) != 1) return 0;
1568  *double_val = *((double*)ptr);
1569  *int_val = *double_val;
1570  *uint_val = *double_val;
1571  break;
1572  default:
1573  throw std::runtime_error(
1574  format("get_binary_item: bad type = %d", type));
1575  }
1576 
1577 // Added by JL:
1578 // If the Big/Little endian format in the file is different than the native
1579 // format, do the conversion:
1580 #if MRPT_IS_BIG_ENDIAN
1581  const bool do_reverse = (bin_file_type == PLY_BINARY_LE);
1582 #else
1583  const bool do_reverse = (bin_file_type == PLY_BINARY_BE);
1584 #endif
1585 
1586  if (do_reverse)
1587  {
1588  int int_val2 = *int_val;
1589  unsigned int uint_val2 = *uint_val;
1590  double double_val2 = *double_val;
1591  mrpt::utils::reverseBytes(int_val2, *int_val);
1592  mrpt::utils::reverseBytes(uint_val2, *uint_val);
1593  mrpt::utils::reverseBytes(double_val2, *double_val);
1594  }
1595 
1596  return 1;
1597 }
1598 
1599 /******************************************************************************
1600 Extract the value of an item from an ascii word, and place the result
1601 into an integer, an unsigned integer and a double.
1602 
1603 Entry:
1604  word - word to extract value from
1605  type - data type supposedly in the word
1606 
1607 Exit:
1608  int_val - integer value
1609  uint_val - unsigned integer value
1610  double_val - double-precision floating point value
1611 ******************************************************************************/
1612 
1614  const char* word, int type, int* int_val, unsigned int* uint_val,
1615  double* double_val)
1616 {
1617  switch (type)
1618  {
1619  case PLY_CHAR:
1620  case PLY_UCHAR:
1621  case PLY_SHORT:
1622  case PLY_USHORT:
1623  case PLY_INT:
1624  *int_val = atoi(word);
1625  *uint_val = *int_val;
1626  *double_val = *int_val;
1627  break;
1628 
1629  case PLY_UINT:
1630  *uint_val = strtoul(word, (char**)nullptr, 10);
1631  *int_val = *uint_val;
1632  *double_val = *uint_val;
1633  break;
1634 
1635  case PLY_FLOAT:
1636  case PLY_DOUBLE:
1637  *double_val = atof(word);
1638  *int_val = (int)*double_val;
1639  *uint_val = (unsigned int)*double_val;
1640  break;
1641 
1642  default:
1643  throw std::runtime_error(
1644  format("get_ascii_item: bad type = %d", type));
1645  }
1646 }
1647 
1648 /******************************************************************************
1649 Store a value into a place being pointed to, guided by a data type.
1650 
1651 Entry:
1652  item - place to store value
1653  type - data type
1654  int_val - integer version of value
1655  uint_val - unsigned integer version of value
1656  double_val - double version of value
1657 
1658 Exit:
1659  item - pointer to stored value
1660 ******************************************************************************/
1661 
1663  char* item, int type, int int_val, unsigned int uint_val, double double_val)
1664 {
1665  unsigned char* puchar;
1666  short int* pshort;
1667  unsigned short int* pushort;
1668  int* pint;
1669  unsigned int* puint;
1670  float* pfloat;
1671  double* pdouble;
1672 
1673  switch (type)
1674  {
1675  case PLY_CHAR:
1676  *item = int_val;
1677  break;
1678  case PLY_UCHAR:
1679  puchar = (unsigned char*)item;
1680  *puchar = uint_val;
1681  break;
1682  case PLY_SHORT:
1683  pshort = (short*)item;
1684  *pshort = int_val;
1685  break;
1686  case PLY_USHORT:
1687  pushort = (unsigned short*)item;
1688  *pushort = uint_val;
1689  break;
1690  case PLY_INT:
1691  pint = (int*)item;
1692  *pint = int_val;
1693  break;
1694  case PLY_UINT:
1695  puint = (unsigned int*)item;
1696  *puint = uint_val;
1697  break;
1698  case PLY_FLOAT:
1699  pfloat = (float*)item;
1700  *pfloat = double_val;
1701  break;
1702  case PLY_DOUBLE:
1703  pdouble = (double*)item;
1704  *pdouble = double_val;
1705  break;
1706  default:
1707  throw std::runtime_error(format("store_item: bad type = %d", type));
1708  }
1709 }
1710 
1711 /******************************************************************************
1712 Add an element to a PLY file descriptor.
1713 
1714 Entry:
1715  plyfile - PLY file descriptor
1716  words - list of words describing the element
1717  nwords - number of words in the list
1718 ******************************************************************************/
1719 
1720 void add_element(PlyFile* plyfile, const vector<string>& words)
1721 {
1722  /* create the new element */
1723  plyfile->elems.push_back(PlyElement());
1724 
1725  PlyElement* elem = &(*plyfile->elems.rbegin());
1726  elem->name = words[1];
1727  elem->num = atoi(words[2].c_str());
1728 }
1729 
1730 /******************************************************************************
1731 Return the type of a property, given the name of the property.
1732 
1733 Entry:
1734  name - name of property type
1735 
1736 Exit:
1737  returns integer code for property, or 0 if not found
1738 ******************************************************************************/
1739 
1740 int get_prop_type(const string& type_name)
1741 {
1742  int i;
1743 
1744  for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
1745  if (type_name == type_names[i]) return (i);
1746 
1747  /* if we get here, we didn't find the type */
1748  return (0);
1749 }
1750 
1751 /******************************************************************************
1752 Add a property to a PLY file descriptor.
1753 
1754 Entry:
1755  plyfile - PLY file descriptor
1756  words - list of words describing the property
1757  nwords - number of words in the list
1758 ******************************************************************************/
1759 
1760 void add_property(PlyFile* plyfile, const vector<string>& words)
1761 {
1762  /* add this property to the list of properties of the current element */
1763  PlyElement* elem = &(*plyfile->elems.rbegin());
1764 
1765  elem->props.push_back(PlyProperty());
1766 
1767  PlyProperty* prop = &(*elem->props.rbegin());
1768 
1769  /* create the new property */
1770 
1771  if (words[1] == "list")
1772  { /* is a list */
1773  prop->count_external = get_prop_type(words[2]);
1774  prop->external_type = get_prop_type(words[3]);
1775  prop->name = words[4];
1776  prop->is_list = 1;
1777  }
1778  else
1779  { /* not a list */
1780  prop->external_type = get_prop_type(words[1]);
1781  prop->name = words[2];
1782  prop->is_list = 0;
1783  }
1784 }
1785 
1786 /******************************************************************************
1787 Add a comment to a PLY file descriptor.
1788 
1789 Entry:
1790  plyfile - PLY file descriptor
1791  line - line containing comment
1792 ******************************************************************************/
1793 
1794 void add_comment(PlyFile* plyfile, const string& line)
1795 {
1796  /* skip over "comment" and leading spaces and tabs */
1797  ply_put_comment(plyfile, mrpt::system::trim(line.substr(7)));
1798 }
1799 
1800 /******************************************************************************
1801 Add a some object information to a PLY file descriptor.
1802 
1803 Entry:
1804  plyfile - PLY file descriptor
1805  line - line containing text info
1806 ******************************************************************************/
1807 
1808 void add_obj_info(PlyFile* plyfile, const string& line)
1809 {
1810  /* skip over "obj_info" and leading spaces and tabs */
1811  ply_put_obj_info(plyfile, mrpt::system::trim(line.substr(8)));
1812 }
1813 
1814 /******************************************************************************
1815 Copy a property.
1816 ******************************************************************************/
1817 
1818 void copy_property(PlyProperty* dest, const PlyProperty* src) { *dest = *src; }
1819 const float VAL_NOT_SET = -1e10;
1820 
1821 struct TVertex
1822 {
1823  float x, y, z;
1824  float r, g, b;
1825  float intensity;
1826 };
1827 
1829  {/* list of property information for a vertex */
1830  // is_list count_external
1831  // count_internal count_offset
1832  {"x", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, x), 0, 0, 0, 0},
1833  {"y", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, y), 0, 0, 0, 0},
1834  {"z", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, z), 0, 0, 0, 0},
1835  {"intensity", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, intensity), 0, 0, 0,
1836  0}};
1837 
1838 struct TFace
1839 {
1840  float intensity; /* this user attaches intensity to faces */
1841  unsigned char nverts; /* number of vertex indices in list */
1842  int* verts; /* vertex index list */
1843 };
1844 
1846  {/* list of property information for a vertex */
1847  {"intensity", PLY_FLOAT, PLY_FLOAT, offsetof(TFace, intensity), 0, 0, 0,
1848  0},
1849  {"vertex_indices", PLY_INT, PLY_INT, offsetof(TFace, verts), 1, PLY_UCHAR,
1850  PLY_UCHAR, offsetof(TFace, nverts)}};
1851 
1852 /*
1853  Loads from a PLY file.
1854 */
1855 bool PLY_Importer::loadFromPlyFile(
1856  const std::string& filename, CStringList* file_comments,
1857  CStringList* file_obj_info)
1858 {
1859  try
1860  {
1861  /* open a PLY file for reading */
1862  vector<string> elist; // element names
1863  int file_type;
1864  float version;
1865  PlyFile* ply =
1866  ply_open_for_reading(filename.c_str(), elist, &file_type, &version);
1867 
1868  /* go through each kind of element that we learned is in the file */
1869  /* and read them */
1870 
1871  for (size_t i = 0; i < elist.size(); i++)
1872  {
1873  /* get the description of the first element */
1874  const string& elem_name = elist[i];
1875  int num_elems = 0, nprops = 0;
1876 
1877  // vector<PlyProperty> plist =
1878  ply_get_element_description(ply, elem_name, num_elems, nprops);
1879 
1880  /* print the name of the element, for debugging */
1881  // printf ("element %s %d\n", elem_name, num_elems);
1882 
1883  /* if we're on vertex elements, read them in */
1884  if ("vertex" == elem_name)
1885  {
1886  /* set up for getting vertex elements */
1887  for (size_t k = 0; k < sizeof(vert_props) / sizeof(PlyProperty);
1888  k++)
1889  ply_get_property(ply, elem_name, &vert_props[k]);
1890 
1891  /* grab all the vertex elements */
1892  this->PLY_import_set_vertex_count(num_elems);
1893  for (int j = 0; j < num_elems; j++)
1894  {
1895  TVertex pt;
1896  pt.x = pt.y = pt.z = pt.r = pt.g = pt.b = pt.intensity =
1897  VAL_NOT_SET;
1898 
1899  /* grab an element from the file */
1900  ply_get_element(ply, reinterpret_cast<void*>(&pt));
1901  const TPoint3Df xyz(pt.x, pt.y, pt.z);
1902  if (pt.intensity != VAL_NOT_SET)
1903  { // Grayscale
1904  const TColorf col(
1905  pt.intensity, pt.intensity, pt.intensity);
1906  this->PLY_import_set_vertex(j, xyz, &col);
1907  }
1908  else if (
1909  pt.r != VAL_NOT_SET && pt.g != VAL_NOT_SET &&
1910  pt.b != VAL_NOT_SET)
1911  { // RGB
1912  const TColorf col(pt.r, pt.g, pt.b);
1913  this->PLY_import_set_vertex(j, xyz, &col);
1914  }
1915  else
1916  { // No color
1917  this->PLY_import_set_vertex(j, xyz);
1918  }
1919  }
1920  }
1921 
1922  // print out the properties we got, for debugging
1923  // for (int j = 0; j < nprops; j++)
1924  // printf ("property %s\n", plist[j]->name);
1925  }
1926 
1927  // grab and print out the comments in the file
1928  if (file_comments)
1929  {
1930  vector<string> strs;
1931  ply_get_comments(ply, strs);
1932  *file_comments = CStringList(strs);
1933  }
1934 
1935  // grab and print out the object information
1936  if (file_obj_info)
1937  {
1938  vector<string> strs;
1939  ply_get_obj_info(ply, strs);
1940  *file_obj_info = CStringList(strs);
1941  }
1942 
1943  /* close the PLY file */
1944  ply_close(ply);
1945 
1946  // All OK:
1947  m_ply_import_last_error = std::string();
1948  return true;
1949  }
1950  catch (std::exception& e)
1951  {
1952  // Return error:
1953  m_ply_import_last_error = std::string(e.what());
1954  return false;
1955  }
1956 }
1957 
1958 bool PLY_Exporter::saveToPlyFile(
1959  const std::string& filename, bool save_in_binary,
1960  const CStringList& file_comments, const CStringList& file_obj_info) const
1961 {
1962  try
1963  {
1964  /* list of the kinds of elements in the user's object */
1965  vector<string> elem_names;
1966  elem_names.push_back(string("vertex"));
1967  elem_names.push_back(string("face"));
1968 
1969  /* create the vertex index lists for the faces */
1970  // for (i = 0; i < nfaces; i++)
1971  // faces[i].verts = vert_ptrs[i];
1972 
1973  /* open either a binary or ascii PLY file for writing */
1974  /* (the file will be called "test.ply" because the routines */
1975  /* enforce the .ply filename extension) */
1976 
1977  float version;
1979  filename.c_str(), elem_names, save_in_binary ?
1980 #if MRPT_IS_BIG_ENDIAN
1982 #else
1984 #endif
1985  : PLY_ASCII,
1986  &version);
1987 
1988  /* describe what properties go into the vertex and face elements */
1989 
1990  const size_t nverts = this->PLY_export_get_vertex_count();
1991  const size_t nfaces = this->PLY_export_get_face_count();
1992 
1993  if (nverts)
1994  {
1995  // Find out if we have color:
1996  TPoint3Df pt;
1997  bool pt_has_color;
1998  TColorf pt_color;
1999  this->PLY_export_get_vertex(0, pt, pt_has_color, pt_color);
2000 
2001  ply_element_count(ply, "vertex", nverts);
2002  ply_describe_property(ply, "vertex", &vert_props[0]); // x
2003  ply_describe_property(ply, "vertex", &vert_props[1]); // y
2004  ply_describe_property(ply, "vertex", &vert_props[2]); // z
2005 
2006  if (pt_has_color)
2008  ply, "vertex", &vert_props[3]); // intensity
2009  }
2010 
2011  ply_element_count(ply, "face", nfaces);
2012  for (size_t k = 0; k < sizeof(face_props) / sizeof(PlyProperty); k++)
2013  ply_describe_property(ply, "face", &face_props[k]);
2014 
2015  /* write a comment and an object information field */
2016  for (size_t k = 0; k < file_comments.size(); k++)
2017  ply_put_comment(ply, file_comments(k).c_str());
2018 
2019  for (size_t k = 0; k < file_obj_info.size(); k++)
2020  ply_put_obj_info(ply, file_obj_info(k).c_str());
2021 
2022  /* we have described exactly what we will put in the file, so */
2023  /* we are now done with the header info */
2024  ply_header_complete(ply);
2025 
2026  /* set up and write the vertex elements */
2027  ply_put_element_setup(ply, "vertex");
2028  for (size_t i = 0; i < nverts; i++)
2029  {
2030  TPoint3Df pt;
2031  bool pt_has_color;
2032  TColorf pt_color;
2033  this->PLY_export_get_vertex(i, pt, pt_has_color, pt_color);
2034 
2035  TVertex ver;
2036  ver.x = pt.x;
2037  ver.y = pt.y;
2038  ver.z = pt.z;
2039 
2040  if (pt_has_color)
2041  ver.intensity =
2042  (1.0f / 3.0f) * (pt_color.R + pt_color.G + pt_color.B);
2043  else
2044  ver.intensity = 0.5;
2045 
2046  ply_put_element(ply, (void*)&ver);
2047  }
2048 
2049  /* set up and write the face elements */
2050  /* ply_put_element_setup (ply, "face");
2051  for (size_t i = 0; i < nfaces; i++)
2052  {
2053  TFace face;
2054  this->PLY_export_get_face(...);
2055  ply_put_element (ply, (void *) &face);
2056  }*/
2057 
2058  /* close the PLY file */
2059  ply_close(ply);
2060 
2061  // All OK:
2062  m_ply_export_last_error = std::string();
2063  return true;
2064  }
2065  catch (std::exception& e)
2066  {
2067  // Return error:
2068  m_ply_export_last_error = std::string(e.what());
2069  return false;
2070  }
2071 }
#define offsetof(_structure, _field)
Definition: util.h:52
#define BIG_STRING
const char DONT_STORE_PROP
void ply_put_obj_info(PlyFile *plyfile, const string &obj_info)
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble z
Definition: glext.h:3872
void get_ascii_item(const char *, int, int *, unsigned int *, double *)
vector< string > comments
vector< PlyProperty > props
std::string name
PlyElement * find_element(PlyFile *, const std::string &s)
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:272
#define PLY_BINARY_BE
const PlyProperty vert_props[]
vector< char > store_prop
void ply_get_obj_info(PlyFile *plyfile, vector< string > &obj_info)
STL namespace.
#define PLY_ASCII
struct PlyProperty PlyProperty
GLdouble s
Definition: glext.h:3676
GLuint src
Definition: glext.h:7278
PlyFile * ply_open_for_writing(const char *name, const vector< string > &elem_names, int file_type, float *version)
const char NAMED_PROP
int get_binary_item(FILE *, int, int, int *, unsigned int *, double *)
void add_property(PlyFile *, const vector< string > &)
GLuint GLuint num
Definition: glext.h:7278
const int ply_type_size[]
A class for storing a list of text lines.
Definition: CStringList.h:32
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
Lightweight 3D point (float version).
const float VAL_NOT_SET
const char STORE_PROP
GLuint index
Definition: glext.h:4054
const GLubyte * c
Definition: glext.h:6313
double get_item_value(const char *, int)
PlyFile(FILE *_fp=nullptr)
void ply_put_element_setup(PlyFile *plyfile, const string &elem_name)
GLubyte g
Definition: glext.h:6279
PlyElement * which_elem
#define PLY_BINARY_LE
GLubyte GLubyte b
Definition: glext.h:6279
void add_comment(PlyFile *, const string &)
const char OTHER_PROP
void ply_describe_element(PlyFile *plyfile, const string &elem_name, int nelems, vector< PlyProperty > &prop_list)
const PlyProperty face_props[]
GLsizei const GLchar ** string
Definition: glext.h:4101
void ply_describe_property(PlyFile *plyfile, const char *elem_name, const PlyProperty *prop)
size_t size() const
Returns the number of text lines in the list.
PlyFile * ply_read(FILE *fp, vector< string > &elem_names)
void reverseBytes(const T &v_in, T &v_out)
Reverse the order of the bytes of a given type (useful for transforming btw little/big endian) ...
Definition: bits.h:211
void add_element(PlyFile *, const vector< string > &)
const int NO_OTHER_PROPS
int get_prop_type(const string &type_name)
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:405
void tokenize(const std::string &inString, const std::string &inDelimiters, std::deque< std::string > &outTokens, bool skipBlankTokens=true) noexcept
Tokenizes a string according to a set of delimiting characters.
const std::string type_names[]
vector< PlyProperty > ply_get_element_description(PlyFile *plyfile, const string &elem_name, int &nelems, int &nprops)
void add_obj_info(PlyFile *, const string &)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void write_binary_item(FILE *, int, unsigned int, double, int)
Definition: inftrees.h:28
void ply_close(PlyFile *plyfile)
void ply_put_comment(PlyFile *plyfile, const string &comment)
void ply_get_element(PlyFile *plyfile, void *elem_ptr)
void write_scalar_type(FILE *, int)
void write_ascii_item(FILE *, int, unsigned int, double, int)
PlyFile * ply_write(FILE *fp, const vector< string > &elem_names, int file_type)
PlyProperty * find_property(PlyElement *, const std::string &s, int *)
void get_stored_item(void *, int, int *, unsigned int *, double *)
GLuint const GLchar * name
Definition: glext.h:4054
#define ASSERT_(f)
A RGB color - floats in the range [0,1].
Definition: TColor.h:78
void ascii_get_element(PlyFile *, char *)
void copy_property(PlyProperty *, const PlyProperty *)
vector< string > get_words(FILE *, string &)
void binary_get_element(PlyFile *, char *)
GLenum GLint GLint y
Definition: glext.h:3538
std::string trim(const std::string &str)
Removes leading and trailing spaces.
vector< PlyElement > elems
struct PlyElement PlyElement
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:254
void ply_get_property(PlyFile *plyfile, const string &elem_name, const PlyProperty *prop)
GLenum GLsizei GLenum format
Definition: glext.h:3531
void store_item(char *, int, int, unsigned int, double)
void ply_header_complete(PlyFile *plyfile)
GLsizeiptr size
Definition: glext.h:3923
GLenum GLint x
Definition: glext.h:3538
unsigned char nverts
void ply_get_info(PlyFile *ply, float *version, int *file_type)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:3528
vector< string > obj_info
void ply_element_count(PlyFile *plyfile, const string &elem_name, int nelems)
void ply_get_comments(PlyFile *plyfile, vector< string > &comments)
PlyFile * ply_open_for_reading(const char *filename, vector< string > &elem_names, int *file_type, float *version)
void ply_put_element(PlyFile *plyfile, void *elem_ptr)



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019