ply.c
Go to the documentation of this file.
00001 /*
00002 
00003 The interface routines for reading and writing PLY polygon files.
00004 
00005 Greg Turk
00006 
00007 ---------------------------------------------------------------
00008 
00009 A PLY file contains a single polygonal _object_.
00010 
00011 An object is composed of lists of _elements_.  Typical elements are
00012 vertices, faces, edges and materials.
00013 
00014 Each type of element for a given object has one or more _properties_
00015 associated with the element type.  For instance, a vertex element may
00016 have as properties the floating-point values x,y,z and the three unsigned
00017 chars representing red, green and blue.
00018 
00019 -----------------------------------------------------------------------
00020 
00021 Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.   
00022   
00023 Permission to use, copy, modify and distribute this software and its   
00024 documentation for any purpose is hereby granted without fee, provided   
00025 that the above copyright notice and this permission notice appear in   
00026 all copies of this software and that you do not sell the software.   
00027   
00028 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
00029 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
00030 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
00031 
00032 */
00033 
00034 #include <assert.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <math.h>
00038 #include <string.h>
00039 #include <ply.h>
00040 
00041 char *type_names[] = {  /* names of scalar types */
00042 "invalid",
00043 "int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
00044 };
00045 
00046 char *old_type_names[] = {  /* old names of types for backward compatability */
00047 "invalid",
00048 "char", "short", "int", "uchar", "ushort", "uint", "float", "double",
00049 };
00050 
00051 int ply_type_size[] = {
00052   0, 1, 2, 4, 1, 2, 4, 4, 8
00053 };
00054 
00055 #define NO_OTHER_PROPS  -1
00056 
00057 #define DONT_STORE_PROP  0
00058 #define STORE_PROP       1
00059 
00060 #define OTHER_PROP       0
00061 #define NAMED_PROP       1
00062 
00063 /* returns 1 if strings are equal, 0 if not */
00064 int equal_strings(char *, char *);
00065 
00066 /* find an element in a plyfile's list */
00067 PlyElement *find_element(PlyFile *, char *);
00068 
00069 /* find a property in an element's list */
00070 PlyProperty *find_property(PlyElement *, char *, int *);
00071 
00072 /* write to a file the word describing a PLY file data type */
00073 void write_scalar_type (FILE *, int);
00074 
00075 /* read a line from a file and break it up into separate words */
00076 char **get_words(FILE *, int *, char **);
00077 
00078 /* write an item to a file */
00079 void write_binary_item(FILE *, int, unsigned int, double, int);
00080 void write_ascii_item(FILE *, int, unsigned int, double, int);
00081 
00082 /* add information to a PLY file descriptor */
00083 void add_element(PlyFile *, char **, int);
00084 void add_property(PlyFile *, char **, int);
00085 void add_comment(PlyFile *, char *);
00086 void add_obj_info(PlyFile *, char *);
00087 
00088 /* copy a property */
00089 void copy_property(PlyProperty *, PlyProperty *);
00090 
00091 /* store a value into where a pointer and a type specify */
00092 void store_item(char *, int, int, unsigned int, double);
00093 
00094 /* return the value of a stored item */
00095 void get_stored_item( void *, int, int *, unsigned int *, double *);
00096 
00097 /* return the value stored in an item, given ptr to it and its type */
00098 double get_item_value(char *, int);
00099 
00100 /* get binary or ascii item and store it according to ptr and type */
00101 void get_ascii_item(char *, int, int *, unsigned int *, double *);
00102 void get_binary_item(FILE *, int, int *, unsigned int *, double *);
00103 
00104 /* get a bunch of elements from a file */
00105 void ascii_get_element(PlyFile *, char *);
00106 void binary_get_element(PlyFile *, char *);
00107 
00108 /* memory allocation */
00109 static char *my_alloc(int, int, char *);
00110 
00111 
00112 /*************/
00113 /*  Writing  */
00114 /*************/
00115 
00116 
00117 /******************************************************************************
00118 Given a file pointer, get ready to write PLY data to the file.
00119 
00120 Entry:
00121   fp         - the given file pointer
00122   nelems     - number of elements in object
00123   elem_names - list of element names
00124   file_type  - file type, either ascii or binary
00125 
00126 Exit:
00127   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00128 ******************************************************************************/
00129 
00130 PlyFile *ply_write(
00131   FILE *fp,
00132   int nelems,
00133   char **elem_names,
00134   int file_type
00135 )
00136 {
00137   int i;
00138   PlyFile *plyfile;
00139   PlyElement *elem;
00140 
00141   /* check for NULL file pointer */
00142   if (fp == NULL)
00143     return (NULL);
00144 
00145   /* create a record for this object */
00146 
00147   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00148   plyfile->file_type = file_type;
00149   plyfile->num_comments = 0;
00150   plyfile->num_obj_info = 0;
00151   plyfile->num_elem_types = nelems;
00152   plyfile->version = 1.0;
00153   plyfile->fp = fp;
00154   plyfile->other_elems = NULL;
00155 
00156   /* tuck aside the names of the elements */
00157 
00158   plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
00159   for (i = 0; i < nelems; i++) {
00160     elem = (PlyElement *) myalloc (sizeof (PlyElement));
00161     plyfile->elems[i] = elem;
00162     elem->name = strdup (elem_names[i]);
00163     elem->num = 0;
00164     elem->nprops = 0;
00165   }
00166 
00167   /* return pointer to the file descriptor */
00168   return (plyfile);
00169 }
00170 
00171 
00172 /******************************************************************************
00173 Open a polygon file for writing.
00174 
00175 Entry:
00176   filename   - name of file to read from
00177   nelems     - number of elements in object
00178   elem_names - list of element names
00179   file_type  - file type, either ascii or binary
00180 
00181 Exit:
00182   returns a file identifier, used to refer to this file, or NULL if error
00183 ******************************************************************************/
00184 
00185 PlyFile *open_for_writing_ply(
00186   char *filename,
00187   int nelems,
00188   char **elem_names,
00189   int file_type
00190 )
00191 {
00192   int i;
00193   PlyFile *plyfile;
00194   PlyElement *elem;
00195   char *name;
00196   FILE *fp;
00197 
00198   /* tack on the extension .ply, if necessary */
00199 
00200   name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
00201   strcpy (name, filename);
00202   if (strlen (name) < 4 ||
00203       strcmp (name + strlen (name) - 4, ".ply") != 0)
00204       strcat (name, ".ply");
00205 
00206   /* open the file for writing */
00207 
00208   fp = fopen (name, "w");
00209   if (fp == NULL) {
00210     return (NULL);
00211   }
00212 
00213   /* create the actual PlyFile structure */
00214 
00215   plyfile = ply_write (fp, nelems, elem_names, file_type);
00216   if (plyfile == NULL)
00217     return (NULL);
00218 
00219   /* return pointer to the file descriptor */
00220   return (plyfile);
00221 }
00222 
00223 
00224 /******************************************************************************
00225 Describe an element, including its properties and how many will be written
00226 to the file.
00227 
00228 Entry:
00229   plyfile   - file identifier
00230   elem_name - name of element that information is being specified about
00231   nelems    - number of elements of this type to be written
00232   nprops    - number of properties contained in the element
00233   prop_list - list of properties
00234 ******************************************************************************/
00235 
00236 void element_layout_ply(
00237   PlyFile *plyfile,
00238   char *elem_name,
00239   int nelems,
00240   int nprops,
00241   PlyProperty *prop_list
00242 )
00243 {
00244   int i;
00245   PlyElement *elem;
00246   PlyProperty *prop;
00247 
00248   /* look for appropriate element */
00249   elem = find_element (plyfile, elem_name);
00250   if (elem == NULL) {
00251     fprintf(stderr,"element_layout_ply: can't find element '%s'\n",elem_name);
00252     exit (-1);
00253   }
00254 
00255   elem->num = nelems;
00256 
00257   /* copy the list of properties */
00258 
00259   elem->nprops = nprops;
00260   elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
00261   elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
00262 
00263   for (i = 0; i < nprops; i++) {
00264     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00265     elem->props[i] = prop;
00266     elem->store_prop[i] = NAMED_PROP;
00267     copy_property (prop, &prop_list[i]);
00268   }
00269 }
00270 
00271 
00272 /******************************************************************************
00273 Describe a property of an element.
00274 
00275 Entry:
00276   plyfile   - file identifier
00277   elem_name - name of element that information is being specified about
00278   prop      - the new property
00279 ******************************************************************************/
00280 
00281 void ply_describe_property(
00282   PlyFile *plyfile,
00283   char *elem_name,
00284   PlyProperty *prop
00285 )
00286 {
00287   PlyElement *elem;
00288   PlyProperty *elem_prop;
00289 
00290   /* look for appropriate element */
00291   elem = find_element (plyfile, elem_name);
00292   if (elem == NULL) {
00293     fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
00294             elem_name);
00295     return;
00296   }
00297 
00298   /* create room for new property */
00299 
00300   if (elem->nprops == 0) {
00301     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
00302     elem->store_prop = (char *) myalloc (sizeof (char));
00303     elem->nprops = 1;
00304   }
00305   else {
00306     elem->nprops++;
00307     elem->props = (PlyProperty **)
00308                   realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
00309     elem->store_prop = (char *)
00310                   realloc (elem->store_prop, sizeof (char) * elem->nprops);
00311   }
00312 
00313   /* copy the new property */
00314 
00315   elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00316   elem->props[elem->nprops - 1] = elem_prop;
00317   elem->store_prop[elem->nprops - 1] = NAMED_PROP;
00318   copy_property (elem_prop, prop);
00319 }
00320 
00321 
00322 /******************************************************************************
00323 State how many of a given element will be written.
00324 
00325 Entry:
00326   plyfile   - file identifier
00327   elem_name - name of element that information is being specified about
00328   nelems    - number of elements of this type to be written
00329 ******************************************************************************/
00330 
00331 void element_count_ply(
00332   PlyFile *plyfile,
00333   char *elem_name,
00334   int nelems
00335 )
00336 {
00337   int i;
00338   PlyElement *elem;
00339   PlyProperty *prop;
00340 
00341   /* look for appropriate element */
00342   elem = find_element (plyfile, elem_name);
00343   if (elem == NULL) {
00344     fprintf(stderr,"element_count_ply: can't find element '%s'\n",elem_name);
00345     exit (-1);
00346   }
00347 
00348   elem->num = nelems;
00349 }
00350 
00351 
00352 /******************************************************************************
00353 Signal that we've described everything a PLY file's header and that the
00354 header should be written to the file.
00355 
00356 Entry:
00357   plyfile - file identifier
00358 ******************************************************************************/
00359 
00360 void header_complete_ply(PlyFile *plyfile)
00361 {
00362   int i,j;
00363   FILE *fp = plyfile->fp;
00364   PlyElement *elem;
00365   PlyProperty *prop;
00366 
00367   fprintf (fp, "ply\n");
00368 
00369   switch (plyfile->file_type) {
00370     case PLY_ASCII:
00371       fprintf (fp, "format ascii 1.0\n");
00372       break;
00373     case PLY_BINARY_BE:
00374       fprintf (fp, "format binary_big_endian 1.0\n");
00375       break;
00376     case PLY_BINARY_LE:
00377       fprintf (fp, "format binary_little_endian 1.0\n");
00378       break;
00379     default:
00380       fprintf (stderr, "ply_header_complete: bad file type = %d\n",
00381                plyfile->file_type);
00382       exit (-1);
00383   }
00384 
00385   /* write out the comments */
00386 
00387   for (i = 0; i < plyfile->num_comments; i++)
00388     fprintf (fp, "comment %s\n", plyfile->comments[i]);
00389 
00390   /* write out object information */
00391 
00392   for (i = 0; i < plyfile->num_obj_info; i++)
00393     fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
00394 
00395   /* write out information about each element */
00396 
00397   for (i = 0; i < plyfile->num_elem_types; i++) {
00398 
00399     elem = plyfile->elems[i];
00400     fprintf (fp, "element %s %d\n", elem->name, elem->num);
00401 
00402     /* write out each property */
00403     for (j = 0; j < elem->nprops; j++) {
00404       prop = elem->props[j];
00405       if (prop->is_list == PLY_LIST) {
00406         fprintf (fp, "property list ");
00407         write_scalar_type (fp, prop->count_external);
00408         fprintf (fp, " ");
00409         write_scalar_type (fp, prop->external_type);
00410         fprintf (fp, " %s\n", prop->name);
00411       }
00412       else if (prop->is_list == PLY_STRING) {
00413         fprintf (fp, "property string");
00414         fprintf (fp, " %s\n", prop->name);
00415       }
00416       else {
00417         fprintf (fp, "property ");
00418         write_scalar_type (fp, prop->external_type);
00419         fprintf (fp, " %s\n", prop->name);
00420       }
00421     }
00422   }
00423 
00424   fprintf (fp, "end_header\n");
00425 }
00426 
00427 
00428 /******************************************************************************
00429 Specify which elements are going to be written.  This should be called
00430 before a call to the routine ply_put_element().
00431 
00432 Entry:
00433   plyfile   - file identifier
00434   elem_name - name of element we're talking about
00435 ******************************************************************************/
00436 
00437 void put_element_setup_ply(PlyFile *plyfile, char *elem_name)
00438 {
00439   PlyElement *elem;
00440 
00441   elem = find_element (plyfile, elem_name);
00442   if (elem == NULL) {
00443     fprintf(stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name);
00444     exit (-1);
00445   }
00446 
00447   plyfile->which_elem = elem;
00448 }
00449 
00450 
00451 /******************************************************************************
00452 Write an element to the file.  This routine assumes that we're
00453 writing the type of element specified in the last call to the routine
00454 put_element_setup_ply().
00455 
00456 Entry:
00457   plyfile  - file identifier
00458   elem_ptr - pointer to the element
00459 ******************************************************************************/
00460 
00461 void put_element_ply(PlyFile *plyfile, void *elem_ptr)
00462 {
00463   int i,j,k;
00464   FILE *fp = plyfile->fp;
00465   PlyElement *elem;
00466   PlyProperty *prop;
00467   char *item;
00468   char *elem_data;
00469   char **item_ptr;
00470   int list_count;
00471   int item_size;
00472   int int_val;
00473   unsigned int uint_val;
00474   double double_val;
00475   char **other_ptr;
00476 
00477   elem = plyfile->which_elem;
00478   elem_data = (char *) elem_ptr;
00479   other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
00480 
00481   /* write out either to an ascii or binary file */
00482 
00483   if (plyfile->file_type == PLY_ASCII) {
00484 
00485     /* write an ascii file */
00486 
00487     /* write out each property of the element */
00488     for (j = 0; j < elem->nprops; j++) {
00489 
00490       prop = elem->props[j];
00491 
00492       if (elem->store_prop[j] == OTHER_PROP)
00493         elem_data = *other_ptr;
00494       else
00495         elem_data = (char *) elem_ptr;
00496 
00497       if (prop->is_list == PLY_LIST) {  /* list */
00498         item = elem_data + prop->count_offset;
00499         get_stored_item ((void *) item, prop->count_internal,
00500                          &int_val, &uint_val, &double_val);
00501         write_ascii_item (fp, int_val, uint_val, double_val,
00502                           prop->count_external);
00503         list_count = uint_val;
00504         item_ptr = (char **) (elem_data + prop->offset);
00505         item = item_ptr[0];
00506         item_size = ply_type_size[prop->internal_type];
00507         for (k = 0; k < list_count; k++) {
00508           get_stored_item ((void *) item, prop->internal_type,
00509                            &int_val, &uint_val, &double_val);
00510           write_ascii_item (fp, int_val, uint_val, double_val,
00511                             prop->external_type);
00512           item += item_size;
00513         }
00514       }
00515       else if (prop->is_list == PLY_STRING) {  /* string */
00516         char **str;
00517         item = elem_data + prop->offset;
00518         str = (char **) item;
00519         fprintf (fp, "\"%s\"", *str);
00520       }
00521       else {                                  /* scalar */
00522         item = elem_data + prop->offset;
00523         get_stored_item ((void *) item, prop->internal_type,
00524                          &int_val, &uint_val, &double_val);
00525         write_ascii_item (fp, int_val, uint_val, double_val,
00526                           prop->external_type);
00527       }
00528     }
00529 
00530     fprintf (fp, "\n");
00531   }
00532   else {
00533 
00534     /* write a binary file */
00535 
00536     /* write out each property of the element */
00537     for (j = 0; j < elem->nprops; j++) {
00538       prop = elem->props[j];
00539       if (elem->store_prop[j] == OTHER_PROP)
00540         elem_data = *other_ptr;
00541       else
00542         elem_data = (char *) elem_ptr;
00543       if (prop->is_list == PLY_LIST) {   /* list */
00544         item = elem_data + prop->count_offset;
00545         item_size = ply_type_size[prop->count_internal];
00546         get_stored_item ((void *) item, prop->count_internal,
00547                          &int_val, &uint_val, &double_val);
00548         write_binary_item (fp, int_val, uint_val, double_val,
00549                            prop->count_external);
00550         list_count = uint_val;
00551         item_ptr = (char **) (elem_data + prop->offset);
00552         item = item_ptr[0];
00553         item_size = ply_type_size[prop->internal_type];
00554         for (k = 0; k < list_count; k++) {
00555           get_stored_item ((void *) item, prop->internal_type,
00556                            &int_val, &uint_val, &double_val);
00557           write_binary_item (fp, int_val, uint_val, double_val,
00558                              prop->external_type);
00559           item += item_size;
00560         }
00561       }
00562       else if (prop->is_list == PLY_STRING) {   /* string */
00563         int len;
00564         char **str;
00565         item = elem_data + prop->offset;
00566         str = (char **) item;
00567 
00568         /* write the length */
00569         len = strlen(*str) + 1;
00570         fwrite (&len, sizeof(int), 1, fp);
00571 
00572         /* write the string, including the null character */
00573         fwrite (*str, len, 1, fp);
00574       }
00575       else {                   /* scalar */
00576         item = elem_data + prop->offset;
00577         item_size = ply_type_size[prop->internal_type];
00578         get_stored_item ((void *) item, prop->internal_type,
00579                          &int_val, &uint_val, &double_val);
00580         write_binary_item (fp, int_val, uint_val, double_val,
00581                            prop->external_type);
00582       }
00583     }
00584 
00585   }
00586 }
00587 
00588 
00589 
00590 
00591 
00592 
00593 /*************/
00594 /*  Reading  */
00595 /*************/
00596 
00597 
00598 
00599 /******************************************************************************
00600 Given a file pointer, get ready to read PLY data from the file.
00601 
00602 Entry:
00603   fp - the given file pointer
00604 
00605 Exit:
00606   nelems     - number of elements in object
00607   elem_names - list of element names
00608   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
00609 ******************************************************************************/
00610 
00611 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
00612 {
00613   int i,j;
00614   PlyFile *plyfile;
00615   int nwords;
00616   char **words;
00617   int found_format = 0;
00618   char **elist;
00619   PlyElement *elem;
00620   char *orig_line;
00621 
00622   /* check for NULL file pointer */
00623   if (fp == NULL)
00624     return (NULL);
00625 
00626   /* create record for this object */
00627 
00628   plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
00629   plyfile->num_elem_types = 0;
00630   plyfile->comments = NULL;
00631   plyfile->num_comments = 0;
00632   plyfile->obj_info = NULL;
00633   plyfile->num_obj_info = 0;
00634   plyfile->fp = fp;
00635   plyfile->other_elems = NULL;
00636   plyfile->rule_list = NULL;
00637 
00638   /* read and parse the file's header */
00639 
00640   words = get_words (plyfile->fp, &nwords, &orig_line);
00641   
00642   if (words == NULL || !equal_strings (words[0], "ply"))
00643     return (NULL);
00644 
00645   while (words) {
00646 
00647     /* parse words */
00648 
00649     //printf(" words: %s | %s\n",words[0],words[1]);
00650     if (equal_strings (words[0], "format")) {
00651       if (nwords != 3)
00652         return (NULL);
00653       //printf(" words: endian %d\n",equal_strings (words[1], "binary_big_endian"));
00654       if (equal_strings (words[1], "ascii"))
00655         plyfile->file_type = PLY_ASCII;
00656       else if (equal_strings (words[1], "binary_big_endian"))
00657         plyfile->file_type = PLY_BINARY_BE;
00658       else if (equal_strings (words[1], "binary_little_endian"))
00659         plyfile->file_type = PLY_BINARY_LE;
00660       else
00661         return (NULL);
00662       plyfile->version = atof (words[2]);
00663       found_format = 1;
00664     }
00665     else if (equal_strings (words[0], "element"))
00666       add_element (plyfile, words, nwords);
00667     else if (equal_strings (words[0], "property"))
00668       add_property (plyfile, words, nwords);
00669     else if (equal_strings (words[0], "comment"))
00670       add_comment (plyfile, orig_line);
00671     else if (equal_strings (words[0], "obj_info"))
00672       add_obj_info (plyfile, orig_line);
00673     else if (equal_strings (words[0], "end_header"))
00674       break;
00675 
00676     /* free up words space */
00677     free (words);
00678 
00679     words = get_words (plyfile->fp, &nwords, &orig_line);
00680   }
00681 
00682   /* create tags for each property of each element, to be used */
00683   /* later to say whether or not to store each property for the user */
00684 
00685   for (i = 0; i < plyfile->num_elem_types; i++) {
00686     elem = plyfile->elems[i];
00687     elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
00688     for (j = 0; j < elem->nprops; j++)
00689       elem->store_prop[j] = DONT_STORE_PROP;
00690     elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
00691   }
00692 
00693   /* set return values about the elements */
00694 
00695   elist = (char **) myalloc (sizeof (char *) * plyfile->num_elem_types);
00696   for (i = 0; i < plyfile->num_elem_types; i++)
00697     elist[i] = strdup (plyfile->elems[i]->name);
00698 
00699   *elem_names = elist;
00700   *nelems = plyfile->num_elem_types;
00701 
00702   /* return a pointer to the file's information */
00703 
00704   return (plyfile);
00705 }
00706 
00707 
00708 /******************************************************************************
00709 Open a polygon file for reading.
00710 
00711 Entry:
00712   filename - name of file to read from
00713 
00714 Exit:
00715   nelems     - number of elements in object
00716   elem_names - list of element names
00717   file_type  - file type, either ascii or binary
00718   version    - version number of PLY file
00719   returns a file identifier, used to refer to this file, or NULL if error
00720 ******************************************************************************/
00721 
00722 PlyFile *ply_open_for_reading(
00723   char *filename,
00724   int *nelems,
00725   char ***elem_names,
00726   int *file_type,
00727   float *version
00728 )
00729 {
00730   FILE *fp;
00731   PlyFile *plyfile;
00732   char *name;
00733 
00734   /* tack on the extension .ply, if necessary */
00735 
00736   name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
00737   strcpy (name, filename);
00738   if (strlen (name) < 4 ||
00739       strcmp (name + strlen (name) - 4, ".ply") != 0)
00740       strcat (name, ".ply");
00741 
00742   /* open the file for reading */
00743 
00744   fp = fopen (name, "r");
00745   if (fp == NULL)
00746     return (NULL);
00747 
00748   /* create the PlyFile data structure */
00749 
00750   plyfile = ply_read (fp, nelems, elem_names);
00751 
00752   /* determine the file type and version */
00753 
00754   *file_type = plyfile->file_type;
00755   *version = plyfile->version;
00756 
00757   /* return a pointer to the file's information */
00758 
00759   return (plyfile);
00760 }
00761 
00762 
00763 /******************************************************************************
00764 Get information about a particular element.
00765 
00766 Entry:
00767   plyfile   - file identifier
00768   elem_name - name of element to get information about
00769 
00770 Exit:
00771   nelems   - number of elements of this type in the file
00772   nprops   - number of properties
00773   returns a list of properties, or NULL if the file doesn't contain that elem
00774 ******************************************************************************/
00775 
00776 PlyProperty **get_element_description_ply(
00777   PlyFile *plyfile,
00778   char *elem_name,
00779   int *nelems,
00780   int *nprops
00781 )
00782 {
00783   int i;
00784   PlyElement *elem;
00785   PlyProperty *prop;
00786   PlyProperty **prop_list;
00787 
00788   /* find information about the element */
00789   elem = find_element (plyfile, elem_name);
00790   if (elem == NULL)
00791     return (NULL);
00792 
00793   *nelems = elem->num;
00794   *nprops = elem->nprops;
00795 
00796   /* make a copy of the element's property list */
00797   prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
00798   for (i = 0; i < elem->nprops; i++) {
00799     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
00800     copy_property (prop, elem->props[i]);
00801     prop_list[i] = prop;
00802   }
00803 
00804   /* return this duplicate property list */
00805   return (prop_list);
00806 }
00807 
00808 
00809 /******************************************************************************
00810 Specify which properties of an element are to be returned.  This should be
00811 called before a call to the routine get_element_ply().
00812 
00813 Entry:
00814   plyfile   - file identifier
00815   elem_name - which element we're talking about
00816   nprops    - number of properties
00817   prop_list - list of properties
00818 ******************************************************************************/
00819 
00820 void get_element_setup_ply(
00821   PlyFile *plyfile,
00822   char *elem_name,
00823   int nprops,
00824   PlyProperty *prop_list
00825 )
00826 {
00827   int i;
00828   PlyElement *elem;
00829   PlyProperty *prop;
00830   int index;
00831 
00832   /* find information about the element */
00833   elem = find_element (plyfile, elem_name);
00834   plyfile->which_elem = elem;
00835 
00836   /* deposit the property information into the element's description */
00837   for (i = 0; i < nprops; i++) {
00838 
00839     /* look for actual property */
00840     prop = find_property (elem, prop_list[i].name, &index);
00841     if (prop == NULL) {
00842       fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
00843                prop_list[i].name, elem_name);
00844       continue;
00845     }
00846 
00847     /* store its description */
00848     prop->internal_type = prop_list[i].internal_type;
00849     prop->offset = prop_list[i].offset;
00850     prop->count_internal = prop_list[i].count_internal;
00851     prop->count_offset = prop_list[i].count_offset;
00852 
00853     /* specify that the user wants this property */
00854     elem->store_prop[index] = STORE_PROP;
00855   }
00856 }
00857 
00858 
00859 /******************************************************************************
00860 Specify a property of an element that is to be returned.  This should be
00861 called (usually multiple times) before a call to the routine ply_get_element().
00862 This routine should be used in preference to the less flexible old routine
00863 called ply_get_element_setup().
00864 
00865 Entry:
00866   plyfile   - file identifier
00867   elem_name - which element we're talking about
00868   prop      - property to add to those that will be returned
00869 ******************************************************************************/
00870 
00871 void ply_get_property(
00872   PlyFile *plyfile,
00873   char *elem_name,
00874   PlyProperty *prop
00875 )
00876 {
00877   PlyElement *elem;
00878   PlyProperty *prop_ptr;
00879   int index;
00880 
00881   /* find information about the element */
00882   elem = find_element (plyfile, elem_name);
00883   plyfile->which_elem = elem;
00884 
00885   /* deposit the property information into the element's description */
00886 
00887   prop_ptr = find_property (elem, prop->name, &index);
00888   if (prop_ptr == NULL) {
00889     fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
00890              prop->name, elem_name);
00891     return;
00892   }
00893   prop_ptr->internal_type  = prop->internal_type;
00894   prop_ptr->offset         = prop->offset;
00895   prop_ptr->count_internal = prop->count_internal;
00896   prop_ptr->count_offset   = prop->count_offset;
00897 
00898   /* specify that the user wants this property */
00899   elem->store_prop[index] = STORE_PROP;
00900 }
00901 
00902 
00903 /******************************************************************************
00904 Read one element from the file.  This routine assumes that we're reading
00905 the type of element specified in the last call to the routine
00906 ply_get_element_setup().
00907 
00908 Entry:
00909   plyfile  - file identifier
00910   elem_ptr - pointer to location where the element information should be put
00911 ******************************************************************************/
00912 
00913 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
00914 {
00915   if (plyfile->file_type == PLY_ASCII)
00916     ascii_get_element (plyfile, (char *) elem_ptr);
00917   else
00918     binary_get_element (plyfile, (char *) elem_ptr);
00919 }
00920 
00921 
00922 /******************************************************************************
00923 Extract the comments from the header information of a PLY file.
00924 
00925 Entry:
00926   plyfile - file identifier
00927 
00928 Exit:
00929   num_comments - number of comments returned
00930   returns a pointer to a list of comments
00931 ******************************************************************************/
00932 
00933 char **get_comments_ply(PlyFile *plyfile, int *num_comments)
00934 {
00935   *num_comments = plyfile->num_comments;
00936   return (plyfile->comments);
00937 }
00938 
00939 
00940 /******************************************************************************
00941 Extract the object information (arbitrary text) from the header information
00942 of a PLY file.
00943 
00944 Entry:
00945   plyfile - file identifier
00946 
00947 Exit:
00948   num_obj_info - number of lines of text information returned
00949   returns a pointer to a list of object info lines
00950 ******************************************************************************/
00951 
00952 char **get_obj_info_ply(PlyFile *plyfile, int *num_obj_info)
00953 {
00954   *num_obj_info = plyfile->num_obj_info;
00955   return (plyfile->obj_info);
00956 }
00957 
00958 
00959 /******************************************************************************
00960 Make ready for "other" properties of an element-- those properties that
00961 the user has not explicitly asked for, but that are to be stashed away
00962 in a special structure to be carried along with the element's other
00963 information.
00964 
00965 Entry:
00966   plyfile - file identifier
00967   elem    - element for which we want to save away other properties
00968 ******************************************************************************/
00969 
00970 void setup_other_props(PlyFile *plyfile, PlyElement *elem)
00971 {
00972   int i;
00973   PlyProperty *prop;
00974   int size = 0;
00975   int type_size;
00976 
00977   /* Examine each property in decreasing order of size. */
00978   /* We do this so that all data types will be aligned by */
00979   /* word, half-word, or whatever within the structure. */
00980 
00981   for (type_size = 8; type_size > 0; type_size /= 2) {
00982 
00983     /* add up the space taken by each property, and save this information */
00984     /* away in the property descriptor */
00985 
00986     for (i = 0; i < elem->nprops; i++) {
00987 
00988       /* don't bother with properties we've been asked to store explicitly */
00989       if (elem->store_prop[i])
00990         continue;
00991 
00992       prop = elem->props[i];
00993 
00994       /* internal types will be same as external */
00995       prop->internal_type = prop->external_type;
00996       prop->count_internal = prop->count_external;
00997 
00998       /* list case */
00999       if (prop->is_list == PLY_LIST) {
01000 
01001         /* pointer to list */
01002         if (type_size == sizeof (void *)) {
01003           prop->offset = size;
01004           size += sizeof (void *);    /* always use size of a pointer here */
01005         }
01006 
01007         /* count of number of list elements */
01008         if (type_size == ply_type_size[prop->count_external]) {
01009           prop->count_offset = size;
01010           size += ply_type_size[prop->count_external];
01011         }
01012       }
01013       /* string */
01014       else if (prop->is_list == PLY_STRING) {
01015         /* pointer to string */
01016         if (type_size == sizeof (char *)) {
01017           prop->offset = size;
01018           size += sizeof (char *);
01019         }
01020       }
01021       /* scalar */
01022       else if (type_size == ply_type_size[prop->external_type]) {
01023         prop->offset = size;
01024         size += ply_type_size[prop->external_type];
01025       }
01026     }
01027 
01028   }
01029 
01030   /* save the size for the other_props structure */
01031   elem->other_size = size;
01032 }
01033 
01034 
01035 /******************************************************************************
01036 Specify that we want the "other" properties of an element to be tucked
01037 away within the user's structure.
01038 
01039 Entry:
01040   plyfile - file identifier
01041   elem    - the element that we want to store other_props in
01042   offset  - offset to where other_props will be stored inside user's structure
01043 
01044 Exit:
01045   returns pointer to structure containing description of other_props
01046 ******************************************************************************/
01047 
01048 static PlyOtherProp *get_other_properties(
01049   PlyFile *plyfile,
01050   PlyElement *elem,
01051   int offset
01052 )
01053 {
01054   int i;
01055   PlyOtherProp *other;
01056   PlyProperty *prop;
01057   int nprops;
01058 
01059   /* remember that this is the "current" element */
01060   plyfile->which_elem = elem;
01061 
01062   /* save the offset to where to store the other_props */
01063   elem->other_offset = offset;
01064 
01065   /* place the appropriate pointers, etc. in the element's property list */
01066   setup_other_props (plyfile, elem);
01067 
01068   /* create structure for describing other_props */
01069   other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
01070   other->name = strdup (elem->name);
01071 #if 0
01072   if (elem->other_offset == NO_OTHER_PROPS) {
01073     other->size = 0;
01074     other->props = NULL;
01075     other->nprops = 0;
01076     return (other);
01077   }
01078 #endif
01079   other->size = elem->other_size;
01080   other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
01081   
01082   /* save descriptions of each "other" property */
01083   nprops = 0;
01084   for (i = 0; i < elem->nprops; i++) {
01085     if (elem->store_prop[i])
01086       continue;
01087     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
01088     copy_property (prop, elem->props[i]);
01089     other->props[nprops] = prop;
01090     nprops++;
01091   }
01092   other->nprops = nprops;
01093 
01094   /* set other_offset pointer appropriately if there are NO other properties */
01095   if (other->nprops == 0) {
01096     elem->other_offset = NO_OTHER_PROPS;
01097   }
01098  
01099   /* return structure */
01100   return (other);
01101 }
01102 
01103 
01104 /******************************************************************************
01105 Specify that we want the "other" properties of an element to be tucked
01106 away within the user's structure.  The user needn't be concerned for how
01107 these properties are stored.
01108 
01109 Entry:
01110   plyfile   - file identifier
01111   elem_name - name of element that we want to store other_props in
01112   offset    - offset to where other_props will be stored inside user's structure
01113 
01114 Exit:
01115   returns pointer to structure containing description of other_props
01116 ******************************************************************************/
01117 
01118 PlyOtherProp *ply_get_other_properties(
01119   PlyFile *plyfile,
01120   char *elem_name,
01121   int offset
01122 )
01123 {
01124   PlyElement *elem;
01125   PlyOtherProp *other;
01126 
01127   /* find information about the element */
01128   elem = find_element (plyfile, elem_name);
01129   if (elem == NULL) {
01130     fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
01131              elem_name);
01132     return (NULL);
01133   }
01134 
01135   other = get_other_properties (plyfile, elem, offset);
01136   return (other);
01137 }
01138 
01139 
01140 
01141 
01142 /*************************/
01143 /*  Other Element Stuff  */
01144 /*************************/
01145 
01146 
01147 
01148 
01149 
01150 /******************************************************************************
01151 Grab all the data for the current element that a user does not want to
01152 explicitly read in.  Stores this in the PLY object's data structure.
01153 
01154 Entry:
01155   plyfile - pointer to file
01156 
01157 Exit:
01158   returns pointer to ALL the "other" element data for this PLY file
01159 ******************************************************************************/
01160 
01161 PlyOtherElems *get_other_element_ply (PlyFile *plyfile)
01162 {
01163   int i;
01164   PlyElement *elem;
01165   char *elem_name;
01166   int elem_count;
01167   PlyOtherElems *other_elems;
01168   OtherElem *other;
01169 
01170   elem = plyfile->which_elem;
01171   elem_name = elem->name;
01172   elem_count = elem->num;
01173 
01174   /* create room for the new "other" element, initializing the */
01175   /* other data structure if necessary */
01176 
01177   if (plyfile->other_elems == NULL) {
01178     plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
01179     other_elems = plyfile->other_elems;
01180     other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
01181     other = &(other_elems->other_list[0]);
01182     other_elems->num_elems = 1;
01183   }
01184   else {
01185     other_elems = plyfile->other_elems;
01186     other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
01187                               sizeof (OtherElem) * other_elems->num_elems + 1);
01188     other = &(other_elems->other_list[other_elems->num_elems]);
01189     other_elems->num_elems++;
01190   }
01191 
01192   /* count of element instances in file */
01193   other->elem_count = elem_count;
01194 
01195   /* save name of element */
01196   other->elem_name = strdup (elem_name);
01197 
01198   /* create a list to hold all the current elements */
01199   other->other_data = (OtherData **)
01200                   malloc (sizeof (OtherData *) * other->elem_count);
01201 
01202   /* set up for getting elements */
01203   other->other_props = ply_get_other_properties (plyfile, elem_name,
01204                          offsetof(OtherData,other_props));
01205 
01206   /* grab all these elements */
01207   for (i = 0; i < other->elem_count; i++) {
01208     /* grab and element from the file */
01209     other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
01210     ply_get_element (plyfile, (void *) other->other_data[i]);
01211   }
01212 
01213   /* return pointer to the other elements data */
01214   return (other_elems);
01215 }
01216 
01217 
01218 /******************************************************************************
01219 Write out the "other" elements specified for this PLY file.
01220 
01221 Entry:
01222   plyfile - pointer to PLY file to write out other elements for
01223 ******************************************************************************/
01224 
01225 void put_other_elements_ply (PlyFile *plyfile)
01226 {
01227   int i,j;
01228   OtherElem *other;
01229 
01230   /* make sure we have other elements to write */
01231   if (plyfile->other_elems == NULL)
01232     return;
01233 
01234   /* write out the data for each "other" element */
01235 
01236   for (i = 0; i < plyfile->other_elems->num_elems; i++) {
01237 
01238     other = &(plyfile->other_elems->other_list[i]);
01239     put_element_setup_ply (plyfile, other->elem_name);
01240 
01241     /* write out each instance of the current element */
01242     for (j = 0; j < other->elem_count; j++)
01243       put_element_ply (plyfile, (void *) other->other_data[j]);
01244   }
01245 }
01246 
01247 
01248 /******************************************************************************
01249 Free up storage used by an "other" elements data structure.
01250 
01251 Entry:
01252   other_elems - data structure to free up
01253 ******************************************************************************/
01254 
01255 void free_other_elements_ply (PlyOtherElems *other_elems)
01256 {
01257 
01258 }
01259 
01260 
01261 
01262 /*******************/
01263 /*  Miscellaneous  */
01264 /*******************/
01265 
01266 
01267 
01268 /******************************************************************************
01269 Close a PLY file.
01270 
01271 Entry:
01272   plyfile - identifier of file to close
01273 ******************************************************************************/
01274 
01275 void ply_close(PlyFile *plyfile)
01276 {
01277   fclose (plyfile->fp);
01278 
01279   /* free up memory associated with the PLY file */
01280   free (plyfile);
01281 }
01282 
01283 
01284 /******************************************************************************
01285 Get version number and file type of a PlyFile.
01286 
01287 Entry:
01288   ply - pointer to PLY file
01289 
01290 Exit:
01291   version - version of the file
01292   file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
01293 ******************************************************************************/
01294 
01295 void get_info_ply(PlyFile *ply, float *version, int *file_type)
01296 {
01297   if (ply == NULL)
01298     return;
01299 
01300   *version = ply->version;
01301   *file_type = ply->file_type;
01302 }
01303 
01304 
01305 /******************************************************************************
01306 Compare two strings.  Returns 1 if they are the same, 0 if not.
01307 ******************************************************************************/
01308 
01309 int equal_strings(char *s1, char *s2)
01310 {
01311   int i;
01312 
01313   while (*s1 && *s2)
01314     if (*s1++ != *s2++)
01315       return (0);
01316 
01317   if (*s1 != *s2)
01318     return (0);
01319   else
01320     return (1);
01321 }
01322 
01323 
01324 /******************************************************************************
01325 Re-create the command line that was used to invoke this program.
01326 
01327 Entry:
01328   argc - number of words in argv
01329   argv - array of words in command line
01330 ******************************************************************************/
01331 
01332 char *recreate_command_line (int argc, char *argv[])
01333 {
01334   int i;
01335   char *line;
01336   int len = 0;
01337 
01338   /* count total number of characters needed, including separating spaces */
01339   for (i = 0; i < argc; i++)
01340     len += strlen(argv[i]) + 1;
01341 
01342   /* create empty line */
01343   line = (char *) malloc (sizeof(char) * len);
01344   line[0] = '\0';
01345 
01346   /* repeatedly append argv */
01347   for (i = 0; i < argc; i++) {
01348     strcat (line, argv[i]);
01349     if (i != argc - 1)
01350       strcat (line, " ");
01351   }
01352 
01353   return (line);
01354 }
01355 
01356 
01357 /******************************************************************************
01358 Find an element from the element list of a given PLY object.
01359 
01360 Entry:
01361   plyfile - file id for PLY file
01362   element - name of element we're looking for
01363 
01364 Exit:
01365   returns the element, or NULL if not found
01366 ******************************************************************************/
01367 
01368 PlyElement *find_element(PlyFile *plyfile, char *element)
01369 {
01370   int i;
01371 
01372   for (i = 0; i < plyfile->num_elem_types; i++)
01373     if (equal_strings (element, plyfile->elems[i]->name))
01374       return (plyfile->elems[i]);
01375 
01376   return (NULL);
01377 }
01378 
01379 
01380 /******************************************************************************
01381 Find a property in the list of properties of a given element.
01382 
01383 Entry:
01384   elem      - pointer to element in which we want to find the property
01385   prop_name - name of property to find
01386 
01387 Exit:
01388   index - index to position in list
01389   returns a pointer to the property, or NULL if not found
01390 ******************************************************************************/
01391 
01392 PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index)
01393 {
01394   int i;
01395 
01396   for (i = 0; i < elem->nprops; i++)
01397     if (equal_strings (prop_name, elem->props[i]->name)) {
01398       *index = i;
01399       return (elem->props[i]);
01400     }
01401 
01402   *index = -1;
01403   return (NULL);
01404 }
01405 
01406 
01407 /******************************************************************************
01408 Read an element from an ascii file.
01409 
01410 Entry:
01411   plyfile  - file identifier
01412   elem_ptr - pointer to element
01413 ******************************************************************************/
01414 
01415 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
01416 {
01417   int i,j,k;
01418   PlyElement *elem;
01419   PlyProperty *prop;
01420   char **words;
01421   int nwords;
01422   int which_word;
01423   FILE *fp = plyfile->fp;
01424   char *elem_data,*item;
01425   char *item_ptr;
01426   int item_size;
01427   int int_val;
01428   unsigned int uint_val;
01429   double double_val;
01430   int list_count;
01431   int store_it;
01432   char **store_array;
01433   char *orig_line;
01434   char *other_data;
01435   int other_flag;
01436 
01437   /* the kind of element we're reading currently */
01438   elem = plyfile->which_elem;
01439 
01440   /* do we need to setup for other_props? */
01441 
01442   if (elem->other_offset != NO_OTHER_PROPS) {
01443     char **ptr;
01444     other_flag = 1;
01445     /* make room for other_props */
01446     other_data = (char *) myalloc (elem->other_size);
01447     /* store pointer in user's structure to the other_props */
01448     ptr = (char **) (elem_ptr + elem->other_offset);
01449     *ptr = other_data;
01450   }
01451   else
01452     other_flag = 0;
01453 
01454   /* read in the element */
01455 
01456   words = get_words (plyfile->fp, &nwords, &orig_line);
01457   if (words == NULL) {
01458     fprintf (stderr, "ply_get_element: unexpected end of file\n");
01459     exit (-1);
01460   }
01461 
01462   which_word = 0;
01463 
01464   for (j = 0; j < elem->nprops; j++) {
01465 
01466     prop = elem->props[j];
01467     store_it = (elem->store_prop[j] | other_flag);
01468 
01469     /* store either in the user's structure or in other_props */
01470     if (elem->store_prop[j])
01471       elem_data = elem_ptr;
01472     else
01473       elem_data = other_data;
01474 
01475     if (prop->is_list == PLY_LIST) {       /* a list */
01476 
01477       /* get and store the number of items in the list */
01478       get_ascii_item (words[which_word++], prop->count_external,
01479                       &int_val, &uint_val, &double_val);
01480       if (store_it) {
01481         item = elem_data + prop->count_offset;
01482         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01483       }
01484 
01485       /* allocate space for an array of items and store a ptr to the array */
01486       list_count = int_val;
01487       item_size = ply_type_size[prop->internal_type];
01488       store_array = (char **) (elem_data + prop->offset);
01489 
01490       if (list_count == 0) {
01491         if (store_it)
01492           *store_array = NULL;
01493       }
01494       else {
01495         if (store_it) {
01496           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01497           item = item_ptr;
01498           *store_array = item_ptr;
01499         }
01500 
01501         /* read items and store them into the array */
01502         for (k = 0; k < list_count; k++) {
01503           get_ascii_item (words[which_word++], prop->external_type,
01504                           &int_val, &uint_val, &double_val);
01505           if (store_it) {
01506             store_item (item, prop->internal_type,
01507                         int_val, uint_val, double_val);
01508             item += item_size;
01509           }
01510         }
01511       }
01512 
01513     }
01514     else if (prop->is_list == PLY_STRING) {   /* a string */
01515       if (store_it) {
01516         char *str;
01517         char **str_ptr;
01518         str = strdup (words[which_word++]);
01519         item = elem_data + prop->offset;
01520         str_ptr = (char **) item;
01521         *str_ptr = str;
01522       }
01523       else {
01524         which_word++;
01525       }
01526     }
01527     else {                     /* a scalar */
01528       get_ascii_item (words[which_word++], prop->external_type,
01529                       &int_val, &uint_val, &double_val);
01530       if (store_it) {
01531         item = elem_data + prop->offset;
01532         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01533       }
01534     }
01535 
01536   }
01537 
01538   free (words);
01539 }
01540 
01541 
01542 /******************************************************************************
01543 Read an element from a binary file.
01544 
01545 Entry:
01546   plyfile  - file identifier
01547   elem_ptr - pointer to an element
01548 ******************************************************************************/
01549 
01550 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
01551 {
01552   int i,j,k;
01553   PlyElement *elem;
01554   PlyProperty *prop;
01555   FILE *fp = plyfile->fp;
01556   char *elem_data;
01557   char *item;
01558   char *item_ptr;
01559   int item_size;
01560   int int_val;
01561   unsigned int uint_val;
01562   double double_val;
01563   int list_count;
01564   int store_it;
01565   char **store_array;
01566   char *other_data;
01567   int other_flag;
01568 
01569   /* the kind of element we're reading currently */
01570   elem = plyfile->which_elem;
01571 
01572   /* do we need to setup for other_props? */
01573 
01574   if (elem->other_offset != NO_OTHER_PROPS) {
01575     char **ptr;
01576     other_flag = 1;
01577     /* make room for other_props */
01578     other_data = (char *) myalloc (elem->other_size);
01579     /* store pointer in user's structure to the other_props */
01580     ptr = (char **) (elem_ptr + elem->other_offset);
01581     *ptr = other_data;
01582   }
01583   else
01584     other_flag = 0;
01585 
01586   /* read in a number of elements */
01587 
01588   for (j = 0; j < elem->nprops; j++) {
01589 
01590     prop = elem->props[j];
01591 //    printf(" binary_get_element: prop %d %d %d %d\n", prop->is_list, prop->count_external, prop->count_offset, prop->count_internal);
01592     store_it = (elem->store_prop[j] | other_flag);
01593 
01594     /* store either in the user's structure or in other_props */
01595     if (elem->store_prop[j])
01596       elem_data = elem_ptr;
01597     else
01598       elem_data = other_data;
01599 
01600     if (prop->is_list == PLY_LIST) {          /* list */
01601 
01602       /* get and store the number of items in the list */
01603       get_binary_item (fp, prop->count_external,
01604                       &int_val, &uint_val, &double_val);
01605       if (store_it) {
01606         item = elem_data + prop->count_offset;
01607         store_item(item, prop->count_internal, int_val, uint_val, double_val);
01608       }
01609 
01610       /* allocate space for an array of items and store a ptr to the array */
01611       list_count = int_val;
01612       item_size = ply_type_size[prop->internal_type];
01613       store_array = (char **) (elem_data + prop->offset);
01614       if (list_count == 0) {
01615         if (store_it)
01616           *store_array = NULL;
01617       }
01618       else {
01619         if (store_it) {
01620           item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
01621           item = item_ptr;
01622           *store_array = item_ptr;
01623         }
01624 
01625         /* read items and store them into the array */
01626         for (k = 0; k < list_count; k++) {
01627           get_binary_item (fp, prop->external_type,
01628                           &int_val, &uint_val, &double_val);
01629           if (store_it) {
01630             store_item (item, prop->internal_type,
01631                         int_val, uint_val, double_val);
01632             item += item_size;
01633           }
01634         }
01635       }
01636 
01637     }
01638     else if (prop->is_list == PLY_STRING) {     /* string */
01639       int len;
01640       char *str;
01641       fread (&len, sizeof(int), 1, fp);
01642       str = (char *) myalloc (len);
01643       fread (str, len, 1, fp);
01644       if (store_it) {
01645         char **str_ptr;
01646         item = elem_data + prop->offset;
01647         str_ptr = (char **) item;
01648         *str_ptr = str;
01649       }
01650     }
01651     else {                                      /* scalar */
01652       get_binary_item (fp, prop->external_type,
01653                       &int_val, &uint_val, &double_val);
01654       if (store_it) {
01655         item = elem_data + prop->offset;
01656         store_item (item, prop->internal_type, int_val, uint_val, double_val);
01657       }
01658     }
01659 
01660   }
01661 }
01662 
01663 
01664 /******************************************************************************
01665 Write to a file the word that represents a PLY data type.
01666 
01667 Entry:
01668   fp   - file pointer
01669   code - code for type
01670 ******************************************************************************/
01671 
01672 void write_scalar_type (FILE *fp, int code)
01673 {
01674   /* make sure this is a valid code */
01675 
01676   if (code <= StartType || code >= EndType) {
01677     fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
01678     exit (-1);
01679   }
01680 
01681   /* write the code to a file */
01682 
01683   fprintf (fp, "%s", type_names[code]);
01684 }
01685 
01686 
01687 /******************************************************************************
01688 Get a text line from a file and break it up into words.
01689 
01690 IMPORTANT: The calling routine should call "free" on the returned pointer once
01691 finished with it.
01692 
01693 Entry:
01694   fp - file to read from
01695 
01696 Exit:
01697   nwords    - number of words returned
01698   orig_line - the original line of characters
01699   returns a list of words from the line, or NULL if end-of-file
01700 ******************************************************************************/
01701 
01702 char **get_words(FILE *fp, int *nwords, char **orig_line)
01703 {
01704 #define BIG_STRING 4096
01705   int i,j;
01706   static char str[BIG_STRING];
01707   static char str_copy[BIG_STRING];
01708   char **words;
01709   int max_words = 10;
01710   int num_words = 0;
01711   char *ptr,*ptr2;
01712   char *result;
01713 
01714   words = (char **) myalloc (sizeof (char *) * max_words);
01715 
01716   /* read in a line */
01717   result = fgets (str, BIG_STRING, fp);
01718 //  printf("read line: %s\n",result);
01719   if (result == NULL) {
01720     *nwords = 0;
01721     *orig_line = NULL;
01722     return (NULL);
01723   }
01724 
01725   /* convert line-feed and tabs into spaces */
01726   /* (this guarentees that there will be a space before the */
01727   /*  null character at the end of the string) */
01728 
01729   str[BIG_STRING-2] = ' ';
01730   str[BIG_STRING-1] = '\0';
01731 
01732   for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
01733     *ptr2 = *ptr;
01734     if (*ptr == '\t') {
01735       *ptr = ' ';
01736       *ptr2 = ' ';
01737     }
01738     else if (*ptr == '\r') {
01739       *ptr = ' ';
01740       *ptr2 = ' ';
01741     }
01742     else if (*ptr == '\n') {
01743       *ptr = ' ';
01744       *ptr2 = '\0';
01745       break;
01746     }
01747   }
01748 
01749   /* find the words in the line */
01750 
01751   ptr = str;
01752   while (*ptr != '\0') {
01753 
01754     /* jump over leading spaces */
01755     while (*ptr == ' ')
01756       ptr++;
01757 
01758     /* break if we reach the end */
01759     if (*ptr == '\0')
01760       break;
01761 
01762     /* allocate more room for words if necessary */
01763     if (num_words >= max_words) {
01764       max_words += 10;
01765       words = (char **) realloc (words, sizeof (char *) * max_words);
01766     }
01767 
01768     if (*ptr == '\"') {  /* a quote indidicates that we have a string */
01769 
01770       /* skip over leading quote */
01771       ptr++;
01772 
01773       /* save pointer to beginning of word */
01774       words[num_words++] = ptr;
01775 
01776       /* find trailing quote or end of line */
01777       while (*ptr != '\"' && *ptr != '\0')
01778         ptr++;
01779 
01780       /* replace quote with a null character to mark the end of the word */
01781       /* if we are not already at the end of the line */
01782       if (*ptr != '\0')
01783         *ptr++ = '\0';
01784     }
01785     else {               /* non-string */
01786 
01787       /* save pointer to beginning of word */
01788       words[num_words++] = ptr;
01789 
01790       /* jump over non-spaces */
01791       while (*ptr != ' ')
01792         ptr++;
01793 
01794       /* place a null character here to mark the end of the word */
01795       *ptr++ = '\0';
01796     }
01797   }
01798 
01799   /* return the list of words */
01800   *nwords = num_words;
01801   *orig_line = str_copy;
01802   return (words);
01803 }
01804 
01805 
01806 /******************************************************************************
01807 Return the value of an item, given a pointer to it and its type.
01808 
01809 Entry:
01810   item - pointer to item
01811   type - data type that "item" points to
01812 
01813 Exit:
01814   returns a double-precision float that contains the value of the item
01815 ******************************************************************************/
01816 
01817 double get_item_value(char *item, int type)
01818 {
01819   unsigned char *puchar;
01820   char *pchar;
01821   short int *pshort;
01822   unsigned short int *pushort;
01823   int *pint;
01824   unsigned int *puint;
01825   float *pfloat;
01826   double *pdouble;
01827   int int_value;
01828   unsigned int uint_value;
01829   double double_value;
01830 
01831   switch (type) {
01832     case Int8:
01833       pchar = (char *) item;
01834       int_value = *pchar;
01835       return ((double) int_value);
01836     case Uint8:
01837       puchar = (unsigned char *) item;
01838       int_value = *puchar;
01839       return ((double) int_value);
01840     case Int16:
01841       pshort = (short int *) item;
01842       int_value = *pshort;
01843       return ((double) int_value);
01844     case Uint16:
01845       pushort = (unsigned short int *) item;
01846       int_value = *pushort;
01847       return ((double) int_value);
01848     case Int32:
01849       pint = (int *) item;
01850       int_value = *pint;
01851       return ((double) int_value);
01852     case Uint32:
01853       puint = (unsigned int *) item;
01854       uint_value = *puint;
01855       return ((double) uint_value);
01856     case Float32:
01857       pfloat = (float *) item;
01858       double_value = *pfloat;
01859       return (double_value);
01860     case Float64:
01861       pdouble = (double *) item;
01862       double_value = *pdouble;
01863       return (double_value);
01864     default:
01865       fprintf (stderr, "get_item_value: bad type = %d\n", type);
01866       exit (-1);
01867   }
01868 
01869   return (0.0);  /* never actually gets here */
01870 }
01871 
01872 
01873 /******************************************************************************
01874 Write out an item to a file as raw binary bytes.
01875 
01876 Entry:
01877   fp         - file to write to
01878   int_val    - integer version of item
01879   uint_val   - unsigned integer version of item
01880   double_val - double-precision float version of item
01881   type       - data type to write out
01882 ******************************************************************************/
01883 
01884 void write_binary_item(
01885   FILE *fp,
01886   int int_val,
01887   unsigned int uint_val,
01888   double double_val,
01889   int type
01890 )
01891 {
01892   unsigned char uchar_val;
01893   char char_val;
01894   unsigned short ushort_val;
01895   short short_val;
01896   float float_val;
01897 
01898   switch (type) {
01899     case Int8:
01900       char_val = int_val;
01901       fwrite (&char_val, 1, 1, fp);
01902       break;
01903     case Int16:
01904       short_val = int_val;
01905       fwrite (&short_val, 2, 1, fp);
01906       break;
01907     case Int32:
01908       fwrite (&int_val, 4, 1, fp);
01909       break;
01910     case Uint8:
01911       uchar_val = uint_val;
01912       fwrite (&uchar_val, 1, 1, fp);
01913       break;
01914     case Uint16:
01915       ushort_val = uint_val;
01916       fwrite (&ushort_val, 2, 1, fp);
01917       break;
01918     case Uint32:
01919       fwrite (&uint_val, 4, 1, fp);
01920       break;
01921     case Float32:
01922       float_val = double_val;
01923       fwrite (&float_val, 4, 1, fp);
01924       break;
01925     case Float64:
01926       fwrite (&double_val, 8, 1, fp);
01927       break;
01928     default:
01929       fprintf (stderr, "write_binary_item: bad type = %d\n", type);
01930       exit (-1);
01931   }
01932 }
01933 
01934 
01935 /******************************************************************************
01936 Write out an item to a file as ascii characters.
01937 
01938 Entry:
01939   fp         - file to write to
01940   int_val    - integer version of item
01941   uint_val   - unsigned integer version of item
01942   double_val - double-precision float version of item
01943   type       - data type to write out
01944 ******************************************************************************/
01945 
01946 void write_ascii_item(
01947   FILE *fp,
01948   int int_val,
01949   unsigned int uint_val,
01950   double double_val,
01951   int type
01952 )
01953 {
01954   switch (type) {
01955     case Int8:
01956     case Int16:
01957     case Int32:
01958       fprintf (fp, "%d ", int_val);
01959       break;
01960     case Uint8:
01961     case Uint16:
01962     case Uint32:
01963       fprintf (fp, "%u ", uint_val);
01964       break;
01965     case Float32:
01966     case Float64:
01967       fprintf (fp, "%g ", double_val);
01968       break;
01969     default:
01970       fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
01971       exit (-1);
01972   }
01973 }
01974 
01975 
01976 /******************************************************************************
01977 Get the value of an item that is in memory, and place the result
01978 into an integer, an unsigned integer and a double.
01979 
01980 Entry:
01981   ptr  - pointer to the item
01982   type - data type supposedly in the item
01983 
01984 Exit:
01985   int_val    - integer value
01986   uint_val   - unsigned integer value
01987   double_val - double-precision floating point value
01988 ******************************************************************************/
01989 
01990 void get_stored_item(
01991   void *ptr,
01992   int type,
01993   int *int_val,
01994   unsigned int *uint_val,
01995   double *double_val
01996 )
01997 {
01998   switch (type) {
01999     case Int8:
02000       *int_val = *((char *) ptr);
02001       *uint_val = *int_val;
02002       *double_val = *int_val;
02003       break;
02004     case Uint8:
02005       *uint_val = *((unsigned char *) ptr);
02006       *int_val = *uint_val;
02007       *double_val = *uint_val;
02008       break;
02009     case Int16:
02010       *int_val = *((short int *) ptr);
02011       *uint_val = *int_val;
02012       *double_val = *int_val;
02013       break;
02014     case Uint16:
02015       *uint_val = *((unsigned short int *) ptr);
02016       *int_val = *uint_val;
02017       *double_val = *uint_val;
02018       break;
02019     case Int32:
02020       *int_val = *((int *) ptr);
02021       *uint_val = *int_val;
02022       *double_val = *int_val;
02023       break;
02024     case Uint32:
02025       *uint_val = *((unsigned int *) ptr);
02026       *int_val = *uint_val;
02027       *double_val = *uint_val;
02028       break;
02029     case Float32:
02030       *double_val = *((float *) ptr);
02031       *int_val = *double_val;
02032       *uint_val = *double_val;
02033       break;
02034     case Float64:
02035       *double_val = *((double *) ptr);
02036       *int_val = *double_val;
02037       *uint_val = *double_val;
02038       break;
02039     default:
02040       fprintf (stderr, "get_stored_item: bad type = %d\n", type);
02041       exit (-1);
02042   }
02043 }
02044 
02045 
02046 /******************************************************************************
02047 Get the value of an item from a binary file, and place the result
02048 into an integer, an unsigned integer and a double.
02049 
02050 Entry:
02051   fp   - file to get item from
02052   type - data type supposedly in the word
02053 
02054 Exit:
02055   int_val    - integer value
02056   uint_val   - unsigned integer value
02057   double_val - double-precision floating point value
02058 ******************************************************************************/
02059 
02060 void get_binary_item(
02061   FILE *fp,
02062   int type,
02063   int *int_val,
02064   unsigned int *uint_val,
02065   double *double_val
02066 )
02067 {
02068   char c[8];
02069   void *ptr;
02070 
02071   ptr = (void *) c;
02072 
02073   switch (type) {
02074     case Int8:
02075       fread (ptr, 1, 1, fp);
02076       *int_val = *((char *) ptr);
02077       *uint_val = *int_val;
02078       *double_val = *int_val;
02079       break;
02080     case Uint8:
02081       fread (ptr, 1, 1, fp);
02082       *uint_val = *((unsigned char *) ptr);
02083       *int_val = *uint_val;
02084       *double_val = *uint_val;
02085       break;
02086     case Int16:
02087       fread (ptr, 2, 1, fp);
02088       *int_val = *((short int *) ptr);
02089       *uint_val = *int_val;
02090       *double_val = *int_val;
02091       break;
02092     case Uint16:
02093       fread (ptr, 2, 1, fp);
02094       *uint_val = *((unsigned short int *) ptr);
02095       *int_val = *uint_val;
02096       *double_val = *uint_val;
02097       break;
02098     case Int32:
02099       fread (ptr, 4, 1, fp);
02100       *int_val = *((int *) ptr);
02101       *uint_val = *int_val;
02102       *double_val = *int_val;
02103       break;
02104     case Uint32:
02105       fread (ptr, 4, 1, fp);
02106       *uint_val = *((unsigned int *) ptr);
02107       *int_val = *uint_val;
02108       *double_val = *uint_val;
02109       break;
02110     case Float32:
02111       fread (ptr, 4, 1, fp);
02112       *double_val = *((float *) ptr);
02113       *int_val = *double_val;
02114       *uint_val = *double_val;
02115       break;
02116     case Float64:
02117       fread (ptr, 8, 1, fp);
02118       *double_val = *((double *) ptr);
02119       *int_val = *double_val;
02120       *uint_val = *double_val;
02121       break;
02122     default:
02123       fprintf (stderr, "get_binary_item: bad type = %d\n", type);
02124       exit (-1);
02125   }
02126 }
02127 
02128 
02129 /******************************************************************************
02130 Extract the value of an item from an ascii word, and place the result
02131 into an integer, an unsigned integer and a double.
02132 
02133 Entry:
02134   word - word to extract value from
02135   type - data type supposedly in the word
02136 
02137 Exit:
02138   int_val    - integer value
02139   uint_val   - unsigned integer value
02140   double_val - double-precision floating point value
02141 ******************************************************************************/
02142 
02143 void get_ascii_item(
02144   char *word,
02145   int type,
02146   int *int_val,
02147   unsigned int *uint_val,
02148   double *double_val
02149 )
02150 {
02151   switch (type) {
02152     case Int8:
02153     case Uint8:
02154     case Int16:
02155     case Uint16:
02156     case Int32:
02157       *int_val = atoi (word);
02158       *uint_val = *int_val;
02159       *double_val = *int_val;
02160       break;
02161 
02162     case Uint32:
02163       *uint_val = strtoul (word, (char **) NULL, 10);
02164       *int_val = *uint_val;
02165       *double_val = *uint_val;
02166       break;
02167 
02168     case Float32:
02169     case Float64:
02170       *double_val = atof (word);
02171       *int_val = (int) *double_val;
02172       *uint_val = (unsigned int) *double_val;
02173       break;
02174 
02175     default:
02176       fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
02177       exit (-1);
02178   }
02179 }
02180 
02181 
02182 /******************************************************************************
02183 Store a value into a place being pointed to, guided by a data type.
02184 
02185 Entry:
02186   item       - place to store value
02187   type       - data type
02188   int_val    - integer version of value
02189   uint_val   - unsigned integer version of value
02190   double_val - double version of value
02191 
02192 Exit:
02193   item - pointer to stored value
02194 ******************************************************************************/
02195 
02196 void store_item (
02197   char *item,
02198   int type,
02199   int int_val,
02200   unsigned int uint_val,
02201   double double_val
02202 )
02203 {
02204   unsigned char *puchar;
02205   short int *pshort;
02206   unsigned short int *pushort;
02207   int *pint;
02208   unsigned int *puint;
02209   float *pfloat;
02210   double *pdouble;
02211 
02212   switch (type) {
02213     case Int8:
02214       *item = int_val;
02215       break;
02216     case Uint8:
02217       puchar = (unsigned char *) item;
02218       *puchar = uint_val;
02219       break;
02220     case Int16:
02221       pshort = (short *) item;
02222       *pshort = int_val;
02223       break;
02224     case Uint16:
02225       pushort = (unsigned short *) item;
02226       *pushort = uint_val;
02227       break;
02228     case Int32:
02229       pint = (int *) item;
02230       *pint = int_val;
02231       break;
02232     case Uint32:
02233       puint = (unsigned int *) item;
02234       *puint = uint_val;
02235       break;
02236     case Float32:
02237       pfloat = (float *) item;
02238       *pfloat = double_val;
02239       break;
02240     case Float64:
02241       pdouble = (double *) item;
02242       *pdouble = double_val;
02243       break;
02244     default:
02245       fprintf (stderr, "store_item: bad type = %d\n", type);
02246       exit (-1);
02247   }
02248 }
02249 
02250 
02251 /******************************************************************************
02252 Add an element to a PLY file descriptor.
02253 
02254 Entry:
02255   plyfile - PLY file descriptor
02256   words   - list of words describing the element
02257   nwords  - number of words in the list
02258 ******************************************************************************/
02259 
02260 void add_element (PlyFile *plyfile, char **words, int nwords)
02261 {
02262   PlyElement *elem;
02263 
02264   /* create the new element */
02265   elem = (PlyElement *) myalloc (sizeof (PlyElement));
02266   elem->name = strdup (words[1]);
02267   elem->num = atoi (words[2]);
02268   elem->nprops = 0;
02269 
02270   /* make room for new element in the object's list of elements */
02271   if (plyfile->num_elem_types == 0)
02272     plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
02273   else
02274     plyfile->elems = (PlyElement **) realloc (plyfile->elems,
02275                      sizeof (PlyElement *) * (plyfile->num_elem_types + 1));
02276 
02277   /* add the new element to the object's list */
02278   plyfile->elems[plyfile->num_elem_types] = elem;
02279   plyfile->num_elem_types++;
02280 }
02281 
02282 
02283 /******************************************************************************
02284 Return the type of a property, given the name of the property.
02285 
02286 Entry:
02287   name - name of property type
02288 
02289 Exit:
02290   returns integer code for property, or 0 if not found
02291 ******************************************************************************/
02292 
02293 int get_prop_type(char *type_name)
02294 {
02295   int i;
02296 
02297   /* try to match the type name */
02298   for (i = StartType + 1; i < EndType; i++)
02299     if (equal_strings (type_name, type_names[i]))
02300       return (i);
02301 
02302   /* see if we can match an old type name */
02303   for (i = StartType + 1; i < EndType; i++)
02304     if (equal_strings (type_name, old_type_names[i]))
02305       return (i);
02306 
02307   /* if we get here, we didn't find the type */
02308   return (0);
02309 }
02310 
02311 
02312 /******************************************************************************
02313 Add a property to a PLY file descriptor.
02314 
02315 Entry:
02316   plyfile - PLY file descriptor
02317   words   - list of words describing the property
02318   nwords  - number of words in the list
02319 ******************************************************************************/
02320 
02321 void add_property (PlyFile *plyfile, char **words, int nwords)
02322 {
02323   int prop_type;
02324   int count_type;
02325   PlyProperty *prop;
02326   PlyElement *elem;
02327 
02328   /* create the new property */
02329 
02330   prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02331 
02332   if (equal_strings (words[1], "list")) {          /* list */
02333     prop->count_external = get_prop_type (words[2]);
02334     prop->external_type = get_prop_type (words[3]);
02335     prop->name = strdup (words[4]);
02336     prop->is_list = PLY_LIST;
02337   }
02338   else if (equal_strings (words[1], "string")) {   /* string */
02339     prop->count_external = Int8;
02340     prop->external_type = Int8;
02341     prop->name = strdup (words[2]);
02342     prop->is_list = PLY_STRING;
02343   }
02344   else {                                           /* scalar */
02345     prop->external_type = get_prop_type (words[1]);
02346     prop->name = strdup (words[2]);
02347     prop->is_list = PLY_SCALAR;
02348   }
02349 
02350   /* add this property to the list of properties of the current element */
02351 
02352   elem = plyfile->elems[plyfile->num_elem_types - 1];
02353 
02354   if (elem->nprops == 0)
02355     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
02356   else
02357     elem->props = (PlyProperty **) realloc (elem->props,
02358                   sizeof (PlyProperty *) * (elem->nprops + 1));
02359 
02360   elem->props[elem->nprops] = prop;
02361   elem->nprops++;
02362 }
02363 
02364 
02365 /******************************************************************************
02366 Add a comment to a PLY file descriptor.
02367 
02368 Entry:
02369   plyfile - PLY file descriptor
02370   line    - line containing comment
02371 ******************************************************************************/
02372 
02373 void add_comment (PlyFile *plyfile, char *line)
02374 {
02375   int i;
02376 
02377   /* skip over "comment" and leading spaces and tabs */
02378   i = 7;
02379   while (line[i] == ' ' || line[i] == '\t')
02380     i++;
02381 
02382   append_comment_ply (plyfile, &line[i]);
02383 }
02384 
02385 
02386 /******************************************************************************
02387 Add a some object information to a PLY file descriptor.
02388 
02389 Entry:
02390   plyfile - PLY file descriptor
02391   line    - line containing text info
02392 ******************************************************************************/
02393 
02394 void add_obj_info (PlyFile *plyfile, char *line)
02395 {
02396   int i;
02397 
02398   /* skip over "obj_info" and leading spaces and tabs */
02399   i = 8;
02400   while (line[i] == ' ' || line[i] == '\t')
02401     i++;
02402 
02403   append_obj_info_ply (plyfile, &line[i]);
02404 }
02405 
02406 
02407 /******************************************************************************
02408 Copy a property.
02409 ******************************************************************************/
02410 
02411 void copy_property(PlyProperty *dest, PlyProperty *src)
02412 {
02413   dest->name = strdup (src->name);
02414   dest->external_type = src->external_type;
02415   dest->internal_type = src->internal_type;
02416   dest->offset = src->offset;
02417 
02418   dest->is_list = src->is_list;
02419   dest->count_external = src->count_external;
02420   dest->count_internal = src->count_internal;
02421   dest->count_offset = src->count_offset;
02422 }
02423 
02424 
02425 /******************************************************************************
02426 Allocate some memory.
02427 
02428 Entry:
02429   size  - amount of memory requested (in bytes)
02430   lnum  - line number from which memory was requested
02431   fname - file name from which memory was requested
02432 ******************************************************************************/
02433 
02434 static char *my_alloc(int size, int lnum, char *fname)
02435 {
02436   char *ptr;
02437 
02438   ptr = (char *) malloc (size);
02439 
02440   if (ptr == 0) {
02441     fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
02442   }
02443 
02444   return (ptr);
02445 }
02446 
02447 
02448 /**** NEW STUFF ****/
02449 /**** NEW STUFF ****/
02450 /**** NEW STUFF ****/
02451 /**** NEW STUFF ****/
02452 
02453 
02454 
02455 /******************************************************************************
02456 Given a file pointer, get ready to read PLY data from the file.
02457 
02458 Entry:
02459   fp - the given file pointer
02460 
02461 Exit:
02462   nelems     - number of elements in object
02463   elem_names - list of element names
02464   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
02465 ******************************************************************************/
02466 
02467 PlyFile *read_ply(FILE *fp)
02468 {
02469   PlyFile *ply;
02470   int num_elems;
02471   char **elem_names;
02472 
02473   ply = ply_read (fp, &num_elems, &elem_names);
02474 
02475   return (ply);
02476 }
02477 
02478 
02479 /******************************************************************************
02480 Given a file pointer, get ready to write PLY data to the file.
02481 
02482 Entry:
02483   fp         - the given file pointer
02484   nelems     - number of elements in object
02485   elem_names - list of element names
02486   file_type  - file type, either ascii or binary
02487 
02488 Exit:
02489   returns a pointer to a PlyFile, used to refer to this file, or NULL if error
02490 ******************************************************************************/
02491 
02492 PlyFile *write_ply(
02493   FILE *fp,
02494   int nelems,
02495   char **elem_names,
02496   int file_type
02497 )
02498 {
02499   PlyFile *ply;
02500 
02501   ply = ply_write (fp, nelems, elem_names, file_type);
02502 
02503   return (ply);
02504 }
02505 
02506 
02507 /******************************************************************************
02508 Return a list of the names of the elements in a particular PLY file.
02509 
02510 Entry:
02511   ply - PLY file whose element name list we want
02512 
02513 Exit:
02514   num_elems  - the number of element names in the list
02515   returns the list of names
02516 ******************************************************************************/
02517 
02518 char **get_element_list_ply(PlyFile *ply, int *num_elems)
02519 {
02520   int i;
02521   char **elist;
02522 
02523   /* create the list of element names */
02524 
02525   elist = (char **) myalloc (sizeof (char *) * ply->num_elem_types);
02526   for (i = 0; i < ply->num_elem_types; i++)
02527     elist[i] = strdup (ply->elems[i]->name);
02528 
02529   /* return the number of elements and the list of element names */
02530   *num_elems = ply->num_elem_types;
02531   return (elist);
02532 }
02533 
02534 
02535 /******************************************************************************
02536 Append a comment to a PLY file.
02537 
02538 Entry:
02539   ply     - file to append comment to
02540   comment - the comment to append
02541 ******************************************************************************/
02542 
02543 void append_comment_ply(PlyFile *ply, char *comment)
02544 {
02545   /* (re)allocate space for new comment */
02546   if (ply->num_comments == 0)
02547     ply->comments = (char **) myalloc (sizeof (char *));
02548   else
02549     ply->comments = (char **) realloc (ply->comments,
02550                      sizeof (char *) * (ply->num_comments + 1));
02551 
02552   /* add comment to list */
02553   ply->comments[ply->num_comments] = strdup (comment);
02554   ply->num_comments++;
02555 }
02556 
02557 
02558 /******************************************************************************
02559 Copy the comments from one PLY file to another.
02560 
02561 Entry:
02562   out_ply - destination file to copy comments to
02563   in_ply  - the source of the comments
02564 ******************************************************************************/
02565 
02566 void copy_comments_ply(PlyFile *out_ply, PlyFile *in_ply)
02567 {
02568   int i;
02569 
02570   for (i = 0; i < in_ply->num_comments; i++)
02571     append_comment_ply (out_ply, in_ply->comments[i]);
02572 }
02573 
02574 
02575 /******************************************************************************
02576 Append object information (arbitrary text) to a PLY file.
02577 
02578 Entry:
02579   ply      - file to append object info to
02580   obj_info - the object info to append
02581 ******************************************************************************/
02582 
02583 void append_obj_info_ply(PlyFile *ply, char *obj_info)
02584 {
02585   /* (re)allocate space for new info */
02586   if (ply->num_obj_info == 0)
02587     ply->obj_info = (char **) myalloc (sizeof (char *));
02588   else
02589     ply->obj_info = (char **) realloc (ply->obj_info,
02590                      sizeof (char *) * (ply->num_obj_info + 1));
02591 
02592   /* add info to list */
02593   ply->obj_info[ply->num_obj_info] = strdup (obj_info);
02594   ply->num_obj_info++;
02595 }
02596 
02597 
02598 /******************************************************************************
02599 Copy the object information from one PLY file to another.
02600 
02601 Entry:
02602   out_ply - destination file to copy object information to
02603   in_ply  - the source of the object information
02604 ******************************************************************************/
02605 
02606 void copy_obj_info_ply(PlyFile *out_ply, PlyFile *in_ply)
02607 {
02608   int i;
02609 
02610   for (i = 0; i < in_ply->num_obj_info; i++)
02611     append_obj_info_ply (out_ply, in_ply->obj_info[i]);
02612 }
02613 
02614 
02615 /******************************************************************************
02616 Close a PLY file.
02617 
02618 Entry:
02619   plyfile - identifier of file to close
02620 ******************************************************************************/
02621 
02622 void close_ply(PlyFile *plyfile)
02623 {
02624   fclose (plyfile->fp);
02625 }
02626 
02627 
02628 /******************************************************************************
02629 Free the memory used by a PLY file.
02630 
02631 Entry:
02632   plyfile - identifier of file
02633 ******************************************************************************/
02634 
02635 void free_ply(PlyFile *plyfile)
02636 {
02637   /* free up memory associated with the PLY file */
02638   free (plyfile);
02639 }
02640 
02641 
02642 /******************************************************************************
02643 Specify the index of the next element to be read in from a PLY file.
02644 
02645 Entry:
02646   ply - file to read from
02647   index - index of the element to be read
02648 
02649 Exit:
02650   elem_count - the number of elements in the file
02651   returns pointer to the name of this next element
02652 ******************************************************************************/
02653 
02654 char *setup_element_read_ply (PlyFile *ply, int index, int *elem_count)
02655 {
02656   PlyElement *elem;
02657 
02658   if (index < 0 || index > ply->num_elem_types) {
02659     fprintf (stderr, "Warning:  No element with index %d\n", index);
02660     return (0);
02661   }
02662 
02663   elem = ply->elems[index];
02664 
02665   /* set this to be the current element */
02666   ply->which_elem = elem;
02667 
02668   /* return the number of such elements in the file and the element's name */
02669   *elem_count = elem->num;
02670   return (elem->name);
02671 }
02672 
02673 
02674 /******************************************************************************
02675 Read one element from the file.  This routine assumes that we're reading
02676 the type of element specified in the last call to the routine
02677 setup_element_read_ply().
02678 
02679 Entry:
02680   plyfile  - file identifier
02681   elem_ptr - pointer to location where the element information should be put
02682 ******************************************************************************/
02683 
02684 void get_element_ply (PlyFile *plyfile, void *elem_ptr)
02685 {
02686   if (plyfile->file_type == PLY_ASCII)
02687     ascii_get_element (plyfile, (char *) elem_ptr);
02688   else
02689     binary_get_element (plyfile, (char *) elem_ptr);
02690 }
02691 
02692 
02693 /******************************************************************************
02694 Specify one of several properties of the current element that is to be
02695 read from a file.  This should be called (usually multiple times) before a
02696 call to the routine get_element_ply().
02697 
02698 Entry:
02699   plyfile - file identifier
02700   prop    - property to add to those that will be returned
02701 ******************************************************************************/
02702 
02703 void setup_property_ply(
02704   PlyFile *plyfile,
02705   PlyProperty *prop
02706 )
02707 {
02708   PlyElement *elem;
02709   PlyProperty *prop_ptr;
02710   int index;
02711 
02712   elem = plyfile->which_elem;
02713 
02714   /* deposit the property information into the element's description */
02715 
02716   prop_ptr = find_property (elem, prop->name, &index);
02717   if (prop_ptr == NULL) {
02718     fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
02719              prop->name, elem->name);
02720     return;
02721   }
02722   prop_ptr->internal_type  = prop->internal_type;
02723   prop_ptr->offset         = prop->offset;
02724   prop_ptr->count_internal = prop->count_internal;
02725   prop_ptr->count_offset   = prop->count_offset;
02726 
02727   /* specify that the user wants this property */
02728   elem->store_prop[index] = STORE_PROP;
02729 }
02730 
02731 
02732 /******************************************************************************
02733 Specify that we want the "other" properties of the current element to be tucked
02734 away within the user's structure.
02735 
02736 Entry:
02737   plyfile - file identifier
02738   offset  - offset to where other_props will be stored inside user's structure
02739 
02740 Exit:
02741   returns pointer to structure containing description of other_props
02742 ******************************************************************************/
02743 
02744 PlyOtherProp *get_other_properties_ply(
02745   PlyFile *plyfile,
02746   int offset
02747 )
02748 {
02749   PlyOtherProp *other;
02750 
02751   other = get_other_properties (plyfile, plyfile->which_elem, offset);
02752   return (other);
02753 }
02754 
02755 
02756 /******************************************************************************
02757 Describe which element is to be written next and state how many of them will
02758 be written.
02759 
02760 Entry:
02761   plyfile   - file identifier
02762   elem_name - name of element that information is being described
02763   nelems    - number of elements of this type to be written
02764 ******************************************************************************/
02765 
02766 void describe_element_ply(
02767   PlyFile *plyfile,
02768   char *elem_name,
02769   int nelems
02770 )
02771 {
02772   int i;
02773   PlyElement *elem;
02774   PlyProperty *prop;
02775 
02776   /* look for appropriate element */
02777   elem = find_element (plyfile, elem_name);
02778   if (elem == NULL) {
02779     fprintf(stderr,"describe_element_ply: can't find element '%s'\n",elem_name);
02780     exit (-1);
02781   }
02782 
02783   elem->num = nelems;
02784 
02785   /* now this element is the current element */
02786   plyfile->which_elem = elem;
02787 }
02788 
02789 
02790 /******************************************************************************
02791 Describe a property of an element.
02792 
02793 Entry:
02794   plyfile   - file identifier
02795   prop      - the new property
02796 ******************************************************************************/
02797 
02798 void describe_property_ply(
02799   PlyFile *plyfile,
02800   PlyProperty *prop
02801 )
02802 {
02803   PlyElement *elem;
02804   PlyProperty *elem_prop;
02805 
02806   elem = plyfile->which_elem;
02807 
02808   /* create room for new property */
02809 
02810   if (elem->nprops == 0) {
02811     elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
02812     elem->store_prop = (char *) myalloc (sizeof (char));
02813     elem->nprops = 1;
02814   }
02815   else {
02816     elem->nprops++;
02817     elem->props = (PlyProperty **)
02818                   realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
02819     elem->store_prop = (char *)
02820                   realloc (elem->store_prop, sizeof (char) * elem->nprops);
02821   }
02822 
02823   /* copy the new property */
02824 
02825   elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02826   elem->props[elem->nprops - 1] = elem_prop;
02827   elem->store_prop[elem->nprops - 1] = NAMED_PROP;
02828   copy_property (elem_prop, prop);
02829 }
02830 
02831 
02832 /******************************************************************************
02833 Describe what the "other" properties are that are to be stored, and where
02834 they are in an element.
02835 ******************************************************************************/
02836 
02837 void describe_other_properties_ply(
02838   PlyFile *plyfile,
02839   PlyOtherProp *other,
02840   int offset
02841 )
02842 {
02843   int i;
02844   PlyElement *elem;
02845   PlyProperty *prop;
02846 
02847   /* look for appropriate element */
02848   elem = find_element (plyfile, other->name);
02849   if (elem == NULL) {
02850     fprintf(stderr, "describe_other_properties_ply: can't find element '%s'\n",
02851             other->name);
02852     return;
02853   }
02854 
02855   /* create room for other properties */
02856 
02857   if (elem->nprops == 0) {
02858     elem->props = (PlyProperty **)
02859                   myalloc (sizeof (PlyProperty *) * other->nprops);
02860     elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
02861     elem->nprops = 0;
02862   }
02863   else {
02864     int newsize;
02865     newsize = elem->nprops + other->nprops;
02866     elem->props = (PlyProperty **)
02867                   realloc (elem->props, sizeof (PlyProperty *) * newsize);
02868     elem->store_prop = (char *)
02869                   realloc (elem->store_prop, sizeof (char) * newsize);
02870   }
02871 
02872   /* copy the other properties */
02873 
02874   for (i = 0; i < other->nprops; i++) {
02875     prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
02876     copy_property (prop, other->props[i]);
02877     elem->props[elem->nprops] = prop;
02878     elem->store_prop[elem->nprops] = OTHER_PROP;
02879     elem->nprops++;
02880   }
02881 
02882   /* save other info about other properties */
02883   elem->other_size = other->size;
02884   elem->other_offset = offset;
02885 }
02886 
02887 
02888 /******************************************************************************
02889 Pass along a pointer to "other" elements that we want to save in a given
02890 PLY file.  These other elements were presumably read from another PLY file.
02891 
02892 Entry:
02893   plyfile     - file pointer in which to store this other element info
02894   other_elems - info about other elements that we want to store
02895 ******************************************************************************/
02896 
02897 void describe_other_elements_ply (
02898   PlyFile *plyfile,
02899   PlyOtherElems *other_elems
02900 )
02901 {
02902   int i;
02903   OtherElem *other;
02904 
02905   /* ignore this call if there is no other element */
02906   if (other_elems == NULL)
02907     return;
02908 
02909   /* save pointer to this information */
02910   plyfile->other_elems = other_elems;
02911 
02912   /* describe the other properties of this element */
02913 
02914   for (i = 0; i < other_elems->num_elems; i++) {
02915     other = &(other_elems->other_list[i]);
02916     element_count_ply (plyfile, other->elem_name, other->elem_count);
02917     describe_other_properties_ply (plyfile, other->other_props,
02918                                    offsetof(OtherData,other_props));
02919   }
02920 }
02921 
02922 
02923 
02924 /**** Property Propagation Rules ****/
02925 
02926 
02927 typedef struct RuleName {
02928   int code;
02929   char *name;
02930 } RuleName;
02931 
02932 RuleName rule_name_list[] = {
02933   AVERAGE_RULE, "avg",
02934   RANDOM_RULE, "rnd",
02935   MINIMUM_RULE, "max",
02936   MAXIMUM_RULE, "min",
02937   MAJORITY_RULE, "major",
02938   SAME_RULE, "same",
02939   -1, "end_marker",
02940 };
02941 
02942 
02943 
02944 /******************************************************************************
02945 Initialize the property propagation rules for an element.  Default is to
02946 use averaging (AVERAGE_RULE) for creating all new properties.
02947 
02948 Entry:
02949   ply       - PLY object that this is for
02950   elem_name - name of the element that we're making the rules for
02951 
02952 Exit:
02953   returns pointer to the default rules
02954 ******************************************************************************/
02955 
02956 PlyPropRules *init_rule_ply (PlyFile *ply, char *elem_name)
02957 {
02958   int i,j;
02959   PlyElement *elem;
02960   PlyPropRules *rules;
02961   PlyRuleList *list;
02962   int found_prop;
02963 
02964   elem = find_element (ply, elem_name);
02965   if (elem == NULL) {
02966     fprintf (stderr, "init_rule_ply: Can't find element '%s'\n", elem_name);
02967     exit (-1);
02968   }
02969 
02970   rules = (PlyPropRules *) myalloc (sizeof (PlyPropRules));
02971   rules->elem = elem;
02972   rules->rule_list = (int *) myalloc (sizeof(int) * elem->nprops);
02973   rules->max_props = 0;
02974   rules->nprops = 0;
02975 
02976   /* default is to use averaging rule */
02977   for (i = 0; i < elem->nprops; i++)
02978     rules->rule_list[i] = AVERAGE_RULE;
02979 
02980   /* see if there are other rules we should use */
02981 
02982   if (ply->rule_list == NULL)
02983     return (rules);
02984 
02985   /* try to match the element, property and rule name */
02986 
02987   for (list = ply->rule_list; list != NULL; list = list->next) {
02988 
02989     if (!equal_strings (list->element, elem->name))
02990       continue;
02991 
02992     found_prop = 0;
02993 
02994     for (i = 0; i < elem->nprops; i++)
02995       if (equal_strings (list->property, elem->props[i]->name)) {
02996 
02997         found_prop = 1;
02998 
02999         /* look for matching rule name */
03000         for (j = 0; rule_name_list[j].code != -1; j++)
03001           if (equal_strings (list->name, rule_name_list[j].name)) {
03002             rules->rule_list[i] = rule_name_list[j].code;
03003             break;
03004           }
03005       }
03006 
03007     if (!found_prop) {
03008       fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
03009                list->property, list->name);
03010       continue;
03011     }
03012   }
03013 
03014   return (rules);
03015 }
03016 
03017 
03018 /******************************************************************************
03019 Modify a property propagation rule.
03020 
03021 Entry:
03022   rules - rules for the element
03023   prop_name - name of the property whose rule we're modifying
03024   rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.)
03025 ******************************************************************************/
03026 
03027 void modify_rule_ply (PlyPropRules *rules, char *prop_name, int rule_type)
03028 {
03029   int i;
03030   PlyElement *elem = rules->elem;
03031 
03032   /* find the property and modify its rule type */
03033 
03034   for (i = 0; i < elem->nprops; i++)
03035     if (equal_strings (elem->props[i]->name, prop_name)) {
03036       rules->rule_list[i] = rule_type;
03037       return;
03038     }
03039 
03040   /* we didn't find the property if we get here */
03041   fprintf (stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name);
03042   exit (-1);
03043 }
03044 
03045 
03046 /******************************************************************************
03047 Begin to create a set of properties from a set of propagation rules.
03048 
03049 Entry:
03050   ply   - PLY object whose rules we're preparing to use
03051   rules - rules for the element
03052 ******************************************************************************/
03053 
03054 void start_props_ply (PlyFile *ply, PlyPropRules *rules)
03055 {
03056   int i;
03057   int count;
03058   PlyElement *elem = rules->elem;
03059 
03060   /* save pointer to the rules in the PLY object */
03061   ply->current_rules = rules;
03062 
03063   /* get ready for new sets of properties to combine */
03064   rules->nprops = 0;
03065 }
03066 
03067 
03068 /******************************************************************************
03069 Remember a set of properties and their weights for creating a new set of
03070 properties.
03071 
03072 Entry:
03073   weight      - weights for this set of properties
03074   other_props - the properties to use
03075 ******************************************************************************/
03076 
03077 void weight_props_ply (PlyFile *ply, float weight, void *other_props)
03078 {
03079   PlyPropRules *rules = ply->current_rules;
03080 
03081   /* allocate space for properties and weights, if necessary */
03082   if (rules->max_props == 0) {
03083     rules->max_props = 6;
03084     rules->props = (void **) myalloc (sizeof (void *) * rules->max_props);
03085     rules->weights = (float *) myalloc (sizeof (float) * rules->max_props);
03086   }
03087   if (rules->nprops == rules->max_props) {
03088     rules->max_props *= 2;
03089     rules->props = (void **) realloc (rules->props,
03090                    sizeof (void *) * rules->max_props);
03091     rules->weights = (float *) realloc (rules->weights,
03092                      sizeof (float) * rules->max_props);
03093   }
03094 
03095   /* remember these new properties and their weights */
03096 
03097   rules->props[rules->nprops] = other_props;
03098   rules->weights[rules->nprops] = weight;
03099   rules->nprops++;
03100 }
03101 
03102 
03103 /******************************************************************************
03104 Return a pointer to a new set of properties that have been created using
03105 a specified set of property combination rules and a given collection of
03106 "other" properties.
03107 
03108 Exit:
03109   returns a pointer to the new properties
03110 ******************************************************************************/
03111 
03112 void *get_new_props_ply(PlyFile *ply)
03113 {
03114   int i,j;
03115   static double *vals;
03116   static int max_vals = 0;
03117   PlyPropRules *rules = ply->current_rules;
03118   PlyElement *elem = rules->elem;
03119   PlyProperty *prop;
03120   char *data;
03121   char *new_data;
03122   void *ptr;
03123   int offset;
03124   int type;
03125   double double_val;
03126   int int_val;
03127   unsigned int uint_val;
03128   int random_pick;
03129 
03130   /* return NULL if we've got no "other" properties */
03131   if (elem->other_size == 0) {
03132     return (NULL);
03133   }
03134 
03135   /* create room for combined other properties */
03136   new_data = (char *) myalloc (sizeof (char) * elem->other_size);
03137 
03138   /* make sure there is enough room to store values we're to combine */
03139 
03140   if (max_vals == 0) {
03141     max_vals = rules->nprops;
03142     vals = (double *) myalloc (sizeof (double) * rules->nprops);
03143   }
03144   if (rules->nprops >= max_vals) {
03145     max_vals = rules->nprops;
03146     vals = (double *) realloc (vals, sizeof (double) * rules->nprops);
03147   }
03148 
03149   /* in case we need a random choice */
03150   random_pick = (int) floor (rules->nprops * rand());
03151 
03152   /* calculate the combination for each "other" property of the element */
03153 
03154   for (i = 0; i < elem->nprops; i++) {
03155 
03156     /* don't bother with properties we've been asked to store explicitly */
03157     if (elem->store_prop[i])
03158       continue;
03159 
03160     prop = elem->props[i];
03161     offset = prop->offset;
03162     type = prop->external_type;
03163 
03164     /* collect together all the values we're to combine */
03165 
03166     for (j = 0; j < rules->nprops; j++) {
03167       data = (char *) rules->props[j];
03168       ptr = (void *) (data + offset);
03169       get_stored_item ((void *) ptr, type, &int_val, &uint_val, &double_val);
03170       vals[j] = double_val;
03171     }
03172 
03173     /* calculate the combined value */
03174 
03175     switch (rules->rule_list[i]) {
03176       case AVERAGE_RULE: {
03177         double sum = 0;
03178         double weight_sum = 0;
03179         for (j = 0; j < rules->nprops; j++) {
03180           sum += vals[j] * rules->weights[j];
03181           weight_sum += rules->weights[j];
03182         }
03183         double_val = sum / weight_sum;
03184         break;
03185       }
03186       case MINIMUM_RULE: {
03187         double_val = vals[0];
03188         for (j = 1; j < rules->nprops; j++)
03189           if (double_val > vals[j])
03190             double_val = vals[j];
03191         break;
03192       }
03193       case MAXIMUM_RULE: {
03194         double_val = vals[0];
03195         for (j = 1; j < rules->nprops; j++)
03196           if (double_val < vals[j])
03197             double_val = vals[j];
03198         break;
03199       }
03200       case RANDOM_RULE: {
03201         double_val = vals[random_pick];
03202         break;
03203       }
03204       case SAME_RULE: {
03205         double_val = vals[0];
03206         for (j = 1; j < rules->nprops; j++)
03207           if (double_val != vals[j]) {
03208             fprintf (stderr,
03209     "get_new_props_ply: Error combining properties that should be the same.\n");
03210             exit (-1);
03211           }
03212         break;
03213       }
03214       default:
03215         fprintf (stderr, "get_new_props_ply: Bad rule = %d\n",
03216                  rules->rule_list[i]);
03217         exit (-1);
03218     }
03219 
03220     /* store the combined value */
03221 
03222     int_val = (int) double_val;
03223     uint_val = (unsigned int) double_val;
03224     ptr = (void *) (new_data + offset);
03225     store_item ((char *) ptr, type, int_val, uint_val, double_val);
03226   }
03227 
03228   return ((void *) new_data);
03229 }
03230 
03231 
03232 /******************************************************************************
03233 Set the list of user-specified property combination rules.
03234 ******************************************************************************/
03235 
03236 void set_prop_rules_ply (PlyFile *ply, PlyRuleList *prop_rules)
03237 {
03238   ply->rule_list = prop_rules;
03239 }
03240 
03241 
03242 /******************************************************************************
03243 Append a property rule to a growing list of user-specified rules.
03244 
03245 Entry:
03246   rule_list - current rule list
03247   name      - name of property combination rule
03248   property  - "element.property" says which property the rule affects
03249 
03250 Exit:
03251   returns pointer to the new rule list
03252 ******************************************************************************/
03253 
03254 PlyRuleList *append_prop_rule (
03255   PlyRuleList *rule_list,
03256   char *name,
03257   char *property
03258 )
03259 {
03260   PlyRuleList *rule;
03261   PlyRuleList *rule_ptr;
03262   char *str,*str2;
03263   char *ptr;
03264 
03265   /* find . */
03266   str = strdup (property);
03267   for (ptr = str; *ptr != '\0' && *ptr != '.'; ptr++) ;
03268 
03269   /* split string at . */
03270   if (*ptr == '.') {
03271     *ptr = '\0';
03272     str2 = ptr + 1;
03273   }
03274   else {
03275     fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
03276              property, name);
03277     return (rule_list);
03278   }
03279 
03280   rule = (PlyRuleList *) malloc (sizeof (PlyRuleList));
03281   rule->name = name;
03282   rule->element = str;
03283   rule->property = str2;
03284   rule->next = NULL;
03285 
03286   /* either start rule list or append to it */
03287 
03288   if (rule_list == NULL)
03289     rule_list = rule;
03290   else {                      /* append new rule to current list */
03291     rule_ptr = rule_list;
03292     while (rule_ptr->next != NULL)
03293       rule_ptr = rule_ptr->next;
03294     rule_ptr->next = rule;
03295   }
03296 
03297   /* return pointer to list */
03298 
03299   return (rule_list);
03300 }
03301 
03302 
03303 /******************************************************************************
03304 See if a name matches the name of any property combination rules.
03305 
03306 Entry:
03307   name - name of rule we're trying to match
03308 
03309 Exit:
03310   returns 1 if we find a match, 0 if not
03311 ******************************************************************************/
03312 
03313 int matches_rule_name (char *name)
03314 {
03315   int i;
03316 
03317   for (i = 0; rule_name_list[i].code != -1; i++)
03318     if (equal_strings (rule_name_list[i].name, name))
03319       return (1);
03320 
03321   return (0);
03322 }
03323 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


household_objects_database
Author(s): Matei Ciocarlie, except for source files individually marked otherwise
autogenerated on Fri Jan 25 2013 15:02:09