MRPT  1.9.9
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-2019, 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; /* file's data type */
101  int internal_type; /* program's data type */
102  int offset; /* offset bytes of prop in a struct */
103 
104  int is_list; /* 1 = list, 0 = scalar */
105  int count_external; /* file's count type */
106  int count_internal; /* program's count type */
107  int count_offset; /* 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; /* offset to un-asked-for props, or -1 if none*/
120  int other_size; /* 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 
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 */
144 
145 /* find a property in an element's list */
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 = 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(
975  format("ply_get_element: unexpected end of file"));
976 
977  which_word = 0;
978 
979  for (size_t j = 0; j < elem->props.size(); j++)
980  {
981  PlyProperty* prop = &elem->props[j];
982  store_it = (elem->store_prop[j] | other_flag);
983 
984  /* store either in the user's structure or in other_props */
985  if (elem->store_prop[j])
986  elem_data = elem_ptr;
987  else
988  elem_data = other_data;
989 
990  if (prop->is_list)
991  { /* a list */
992 
993  /* get and store the number of items in the list */
995  words[which_word++].c_str(), prop->count_external, &int_val,
996  &uint_val, &double_val);
997  if (store_it)
998  {
999  item = elem_data + prop->count_offset;
1000  store_item(
1001  item, prop->count_internal, int_val, uint_val, double_val);
1002  }
1003 
1004  /* allocate space for an array of items and store a ptr to the array
1005  */
1006  list_count = int_val;
1007  item_size = ply_type_size[prop->internal_type];
1008  store_array = (char**)(elem_data + prop->offset);
1009 
1010  if (list_count == 0)
1011  {
1012  if (store_it) *store_array = nullptr;
1013  }
1014  else
1015  {
1016  if (store_it)
1017  {
1018  item_ptr =
1019  (char*)malloc(sizeof(char) * item_size * list_count);
1020  item = item_ptr;
1021  *store_array = item_ptr;
1022  }
1023 
1024  /* read items and store them into the array */
1025  for (int k = 0; k < list_count; k++)
1026  {
1028  words[which_word++].c_str(), prop->external_type,
1029  &int_val, &uint_val, &double_val);
1030  if (store_it)
1031  {
1032  store_item(
1033  item, prop->internal_type, int_val, uint_val,
1034  double_val);
1035  item += item_size;
1036  }
1037  }
1038  }
1039  }
1040  else
1041  { /* not a list */
1043  words[which_word++].c_str(), prop->external_type, &int_val,
1044  &uint_val, &double_val);
1045  if (store_it)
1046  {
1047  item = elem_data + prop->offset;
1048  store_item(
1049  item, prop->internal_type, int_val, uint_val, double_val);
1050  }
1051  }
1052  }
1053 }
1054 
1055 /******************************************************************************
1056 Read an element from a binary file.
1057 
1058 Entry:
1059  plyfile - file identifier
1060  elem_ptr - pointer to an element
1061 ******************************************************************************/
1062 
1063 void binary_get_element(PlyFile* plyfile, char* elem_ptr)
1064 {
1065  FILE* fp = plyfile->fp;
1066  char *elem_data, *item = nullptr;
1067  char* item_ptr;
1068  int item_size = 0;
1069  int int_val;
1070  unsigned int uint_val;
1071  double double_val;
1072  int list_count;
1073  int store_it;
1074  char** store_array;
1075  char* other_data = nullptr;
1076  int other_flag;
1077 
1078  int bin_file_type = plyfile->file_type;
1079 
1080  /* the kind of element we're reading currently */
1081  PlyElement* elem = plyfile->which_elem;
1082 
1083  /* do we need to setup for other_props? */
1084 
1085  if (elem->other_offset != NO_OTHER_PROPS)
1086  {
1087  char** ptr;
1088  other_flag = 1;
1089  /* make room for other_props */
1090  other_data = (char*)malloc(elem->other_size);
1091  /* store pointer in user's structure to the other_props */
1092  ptr = (char**)(elem_ptr + elem->other_offset);
1093  *ptr = other_data;
1094  }
1095  else
1096  other_flag = 0;
1097 
1098  /* read in a number of elements */
1099 
1100  for (size_t j = 0; j < elem->props.size(); j++)
1101  {
1102  PlyProperty* prop = &elem->props[j];
1103  store_it = (elem->store_prop[j] | other_flag);
1104 
1105  /* store either in the user's structure or in other_props */
1106  if (elem->store_prop[j])
1107  elem_data = elem_ptr;
1108  else
1109  elem_data = other_data;
1110 
1111  if (prop->is_list)
1112  { /* a list */
1113 
1114  /* get and store the number of items in the list */
1115  if (!get_binary_item(
1116  fp, bin_file_type, prop->count_external, &int_val,
1117  &uint_val, &double_val))
1118  {
1119  // Error...
1120  fprintf(
1121  stderr,
1122  "RPly::binary_get_element: Error reading binary file!\n");
1123  }
1124 
1125  if (store_it)
1126  {
1127  item = elem_data + prop->count_offset;
1128  store_item(
1129  item, prop->count_internal, int_val, uint_val, double_val);
1130  }
1131 
1132  /* allocate space for an array of items and store a ptr to the array
1133  */
1134  list_count = int_val;
1135  /* The "if" was added by Afra Zomorodian 8/22/95
1136  * so that zipper won't crash reading plies that have additional
1137  * properties.
1138  */
1139  if (store_it)
1140  {
1141  item_size = ply_type_size[prop->internal_type];
1142  }
1143  store_array = (char**)(elem_data + prop->offset);
1144  if (list_count == 0)
1145  {
1146  if (store_it) *store_array = nullptr;
1147  }
1148  else
1149  {
1150  if (store_it)
1151  {
1152  item_ptr =
1153  (char*)malloc(sizeof(char) * item_size * list_count);
1154  item = item_ptr;
1155  *store_array = item_ptr;
1156  }
1157 
1158  /* read items and store them into the array */
1159  for (int k = 0; k < list_count; k++)
1160  {
1161  if (!get_binary_item(
1162  fp, bin_file_type, prop->external_type, &int_val,
1163  &uint_val, &double_val))
1164  {
1165  // Error...
1166  fprintf(
1167  stderr,
1168  "RPly::binary_get_element: Error reading binary "
1169  "file!\n");
1170  }
1171 
1172  if (store_it)
1173  {
1174  store_item(
1175  item, prop->internal_type, int_val, uint_val,
1176  double_val);
1177  item += item_size;
1178  }
1179  }
1180  }
1181  }
1182  else
1183  { /* not a list */
1184  if (!get_binary_item(
1185  fp, bin_file_type, prop->external_type, &int_val, &uint_val,
1186  &double_val))
1187  {
1188  // Error...
1189  fprintf(
1190  stderr,
1191  "RPly::binary_get_element: Error reading binary file!\n");
1192  }
1193 
1194  if (store_it)
1195  {
1196  item = elem_data + prop->offset;
1197  store_item(
1198  item, prop->internal_type, int_val, uint_val, double_val);
1199  }
1200  }
1201  }
1202 }
1203 
1204 /******************************************************************************
1205 Write to a file the word that represents a PLY data type.
1206 
1207 Entry:
1208  fp - file pointer
1209  code - code for type
1210 ******************************************************************************/
1211 
1212 void write_scalar_type(FILE* fp, int code)
1213 {
1214  /* make sure this is a valid code */
1215 
1217  throw std::runtime_error(
1218  format("write_scalar_type: bad data code = %d", code));
1219 
1220  /* write the code to a file */
1221 
1222  fprintf(fp, "%s", type_names[code].c_str());
1223 }
1224 
1225 /******************************************************************************
1226 Get a text line from a file and break it up into words.
1227 
1228 IMPORTANT: The calling routine call "free" on the returned pointer once
1229 finished with it.
1230 
1231 Entry:
1232  fp - file to read from
1233 
1234 Exit:
1235  nwords - number of words returned
1236  orig_line - the original line of characters
1237  returns a list of words from the line, or nullptr if end-of-file
1238 ******************************************************************************/
1239 
1240 vector<string> get_words(FILE* fp, string& orig_line)
1241 {
1242 #define BIG_STRING 4096
1243  char str[BIG_STRING];
1244 
1245  vector<string> words;
1246 
1247  ASSERT_(fp != nullptr);
1248 
1249  /* read in a line */
1250  char* result = fgets(str, BIG_STRING, fp);
1251  if (result == nullptr)
1252  {
1253  orig_line = string();
1254  return words;
1255  }
1256 
1257  orig_line = string(str);
1258  mrpt::system::tokenize(orig_line, " \t\r\n", words);
1259 
1260  return words;
1261 }
1262 
1263 /******************************************************************************
1264 Return the value of an item, given a pointer to it and its type.
1265 
1266 Entry:
1267  item - pointer to item
1268  type - data type that "item" points to
1269 
1270 Exit:
1271  returns a double-precision float that contains the value of the item
1272 ******************************************************************************/
1273 
1274 double get_item_value(char* item, int type)
1275 {
1276  unsigned char* puchar;
1277  char* pchar;
1278  short int* pshort;
1279  unsigned short int* pushort;
1280  int* pint;
1281  unsigned int* puint;
1282  float* pfloat;
1283  double* pdouble;
1284  int int_value;
1285  unsigned int uint_value;
1286  double double_value;
1287 
1288  switch (type)
1289  {
1290  case PLY_CHAR:
1291  pchar = (char*)item;
1292  int_value = *pchar;
1293  return ((double)int_value);
1294  case PLY_UCHAR:
1295  puchar = (unsigned char*)item;
1296  int_value = *puchar;
1297  return ((double)int_value);
1298  case PLY_SHORT:
1299  pshort = (short int*)item;
1300  int_value = *pshort;
1301  return ((double)int_value);
1302  case PLY_USHORT:
1303  pushort = (unsigned short int*)item;
1304  int_value = *pushort;
1305  return ((double)int_value);
1306  case PLY_INT:
1307  pint = (int*)item;
1308  int_value = *pint;
1309  return ((double)int_value);
1310  case PLY_UINT:
1311  puint = (unsigned int*)item;
1312  uint_value = *puint;
1313  return ((double)uint_value);
1314  case PLY_FLOAT:
1315  pfloat = (float*)item;
1316  double_value = *pfloat;
1317  return (double_value);
1318  case PLY_DOUBLE:
1319  pdouble = (double*)item;
1320  double_value = *pdouble;
1321  return (double_value);
1322  default:
1323  throw std::runtime_error(
1324  format("get_item_value: bad type = %d", type));
1325  }
1326 }
1327 
1328 /******************************************************************************
1329 Write out an item to a file as raw binary bytes.
1330 
1331 Entry:
1332  fp - file to write to
1333  int_val - integer version of item
1334  uint_val - unsigned integer version of item
1335  double_val - double-precision float version of item
1336  type - data type to write out
1337 ******************************************************************************/
1338 
1340  FILE* fp, int int_val, unsigned int uint_val, double double_val, int type)
1341 {
1342  unsigned char uchar_val;
1343  char char_val;
1344  unsigned short ushort_val;
1345  short short_val;
1346  float float_val;
1347 
1348  switch (type)
1349  {
1350  case PLY_CHAR:
1351  char_val = int_val;
1352  fwrite(&char_val, 1, 1, fp);
1353  break;
1354  case PLY_SHORT:
1355  short_val = int_val;
1356  fwrite(&short_val, 2, 1, fp);
1357  break;
1358  case PLY_INT:
1359  fwrite(&int_val, 4, 1, fp);
1360  break;
1361  case PLY_UCHAR:
1362  uchar_val = uint_val;
1363  fwrite(&uchar_val, 1, 1, fp);
1364  break;
1365  case PLY_USHORT:
1366  ushort_val = uint_val;
1367  fwrite(&ushort_val, 2, 1, fp);
1368  break;
1369  case PLY_UINT:
1370  fwrite(&uint_val, 4, 1, fp);
1371  break;
1372  case PLY_FLOAT:
1373  float_val = double_val;
1374  fwrite(&float_val, 4, 1, fp);
1375  break;
1376  case PLY_DOUBLE:
1377  fwrite(&double_val, 8, 1, fp);
1378  break;
1379  default:
1380  throw std::runtime_error(
1381  format("write_binary_item: bad type = %d", type));
1382  }
1383 }
1384 
1385 /******************************************************************************
1386 Write out an item to a file as ascii characters.
1387 
1388 Entry:
1389  fp - file to write to
1390  int_val - integer version of item
1391  uint_val - unsigned integer version of item
1392  double_val - double-precision float version of item
1393  type - data type to write out
1394 ******************************************************************************/
1395 
1397  FILE* fp, int int_val, unsigned int uint_val, double double_val, int type)
1398 {
1399  switch (type)
1400  {
1401  case PLY_CHAR:
1402  case PLY_SHORT:
1403  case PLY_INT:
1404  fprintf(fp, "%d ", int_val);
1405  break;
1406  case PLY_UCHAR:
1407  case PLY_USHORT:
1408  case PLY_UINT:
1409  fprintf(fp, "%u ", uint_val);
1410  break;
1411  case PLY_FLOAT:
1412  case PLY_DOUBLE:
1413  fprintf(fp, "%g ", double_val);
1414  break;
1415  default:
1416  throw std::runtime_error(
1417  format("write_ascii_item: bad type = %d", type));
1418  }
1419 }
1420 
1421 /******************************************************************************
1422 Get the value of an item that is in memory, and place the result
1423 into an integer, an unsigned integer and a double.
1424 
1425 Entry:
1426  ptr - pointer to the item
1427  type - data type supposedly in the item
1428 
1429 Exit:
1430  int_val - integer value
1431  uint_val - unsigned integer value
1432  double_val - double-precision floating point value
1433 ******************************************************************************/
1434 
1436  void* ptr, int type, int* int_val, unsigned int* uint_val,
1437  double* double_val)
1438 {
1439  switch (type)
1440  {
1441  case PLY_CHAR:
1442  *int_val = *((char*)ptr);
1443  *uint_val = *int_val;
1444  *double_val = *int_val;
1445  break;
1446  case PLY_UCHAR:
1447  *uint_val = *((unsigned char*)ptr);
1448  *int_val = *uint_val;
1449  *double_val = *uint_val;
1450  break;
1451  case PLY_SHORT:
1452  *int_val = *((short int*)ptr);
1453  *uint_val = *int_val;
1454  *double_val = *int_val;
1455  break;
1456  case PLY_USHORT:
1457  *uint_val = *((unsigned short int*)ptr);
1458  *int_val = *uint_val;
1459  *double_val = *uint_val;
1460  break;
1461  case PLY_INT:
1462  *int_val = *((int*)ptr);
1463  *uint_val = *int_val;
1464  *double_val = *int_val;
1465  break;
1466  case PLY_UINT:
1467  *uint_val = *((unsigned int*)ptr);
1468  *int_val = *uint_val;
1469  *double_val = *uint_val;
1470  break;
1471  case PLY_FLOAT:
1472  *double_val = *((float*)ptr);
1473  *int_val = *double_val;
1474  *uint_val = *double_val;
1475  break;
1476  case PLY_DOUBLE:
1477  *double_val = *((double*)ptr);
1478  *int_val = *double_val;
1479  *uint_val = *double_val;
1480  break;
1481  default:
1482  throw std::runtime_error(
1483  format("get_stored_item: bad type = %d", type));
1484  }
1485 }
1486 
1487 /******************************************************************************
1488 Get the value of an item from a binary file, and place the result
1489 into an integer, an unsigned integer and a double.
1490 
1491 Entry:
1492  fp - file to get item from
1493  type - data type supposedly in the word
1494 
1495 Exit:
1496  int_val - integer value
1497  uint_val - unsigned integer value
1498  double_val - double-precision floating point value
1499 
1500 Return: 0: On error
1501 ******************************************************************************/
1502 
1504  FILE* fp, int bin_file_type, int type, int* int_val, unsigned int* uint_val,
1505  double* double_val)
1506 {
1507  char c[8];
1508  void* ptr;
1509 
1510  ptr = (void*)c;
1511 
1512  switch (type)
1513  {
1514  case PLY_CHAR:
1515  if (fread(ptr, 1, 1, fp) != 1) return 0;
1516  *int_val = *((char*)ptr);
1517  *uint_val = *int_val;
1518  *double_val = *int_val;
1519  break;
1520  case PLY_UCHAR:
1521  if (fread(ptr, 1, 1, fp) != 1) return 0;
1522  *uint_val = *((unsigned char*)ptr);
1523  *int_val = *uint_val;
1524  *double_val = *uint_val;
1525  break;
1526  case PLY_SHORT:
1527  if (fread(ptr, 2, 1, fp) != 1) return 0;
1528  *int_val = *((short int*)ptr);
1529  *uint_val = *int_val;
1530  *double_val = *int_val;
1531  break;
1532  case PLY_USHORT:
1533  if (fread(ptr, 2, 1, fp) != 1) return 0;
1534  *uint_val = *((unsigned short int*)ptr);
1535  *int_val = *uint_val;
1536  *double_val = *uint_val;
1537  break;
1538  case PLY_INT:
1539  if (fread(ptr, 4, 1, fp) != 1) return 0;
1540  *int_val = *((int*)ptr);
1541  *uint_val = *int_val;
1542  *double_val = *int_val;
1543  break;
1544  case PLY_UINT:
1545  if (fread(ptr, 4, 1, fp) != 1) return 0;
1546  *uint_val = *((unsigned int*)ptr);
1547  *int_val = *uint_val;
1548  *double_val = *uint_val;
1549  break;
1550  case PLY_FLOAT:
1551  if (fread(ptr, 4, 1, fp) != 1) return 0;
1552  *double_val = *((float*)ptr);
1553  *int_val = *double_val;
1554  *uint_val = *double_val;
1555  break;
1556  case PLY_DOUBLE:
1557  if (fread(ptr, 8, 1, fp) != 1) return 0;
1558  *double_val = *((double*)ptr);
1559  *int_val = *double_val;
1560  *uint_val = *double_val;
1561  break;
1562  default:
1563  throw std::runtime_error(
1564  format("get_binary_item: bad type = %d", type));
1565  }
1566 
1567 // Added by JL:
1568 // If the Big/Little endian format in the file is different than the native
1569 // format, do the conversion:
1570 #if MRPT_IS_BIG_ENDIAN
1571  const bool do_reverse = (bin_file_type == PLY_BINARY_LE);
1572 #else
1573  const bool do_reverse = (bin_file_type == PLY_BINARY_BE);
1574 #endif
1575 
1576  if (do_reverse)
1577  {
1578  int int_val2 = *int_val;
1579  unsigned int uint_val2 = *uint_val;
1580  double double_val2 = *double_val;
1581  mrpt::reverseBytes(int_val2, *int_val);
1582  mrpt::reverseBytes(uint_val2, *uint_val);
1583  mrpt::reverseBytes(double_val2, *double_val);
1584  }
1585 
1586  return 1;
1587 }
1588 
1589 /******************************************************************************
1590 Extract the value of an item from an ascii word, and place the result
1591 into an integer, an unsigned integer and a double.
1592 
1593 Entry:
1594  word - word to extract value from
1595  type - data type supposedly in the word
1596 
1597 Exit:
1598  int_val - integer value
1599  uint_val - unsigned integer value
1600  double_val - double-precision floating point value
1601 ******************************************************************************/
1602 
1604  const char* word, int type, int* int_val, unsigned int* uint_val,
1605  double* double_val)
1606 {
1607  switch (type)
1608  {
1609  case PLY_CHAR:
1610  case PLY_UCHAR:
1611  case PLY_SHORT:
1612  case PLY_USHORT:
1613  case PLY_INT:
1614  *int_val = atoi(word);
1615  *uint_val = *int_val;
1616  *double_val = *int_val;
1617  break;
1618 
1619  case PLY_UINT:
1620  *uint_val = strtoul(word, (char**)nullptr, 10);
1621  *int_val = *uint_val;
1622  *double_val = *uint_val;
1623  break;
1624 
1625  case PLY_FLOAT:
1626  case PLY_DOUBLE:
1627  *double_val = atof(word);
1628  *int_val = (int)*double_val;
1629  *uint_val = (unsigned int)*double_val;
1630  break;
1631 
1632  default:
1633  throw std::runtime_error(
1634  format("get_ascii_item: bad type = %d", type));
1635  }
1636 }
1637 
1638 /******************************************************************************
1639 Store a value into a place being pointed to, guided by a data type.
1640 
1641 Entry:
1642  item - place to store value
1643  type - data type
1644  int_val - integer version of value
1645  uint_val - unsigned integer version of value
1646  double_val - double version of value
1647 
1648 Exit:
1649  item - pointer to stored value
1650 ******************************************************************************/
1651 
1653  char* item, int type, int int_val, unsigned int uint_val, double double_val)
1654 {
1655  unsigned char* puchar;
1656  short int* pshort;
1657  unsigned short int* pushort;
1658  int* pint;
1659  unsigned int* puint;
1660  float* pfloat;
1661  double* pdouble;
1662 
1663  switch (type)
1664  {
1665  case PLY_CHAR:
1666  *item = int_val;
1667  break;
1668  case PLY_UCHAR:
1669  puchar = (unsigned char*)item;
1670  *puchar = uint_val;
1671  break;
1672  case PLY_SHORT:
1673  pshort = (short*)item;
1674  *pshort = int_val;
1675  break;
1676  case PLY_USHORT:
1677  pushort = (unsigned short*)item;
1678  *pushort = uint_val;
1679  break;
1680  case PLY_INT:
1681  pint = (int*)item;
1682  *pint = int_val;
1683  break;
1684  case PLY_UINT:
1685  puint = (unsigned int*)item;
1686  *puint = uint_val;
1687  break;
1688  case PLY_FLOAT:
1689  pfloat = (float*)item;
1690  *pfloat = double_val;
1691  break;
1692  case PLY_DOUBLE:
1693  pdouble = (double*)item;
1694  *pdouble = double_val;
1695  break;
1696  default:
1697  throw std::runtime_error(format("store_item: bad type = %d", type));
1698  }
1699 }
1700 
1701 /******************************************************************************
1702 Add an element to a PLY file descriptor.
1703 
1704 Entry:
1705  plyfile - PLY file descriptor
1706  words - list of words describing the element
1707  nwords - number of words in the list
1708 ******************************************************************************/
1709 
1710 void add_element(PlyFile* plyfile, const vector<string>& words)
1711 {
1712  /* create the new element */
1713  plyfile->elems.emplace_back();
1714 
1715  PlyElement* elem = &(*plyfile->elems.rbegin());
1716  elem->name = words[1];
1717  elem->num = atoi(words[2].c_str());
1718 }
1719 
1720 /******************************************************************************
1721 Return the type of a property, given the name of the property.
1722 
1723 Entry:
1724  name - name of property type
1725 
1726 Exit:
1727  returns integer code for property, or 0 if not found
1728 ******************************************************************************/
1729 
1730 int get_prop_type(const string& type_name)
1731 {
1732  int i;
1733 
1734  for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
1735  if (type_name == type_names[i]) return (i);
1736 
1737  /* if we get here, we didn't find the type */
1738  return (0);
1739 }
1740 
1741 /******************************************************************************
1742 Add a property to a PLY file descriptor.
1743 
1744 Entry:
1745  plyfile - PLY file descriptor
1746  words - list of words describing the property
1747  nwords - number of words in the list
1748 ******************************************************************************/
1749 
1750 void add_property(PlyFile* plyfile, const vector<string>& words)
1751 {
1752  /* add this property to the list of properties of the current element */
1753  PlyElement* elem = &(*plyfile->elems.rbegin());
1754 
1755  elem->props.emplace_back();
1756 
1757  PlyProperty* prop = &(*elem->props.rbegin());
1758 
1759  /* create the new property */
1760 
1761  if (words[1] == "list")
1762  { /* is a list */
1763  prop->count_external = get_prop_type(words[2]);
1764  prop->external_type = get_prop_type(words[3]);
1765  prop->name = words[4];
1766  prop->is_list = 1;
1767  }
1768  else
1769  { /* not a list */
1770  prop->external_type = get_prop_type(words[1]);
1771  prop->name = words[2];
1772  prop->is_list = 0;
1773  }
1774 }
1775 
1776 /******************************************************************************
1777 Add a comment to a PLY file descriptor.
1778 
1779 Entry:
1780  plyfile - PLY file descriptor
1781  line - line containing comment
1782 ******************************************************************************/
1783 
1784 void add_comment(PlyFile* plyfile, const string& line)
1785 {
1786  /* skip over "comment" and leading spaces and tabs */
1787  ply_put_comment(plyfile, mrpt::system::trim(line.substr(7)));
1788 }
1789 
1790 /******************************************************************************
1791 Add a some object information to a PLY file descriptor.
1792 
1793 Entry:
1794  plyfile - PLY file descriptor
1795  line - line containing text info
1796 ******************************************************************************/
1797 
1798 void add_obj_info(PlyFile* plyfile, const string& line)
1799 {
1800  /* skip over "obj_info" and leading spaces and tabs */
1801  ply_put_obj_info(plyfile, mrpt::system::trim(line.substr(8)));
1802 }
1803 
1804 /******************************************************************************
1805 Copy a property.
1806 ******************************************************************************/
1807 
1808 void copy_property(PlyProperty* dest, const PlyProperty* src) { *dest = *src; }
1809 const float VAL_NOT_SET = -1e10;
1810 
1811 struct TVertex
1812 {
1813  float x, y, z;
1814  float r, g, b;
1815  float intensity;
1816 };
1817 
1819  {/* list of property information for a vertex */
1820  // is_list count_external
1821  // count_internal count_offset
1822  {"x", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, x), 0, 0, 0, 0},
1823  {"y", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, y), 0, 0, 0, 0},
1824  {"z", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, z), 0, 0, 0, 0},
1825  {"intensity", PLY_FLOAT, PLY_FLOAT, offsetof(TVertex, intensity), 0, 0, 0,
1826  0}};
1827 
1828 struct TFace
1829 {
1830  float intensity; /* this user attaches intensity to faces */
1831  unsigned char nverts; /* number of vertex indices in list */
1832  int* verts; /* vertex index list */
1833 };
1834 
1836  {/* list of property information for a vertex */
1837  {"intensity", PLY_FLOAT, PLY_FLOAT, offsetof(TFace, intensity), 0, 0, 0,
1838  0},
1839  {"vertex_indices", PLY_INT, PLY_INT, offsetof(TFace, verts), 1, PLY_UCHAR,
1840  PLY_UCHAR, offsetof(TFace, nverts)}};
1841 
1842 /*
1843  Loads from a PLY file.
1844 */
1845 bool PLY_Importer::loadFromPlyFile(
1846  const std::string& filename, std::vector<std::string>* file_comments,
1847  std::vector<std::string>* file_obj_info)
1848 {
1849  try
1850  {
1851  /* open a PLY file for reading */
1852  vector<string> elist; // element names
1853  int file_type;
1854  float version;
1855  PlyFile* ply =
1856  ply_open_for_reading(filename.c_str(), elist, &file_type, &version);
1857 
1858  /* go through each kind of element that we learned is in the file */
1859  /* and read them */
1860 
1861  for (const auto& elem_name : elist)
1862  {
1863  /* get the description of the first element */
1864  int num_elems = 0, nprops = 0;
1865 
1866  // vector<PlyProperty> plist =
1867  ply_get_element_description(ply, elem_name, num_elems, nprops);
1868 
1869  /* print the name of the element, for debugging */
1870  // printf ("element %s %d\n", elem_name, num_elems);
1871 
1872  /* if we're on vertex elements, read them in */
1873  if ("vertex" == elem_name)
1874  {
1875  /* set up for getting vertex elements */
1876  for (const auto& vert_prop : vert_props)
1877  ply_get_property(ply, elem_name, &vert_prop);
1878 
1879  /* grab all the vertex elements */
1880  this->PLY_import_set_vertex_count(num_elems);
1881  for (int j = 0; j < num_elems; j++)
1882  {
1883  TVertex pt;
1884  pt.x = pt.y = pt.z = pt.r = pt.g = pt.b = pt.intensity =
1885  VAL_NOT_SET;
1886 
1887  /* grab an element from the file */
1888  ply_get_element(ply, reinterpret_cast<void*>(&pt));
1889  const TPoint3Df xyz(pt.x, pt.y, pt.z);
1890  if (pt.intensity != VAL_NOT_SET)
1891  { // Grayscale
1892  const TColorf col(
1893  pt.intensity, pt.intensity, pt.intensity);
1894  this->PLY_import_set_vertex(j, xyz, &col);
1895  }
1896  else if (
1897  pt.r != VAL_NOT_SET && pt.g != VAL_NOT_SET &&
1898  pt.b != VAL_NOT_SET)
1899  { // RGB
1900  const TColorf col(pt.r, pt.g, pt.b);
1901  this->PLY_import_set_vertex(j, xyz, &col);
1902  }
1903  else
1904  { // No color
1905  this->PLY_import_set_vertex(j, xyz);
1906  }
1907  }
1908  }
1909 
1910  // print out the properties we got, for debugging
1911  // for (int j = 0; j < nprops; j++)
1912  // printf ("property %s\n", plist[j]->name);
1913  }
1914 
1915  // grab and print out the comments in the file
1916  if (file_comments)
1917  {
1918  vector<string> strs;
1919  ply_get_comments(ply, strs);
1920  *file_comments = std::vector<std::string>(strs);
1921  }
1922 
1923  // grab and print out the object information
1924  if (file_obj_info)
1925  {
1926  vector<string> strs;
1927  ply_get_obj_info(ply, strs);
1928  *file_obj_info = std::vector<std::string>(strs);
1929  }
1930 
1931  /* close the PLY file */
1932  ply_close(ply);
1933 
1934  // All OK:
1935  m_ply_import_last_error = std::string();
1936  return true;
1937  }
1938  catch (const std::exception& e)
1939  {
1940  // Return error:
1941  m_ply_import_last_error = std::string(e.what());
1942  return false;
1943  }
1944 }
1945 
1946 bool PLY_Exporter::saveToPlyFile(
1947  const std::string& filename, bool save_in_binary,
1948  const std::vector<std::string>& file_comments,
1949  const std::vector<std::string>& file_obj_info) const
1950 {
1951  try
1952  {
1953  /* list of the kinds of elements in the user's object */
1954  vector<string> elem_names;
1955  elem_names.emplace_back("vertex");
1956  elem_names.emplace_back("face");
1957 
1958  /* create the vertex index lists for the faces */
1959  // for (i = 0; i < nfaces; i++)
1960  // faces[i].verts = vert_ptrs[i];
1961 
1962  /* open either a binary or ascii PLY file for writing */
1963  /* (the file will be called "test.ply" because the routines */
1964  /* enforce the .ply filename extension) */
1965 
1966  float version;
1968  filename.c_str(), elem_names,
1969  save_in_binary ?
1970 #if MRPT_IS_BIG_ENDIAN
1972 #else
1974 #endif
1975  : PLY_ASCII,
1976  &version);
1977 
1978  /* describe what properties go into the vertex and face elements */
1979 
1980  const size_t nverts = this->PLY_export_get_vertex_count();
1981  const size_t nfaces = this->PLY_export_get_face_count();
1982 
1983  if (nverts)
1984  {
1985  // Find out if we have color:
1986  TPoint3Df pt;
1987  bool pt_has_color;
1988  TColorf pt_color;
1989  this->PLY_export_get_vertex(0, pt, pt_has_color, pt_color);
1990 
1991  ply_element_count(ply, "vertex", nverts);
1992  ply_describe_property(ply, "vertex", &vert_props[0]); // x
1993  ply_describe_property(ply, "vertex", &vert_props[1]); // y
1994  ply_describe_property(ply, "vertex", &vert_props[2]); // z
1995 
1996  if (pt_has_color)
1998  ply, "vertex", &vert_props[3]); // intensity
1999  }
2000 
2001  ply_element_count(ply, "face", nfaces);
2002  for (const auto& face_prop : face_props)
2003  ply_describe_property(ply, "face", &face_prop);
2004 
2005  /* write a comment and an object information field */
2006  for (const auto& file_comment : file_comments)
2007  ply_put_comment(ply, file_comment.c_str());
2008 
2009  for (const auto& k : file_obj_info) ply_put_obj_info(ply, k.c_str());
2010 
2011  /* we have described exactly what we will put in the file, so */
2012  /* we are now done with the header info */
2013  ply_header_complete(ply);
2014 
2015  /* set up and write the vertex elements */
2016  ply_put_element_setup(ply, "vertex");
2017  for (size_t i = 0; i < nverts; i++)
2018  {
2019  TPoint3Df pt;
2020  bool pt_has_color;
2021  TColorf pt_color;
2022  this->PLY_export_get_vertex(i, pt, pt_has_color, pt_color);
2023 
2024  TVertex ver;
2025  ver.x = pt.x;
2026  ver.y = pt.y;
2027  ver.z = pt.z;
2028 
2029  if (pt_has_color)
2030  ver.intensity =
2031  (1.0f / 3.0f) * (pt_color.R + pt_color.G + pt_color.B);
2032  else
2033  ver.intensity = 0.5;
2034 
2035  ply_put_element(ply, (void*)&ver);
2036  }
2037 
2038  /* set up and write the face elements */
2039  /* ply_put_element_setup (ply, "face");
2040  for (size_t i = 0; i < nfaces; i++)
2041  {
2042  TFace face;
2043  this->PLY_export_get_face(...);
2044  ply_put_element (ply, (void *) &face);
2045  }*/
2046 
2047  /* close the PLY file */
2048  ply_close(ply);
2049 
2050  // All OK:
2051  m_ply_export_last_error = std::string();
2052  return true;
2053  }
2054  catch (const std::exception& e)
2055  {
2056  // Return error:
2057  m_ply_export_last_error = std::string(e.what());
2058  return false;
2059  }
2060 }
#define offsetof(_structure, _field)
Definition: util.h:54
#define BIG_STRING
const char DONT_STORE_PROP
void ply_put_obj_info(PlyFile *plyfile, const string &obj_info)
GLdouble GLdouble z
Definition: glext.h:3879
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: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:36
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:3682
GLuint src
Definition: glext.h:7397
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:7397
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
const int ply_type_size[]
This base provides a set of functions for maths stuff.
Lightweight 3D point (float version).
Definition: TPoint3D.h:21
const float VAL_NOT_SET
const char STORE_PROP
GLuint index
Definition: glext.h:4068
const GLubyte * c
Definition: glext.h:6406
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:6372
PlyElement * which_elem
#define PLY_BINARY_LE
GLubyte GLubyte b
Definition: glext.h:6372
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:4116
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:410
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 *)
A RGB color - floats in the range [0,1].
Definition: TColor.h:77
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
GLuint const GLchar * name
Definition: glext.h:4068
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:3542
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)
GLenum GLsizei GLenum format
Definition: glext.h:3535
void store_item(char *, int, int, unsigned int, double)
void ply_header_complete(PlyFile *plyfile)
GLsizeiptr size
Definition: glext.h:3934
GLenum GLint x
Definition: glext.h:3542
unsigned char nverts
void ply_get_info(PlyFile *ply, float *version, int *file_type)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:3532
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: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019