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