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



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020