Closest Point Find the Closest Point on a mesh

- Main Page
- Classes
- Files

- File List

src/ply.c

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

All Classes