Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

ply.c

Go to the documentation of this file.
00001 /*
00002 
00003 The interface routines for reading and writing PLY polygon files.
00004 
00005 Greg Turk
00006 
00007 ---------------------------------------------------------------
00008 
00009 A PLY file contains a single polygonal _object_.
00010 
00011 An object is composed of lists of _elements_.  Typical elements are
00012 vertices, faces, edges and materials.
00013 
00014 Each type of element for a given object has one or more _properties_
00015 associated with the element type.  For instance, a vertex element may
00016 have as properties the floating-point values x,y,z and the three unsigned
00017 chars representing red, green and blue.
00018 
00019 -----------------------------------------------------------------------
00020 
00021 Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.   
00022   
00023 Permission to use, copy, modify and distribute this software and its   
00024 documentation for any purpose is hereby granted without fee, provided   
00025 that the above copyright notice and this permission notice appear in   
00026 all copies of this software and that you do not sell the software.   
00027   
00028 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
00029 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
00030 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
00031 
00032 */
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <math.h>
00037 #include <string.h>
00038 #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 
00740   fp = fopen (name, "r");
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 #if defined(_MSC_VER)
03141   random_pick = 0;
03142 #else
03143   random_pick = (int) floor (rules->nprops * drand48());
03144 #endif
03145   /* calculate the combination for each "other" property of the element */
03146 
03147   for (i = 0; i < elem->nprops; i++) {
03148 
03149     /* don't bother with properties we've been asked to store explicitly */
03150     if (elem->store_prop[i])
03151       continue;
03152 
03153     prop = elem->props[i];
03154     offset = prop->offset;
03155     type = prop->external_type;
03156 
03157     /* collect together all the values we're to combine */
03158 
03159     for (j = 0; j < rules->nprops; j++) {
03160       data = (char *) rules->props[j];
03161       ptr = (void *) (data + offset);
03162       get_stored_item ((void *) ptr, type, &int_val, &uint_val, &double_val);
03163       vals[j] = double_val;
03164     }
03165 
03166     /* calculate the combined value */
03167 
03168     switch (rules->rule_list[i]) {
03169       case AVERAGE_RULE: {
03170         double sum = 0;
03171         double weight_sum = 0;
03172         for (j = 0; j < rules->nprops; j++) {
03173           sum += vals[j] * rules->weights[j];
03174           weight_sum += rules->weights[j];
03175         }
03176         double_val = sum / weight_sum;
03177         break;
03178       }
03179       case MINIMUM_RULE: {
03180         double_val = vals[0];
03181         for (j = 1; j < rules->nprops; j++)
03182           if (double_val > vals[j])
03183             double_val = vals[j];
03184         break;
03185       }
03186       case MAXIMUM_RULE: {
03187         double_val = vals[0];
03188         for (j = 1; j < rules->nprops; j++)
03189           if (double_val < vals[j])
03190             double_val = vals[j];
03191         break;
03192       }
03193       case RANDOM_RULE: {
03194         double_val = vals[random_pick];
03195         break;
03196       }
03197       case SAME_RULE: {
03198         double_val = vals[0];
03199         for (j = 1; j < rules->nprops; j++)
03200           if (double_val != vals[j]) {
03201             fprintf (stderr,
03202     "get_new_props_ply: Error combining properties that should be the same.\n");
03203             exit (-1);
03204           }
03205         break;
03206       }
03207       default:
03208         fprintf (stderr, "get_new_props_ply: Bad rule = %d\n",
03209                  rules->rule_list[i]);
03210         exit (-1);
03211     }
03212 
03213     /* store the combined value */
03214 
03215     int_val = (int) double_val;
03216     uint_val = (unsigned int) double_val;
03217     ptr = (void *) (new_data + offset);
03218     store_item ((char *) ptr, type, int_val, uint_val, double_val);
03219   }
03220 
03221   return ((void *) new_data);
03222 }
03223 
03224 
03225 /******************************************************************************
03226 Set the list of user-specified property combination rules.
03227 ******************************************************************************/
03228 
03229 void set_prop_rules_ply (PlyFile *ply, PlyRuleList *prop_rules)
03230 {
03231   ply->rule_list = prop_rules;
03232 }
03233 
03234 
03235 /******************************************************************************
03236 Append a property rule to a growing list of user-specified rules.
03237 
03238 Entry:
03239   rule_list - current rule list
03240   name      - name of property combination rule
03241   property  - "element.property" says which property the rule affects
03242 
03243 Exit:
03244   returns pointer to the new rule list
03245 ******************************************************************************/
03246 
03247 PlyRuleList *append_prop_rule (
03248   PlyRuleList *rule_list,
03249   char *name,
03250   char *property
03251 )
03252 {
03253   PlyRuleList *rule;
03254   PlyRuleList *rule_ptr;
03255   char *str,*str2;
03256   char *ptr;
03257 
03258   /* find . */
03259   str = strdup (property);
03260   for (ptr = str; *ptr != '\0' && *ptr != '.'; ptr++) ;
03261 
03262   /* split string at . */
03263   if (*ptr == '.') {
03264     *ptr = '\0';
03265     str2 = ptr + 1;
03266   }
03267   else {
03268     fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
03269              property, name);
03270     return (rule_list);
03271   }
03272 
03273   rule = (PlyRuleList *) malloc (sizeof (PlyRuleList));
03274   rule->name = name;
03275   rule->element = str;
03276   rule->property = str2;
03277   rule->next = NULL;
03278 
03279   /* either start rule list or append to it */
03280 
03281   if (rule_list == NULL)
03282     rule_list = rule;
03283   else {                      /* append new rule to current list */
03284     rule_ptr = rule_list;
03285     while (rule_ptr->next != NULL)
03286       rule_ptr = rule_ptr->next;
03287     rule_ptr->next = rule;
03288   }
03289 
03290   /* return pointer to list */
03291 
03292   return (rule_list);
03293 }
03294 
03295 
03296 /******************************************************************************
03297 See if a name matches the name of any property combination rules.
03298 
03299 Entry:
03300   name - name of rule we're trying to match
03301 
03302 Exit:
03303   returns 1 if we find a match, 0 if not
03304 ******************************************************************************/
03305 
03306 int matches_rule_name (char *name)
03307 {
03308   int i;
03309 
03310   for (i = 0; rule_name_list[i].code != -1; i++)
03311     if (equal_strings (rule_name_list[i].name, name))
03312       return (1);
03313 
03314   return (0);
03315 }
03316 

Generated on Tue Mar 19 03:09:48 2024 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002