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