Subversion Repositories gelsvn

Rev

Rev 337 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
337 jab 1
/*
2
 
3
The interface routines for reading and writing PLY polygon files.
4
 
5
Greg Turk
6
 
7
---------------------------------------------------------------
8
 
9
A PLY file contains a single polygonal _object_.
10
 
11
An object is composed of lists of _elements_.  Typical elements are
12
vertices, faces, edges and materials.
13
 
14
Each type of element for a given object has one or more _properties_
15
associated with the element type.  For instance, a vertex element may
16
have as properties the floating-point values x,y,z and the three unsigned
17
chars representing red, green and blue.
18
 
19
-----------------------------------------------------------------------
20
 
21
Copyright (c) 1998 Georgia Institute of Technology.  All rights reserved.   
22
 
23
Permission to use, copy, modify and distribute this software and its   
24
documentation for any purpose is hereby granted without fee, provided   
25
that the above copyright notice and this permission notice appear in   
26
all copies of this software and that you do not sell the software.   
27
 
28
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,   
29
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY   
30
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.   
31
 
32
*/
33
 
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <math.h>
37
#include <string.h>
365 jab 38
#include "ply.h"
337 jab 39
 
40
char *type_names[] = {  /* names of scalar types */
41
"invalid",
42
"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
43
};
44
 
45
char *old_type_names[] = {  /* old names of types for backward compatability */
46
"invalid",
47
"char", "short", "int", "uchar", "ushort", "uint", "float", "double",
48
};
49
 
50
int ply_type_size[] = {
51
  0, 1, 2, 4, 1, 2, 4, 4, 8
52
};
53
 
54
#define NO_OTHER_PROPS  -1
55
 
56
#define DONT_STORE_PROP  0
57
#define STORE_PROP       1
58
 
59
#define OTHER_PROP       0
60
#define NAMED_PROP       1
61
 
62
/* returns 1 if strings are equal, 0 if not */
63
int equal_strings(char *, char *);
64
 
65
/* find an element in a plyfile's list */
66
PlyElement *find_element(PlyFile *, char *);
67
 
68
/* find a property in an element's list */
69
PlyProperty *find_property(PlyElement *, char *, int *);
70
 
71
/* write to a file the word describing a PLY file data type */
72
void write_scalar_type (FILE *, int);
73
 
74
/* read a line from a file and break it up into separate words */
75
char **get_words(FILE *, int *, char **);
76
 
77
/* write an item to a file */
78
void write_binary_item(FILE *, int, unsigned int, double, int);
79
void write_ascii_item(FILE *, int, unsigned int, double, int);
80
 
81
/* add information to a PLY file descriptor */
82
void add_element(PlyFile *, char **, int);
83
void add_property(PlyFile *, char **, int);
84
void add_comment(PlyFile *, char *);
85
void add_obj_info(PlyFile *, char *);
86
 
87
/* copy a property */
88
void copy_property(PlyProperty *, PlyProperty *);
89
 
90
/* store a value into where a pointer and a type specify */
91
void store_item(char *, int, int, unsigned int, double);
92
 
93
/* return the value of a stored item */
94
void get_stored_item( void *, int, int *, unsigned int *, double *);
95
 
96
/* return the value stored in an item, given ptr to it and its type */
97
double get_item_value(char *, int);
98
 
99
/* get binary or ascii item and store it according to ptr and type */
100
void get_ascii_item(char *, int, int *, unsigned int *, double *);
101
void get_binary_item(FILE *, int, int *, unsigned int *, double *);
102
 
103
/* get a bunch of elements from a file */
104
void ascii_get_element(PlyFile *, char *);
105
void binary_get_element(PlyFile *, char *);
106
 
107
/* memory allocation */
108
static char *my_alloc(int, int, char *);
109
 
110
 
111
/*************/
112
/*  Writing  */
113
/*************/
114
 
115
 
116
/******************************************************************************
117
Given a file pointer, get ready to write PLY data to the file.
118
 
119
Entry:
120
  fp         - the given file pointer
121
  nelems     - number of elements in object
122
  elem_names - list of element names
123
  file_type  - file type, either ascii or binary
124
 
125
Exit:
126
  returns a pointer to a PlyFile, used to refer to this file, or NULL if error
127
******************************************************************************/
128
 
129
PlyFile *ply_write(
130
  FILE *fp,
131
  int nelems,
132
  char **elem_names,
133
  int file_type
134
)
135
{
136
  int i;
137
  PlyFile *plyfile;
138
  PlyElement *elem;
139
 
140
  /* check for NULL file pointer */
141
  if (fp == NULL)
142
    return (NULL);
143
 
144
  /* create a record for this object */
145
 
146
  plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
147
  plyfile->file_type = file_type;
148
  plyfile->num_comments = 0;
149
  plyfile->num_obj_info = 0;
150
  plyfile->num_elem_types = nelems;
151
  plyfile->version = 1.0;
152
  plyfile->fp = fp;
153
  plyfile->other_elems = NULL;
154
 
155
  /* tuck aside the names of the elements */
156
 
157
  plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
158
  for (i = 0; i < nelems; i++) {
159
    elem = (PlyElement *) myalloc (sizeof (PlyElement));
160
    plyfile->elems[i] = elem;
161
    elem->name = strdup (elem_names[i]);
162
    elem->num = 0;
163
    elem->nprops = 0;
164
  }
165
 
166
  /* return pointer to the file descriptor */
167
  return (plyfile);
168
}
169
 
170
 
171
/******************************************************************************
172
Open a polygon file for writing.
173
 
174
Entry:
175
  filename   - name of file to read from
176
  nelems     - number of elements in object
177
  elem_names - list of element names
178
  file_type  - file type, either ascii or binary
179
 
180
Exit:
181
  returns a file identifier, used to refer to this file, or NULL if error
182
******************************************************************************/
183
 
184
PlyFile *open_for_writing_ply(
185
  char *filename,
186
  int nelems,
187
  char **elem_names,
188
  int file_type
189
)
190
{
191
  int i;
192
  PlyFile *plyfile;
193
  PlyElement *elem;
194
  char *name;
195
  FILE *fp;
196
 
197
  /* tack on the extension .ply, if necessary */
198
 
199
  name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
200
  strcpy (name, filename);
201
  if (strlen (name) < 4 ||
202
      strcmp (name + strlen (name) - 4, ".ply") != 0)
203
      strcat (name, ".ply");
204
 
205
  /* open the file for writing */
206
 
207
  fp = fopen (name, "w");
208
  if (fp == NULL) {
209
    return (NULL);
210
  }
211
 
212
  /* create the actual PlyFile structure */
213
 
214
  plyfile = ply_write (fp, nelems, elem_names, file_type);
215
  if (plyfile == NULL)
216
    return (NULL);
217
 
218
  /* return pointer to the file descriptor */
219
  return (plyfile);
220
}
221
 
222
 
223
/******************************************************************************
224
Describe an element, including its properties and how many will be written
225
to the file.
226
 
227
Entry:
228
  plyfile   - file identifier
229
  elem_name - name of element that information is being specified about
230
  nelems    - number of elements of this type to be written
231
  nprops    - number of properties contained in the element
232
  prop_list - list of properties
233
******************************************************************************/
234
 
235
void element_layout_ply(
236
  PlyFile *plyfile,
237
  char *elem_name,
238
  int nelems,
239
  int nprops,
240
  PlyProperty *prop_list
241
)
242
{
243
  int i;
244
  PlyElement *elem;
245
  PlyProperty *prop;
246
 
247
  /* look for appropriate element */
248
  elem = find_element (plyfile, elem_name);
249
  if (elem == NULL) {
250
    fprintf(stderr,"element_layout_ply: can't find element '%s'\n",elem_name);
251
    exit (-1);
252
  }
253
 
254
  elem->num = nelems;
255
 
256
  /* copy the list of properties */
257
 
258
  elem->nprops = nprops;
259
  elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
260
  elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
261
 
262
  for (i = 0; i < nprops; i++) {
263
    prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
264
    elem->props[i] = prop;
265
    elem->store_prop[i] = NAMED_PROP;
266
    copy_property (prop, &prop_list[i]);
267
  }
268
}
269
 
270
 
271
/******************************************************************************
272
Describe a property of an element.
273
 
274
Entry:
275
  plyfile   - file identifier
276
  elem_name - name of element that information is being specified about
277
  prop      - the new property
278
******************************************************************************/
279
 
280
void ply_describe_property(
281
  PlyFile *plyfile,
282
  char *elem_name,
283
  PlyProperty *prop
284
)
285
{
286
  PlyElement *elem;
287
  PlyProperty *elem_prop;
288
 
289
  /* look for appropriate element */
290
  elem = find_element (plyfile, elem_name);
291
  if (elem == NULL) {
292
    fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
293
            elem_name);
294
    return;
295
  }
296
 
297
  /* create room for new property */
298
 
299
  if (elem->nprops == 0) {
300
    elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
301
    elem->store_prop = (char *) myalloc (sizeof (char));
302
    elem->nprops = 1;
303
  }
304
  else {
305
    elem->nprops++;
306
    elem->props = (PlyProperty **)
307
                  realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
308
    elem->store_prop = (char *)
309
                  realloc (elem->store_prop, sizeof (char) * elem->nprops);
310
  }
311
 
312
  /* copy the new property */
313
 
314
  elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
315
  elem->props[elem->nprops - 1] = elem_prop;
316
  elem->store_prop[elem->nprops - 1] = NAMED_PROP;
317
  copy_property (elem_prop, prop);
318
}
319
 
320
 
321
/******************************************************************************
322
State how many of a given element will be written.
323
 
324
Entry:
325
  plyfile   - file identifier
326
  elem_name - name of element that information is being specified about
327
  nelems    - number of elements of this type to be written
328
******************************************************************************/
329
 
330
void element_count_ply(
331
  PlyFile *plyfile,
332
  char *elem_name,
333
  int nelems
334
)
335
{
336
  int i;
337
  PlyElement *elem;
338
  PlyProperty *prop;
339
 
340
  /* look for appropriate element */
341
  elem = find_element (plyfile, elem_name);
342
  if (elem == NULL) {
343
    fprintf(stderr,"element_count_ply: can't find element '%s'\n",elem_name);
344
    exit (-1);
345
  }
346
 
347
  elem->num = nelems;
348
}
349
 
350
 
351
/******************************************************************************
352
Signal that we've described everything a PLY file's header and that the
353
header should be written to the file.
354
 
355
Entry:
356
  plyfile - file identifier
357
******************************************************************************/
358
 
359
void header_complete_ply(PlyFile *plyfile)
360
{
361
  int i,j;
362
  FILE *fp = plyfile->fp;
363
  PlyElement *elem;
364
  PlyProperty *prop;
365
 
366
  fprintf (fp, "ply\n");
367
 
368
  switch (plyfile->file_type) {
369
    case PLY_ASCII:
370
      fprintf (fp, "format ascii 1.0\n");
371
      break;
372
    case PLY_BINARY_BE:
373
      fprintf (fp, "format binary_big_endian 1.0\n");
374
      break;
375
    case PLY_BINARY_LE:
376
      fprintf (fp, "format binary_little_endian 1.0\n");
377
      break;
378
    default:
379
      fprintf (stderr, "ply_header_complete: bad file type = %d\n",
380
               plyfile->file_type);
381
      exit (-1);
382
  }
383
 
384
  /* write out the comments */
385
 
386
  for (i = 0; i < plyfile->num_comments; i++)
387
    fprintf (fp, "comment %s\n", plyfile->comments[i]);
388
 
389
  /* write out object information */
390
 
391
  for (i = 0; i < plyfile->num_obj_info; i++)
392
    fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
393
 
394
  /* write out information about each element */
395
 
396
  for (i = 0; i < plyfile->num_elem_types; i++) {
397
 
398
    elem = plyfile->elems[i];
399
    fprintf (fp, "element %s %d\n", elem->name, elem->num);
400
 
401
    /* write out each property */
402
    for (j = 0; j < elem->nprops; j++) {
403
      prop = elem->props[j];
404
      if (prop->is_list == PLY_LIST) {
405
        fprintf (fp, "property list ");
406
        write_scalar_type (fp, prop->count_external);
407
        fprintf (fp, " ");
408
        write_scalar_type (fp, prop->external_type);
409
        fprintf (fp, " %s\n", prop->name);
410
      }
411
      else if (prop->is_list == PLY_STRING) {
412
        fprintf (fp, "property string");
413
        fprintf (fp, " %s\n", prop->name);
414
      }
415
      else {
416
        fprintf (fp, "property ");
417
        write_scalar_type (fp, prop->external_type);
418
        fprintf (fp, " %s\n", prop->name);
419
      }
420
    }
421
  }
422
 
423
  fprintf (fp, "end_header\n");
424
}
425
 
426
 
427
/******************************************************************************
428
Specify which elements are going to be written.  This should be called
429
before a call to the routine ply_put_element().
430
 
431
Entry:
432
  plyfile   - file identifier
433
  elem_name - name of element we're talking about
434
******************************************************************************/
435
 
436
void put_element_setup_ply(PlyFile *plyfile, char *elem_name)
437
{
438
  PlyElement *elem;
439
 
440
  elem = find_element (plyfile, elem_name);
441
  if (elem == NULL) {
442
    fprintf(stderr, "put_element_setup_ply: can't find element '%s'\n", elem_name);
443
    exit (-1);
444
  }
445
 
446
  plyfile->which_elem = elem;
447
}
448
 
449
 
450
/******************************************************************************
451
Write an element to the file.  This routine assumes that we're
452
writing the type of element specified in the last call to the routine
453
put_element_setup_ply().
454
 
455
Entry:
456
  plyfile  - file identifier
457
  elem_ptr - pointer to the element
458
******************************************************************************/
459
 
460
void put_element_ply(PlyFile *plyfile, void *elem_ptr)
461
{
462
  int i,j,k;
463
  FILE *fp = plyfile->fp;
464
  PlyElement *elem;
465
  PlyProperty *prop;
466
  char *item;
467
  char *elem_data;
468
  char **item_ptr;
469
  int list_count;
470
  int item_size;
471
  int int_val;
472
  unsigned int uint_val;
473
  double double_val;
474
  char **other_ptr;
475
 
476
  elem = plyfile->which_elem;
477
  elem_data = (char *) elem_ptr;
478
  other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
479
 
480
  /* write out either to an ascii or binary file */
481
 
482
  if (plyfile->file_type == PLY_ASCII) {
483
 
484
    /* write an ascii file */
485
 
486
    /* write out each property of the element */
487
    for (j = 0; j < elem->nprops; j++) {
488
 
489
      prop = elem->props[j];
490
 
491
      if (elem->store_prop[j] == OTHER_PROP)
492
        elem_data = *other_ptr;
493
      else
494
        elem_data = (char *) elem_ptr;
495
 
496
      if (prop->is_list == PLY_LIST) {  /* list */
497
        item = elem_data + prop->count_offset;
498
        get_stored_item ((void *) item, prop->count_internal,
499
                         &int_val, &uint_val, &double_val);
500
        write_ascii_item (fp, int_val, uint_val, double_val,
501
                          prop->count_external);
502
        list_count = uint_val;
503
        item_ptr = (char **) (elem_data + prop->offset);
504
        item = item_ptr[0];
505
        item_size = ply_type_size[prop->internal_type];
506
        for (k = 0; k < list_count; k++) {
507
          get_stored_item ((void *) item, prop->internal_type,
508
                           &int_val, &uint_val, &double_val);
509
          write_ascii_item (fp, int_val, uint_val, double_val,
510
                            prop->external_type);
511
          item += item_size;
512
        }
513
      }
514
      else if (prop->is_list == PLY_STRING) {  /* string */
515
	char **str;
516
        item = elem_data + prop->offset;
517
	str = (char **) item;
518
	fprintf (fp, "\"%s\"", *str);
519
      }
520
      else {                                  /* scalar */
521
        item = elem_data + prop->offset;
522
        get_stored_item ((void *) item, prop->internal_type,
523
                         &int_val, &uint_val, &double_val);
524
        write_ascii_item (fp, int_val, uint_val, double_val,
525
                          prop->external_type);
526
      }
527
    }
528
 
529
    fprintf (fp, "\n");
530
  }
531
  else {
532
 
533
    /* write a binary file */
534
 
535
    /* write out each property of the element */
536
    for (j = 0; j < elem->nprops; j++) {
537
      prop = elem->props[j];
538
      if (elem->store_prop[j] == OTHER_PROP)
539
        elem_data = *other_ptr;
540
      else
541
        elem_data = (char *) elem_ptr;
542
      if (prop->is_list == PLY_LIST) {   /* list */
543
        item = elem_data + prop->count_offset;
544
        item_size = ply_type_size[prop->count_internal];
545
        get_stored_item ((void *) item, prop->count_internal,
546
                         &int_val, &uint_val, &double_val);
547
        write_binary_item (fp, int_val, uint_val, double_val,
548
                           prop->count_external);
549
        list_count = uint_val;
550
        item_ptr = (char **) (elem_data + prop->offset);
551
        item = item_ptr[0];
552
        item_size = ply_type_size[prop->internal_type];
553
        for (k = 0; k < list_count; k++) {
554
          get_stored_item ((void *) item, prop->internal_type,
555
                           &int_val, &uint_val, &double_val);
556
          write_binary_item (fp, int_val, uint_val, double_val,
557
                             prop->external_type);
558
          item += item_size;
559
        }
560
      }
561
      else if (prop->is_list == PLY_STRING) {   /* string */
562
	int len;
563
	char **str;
564
        item = elem_data + prop->offset;
565
	str = (char **) item;
566
 
567
	/* write the length */
568
	len = strlen(*str) + 1;
569
	fwrite (&len, sizeof(int), 1, fp);
570
 
571
	/* write the string, including the null character */
572
	fwrite (*str, len, 1, fp);
573
      }
574
      else {                   /* scalar */
575
        item = elem_data + prop->offset;
576
        item_size = ply_type_size[prop->internal_type];
577
        get_stored_item ((void *) item, prop->internal_type,
578
                         &int_val, &uint_val, &double_val);
579
        write_binary_item (fp, int_val, uint_val, double_val,
580
                           prop->external_type);
581
      }
582
    }
583
 
584
  }
585
}
586
 
587
 
588
 
589
 
590
 
591
 
592
/*************/
593
/*  Reading  */
594
/*************/
595
 
596
 
597
 
598
/******************************************************************************
599
Given a file pointer, get ready to read PLY data from the file.
600
 
601
Entry:
602
  fp - the given file pointer
603
 
604
Exit:
605
  nelems     - number of elements in object
606
  elem_names - list of element names
607
  returns a pointer to a PlyFile, used to refer to this file, or NULL if error
608
******************************************************************************/
609
 
610
PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
611
{
612
  int i,j;
613
  PlyFile *plyfile;
614
  int nwords;
615
  char **words;
616
  int found_format = 0;
617
  char **elist;
618
  PlyElement *elem;
619
  char *orig_line;
620
 
621
  /* check for NULL file pointer */
622
  if (fp == NULL)
623
    return (NULL);
624
 
625
  /* create record for this object */
626
 
627
  plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
628
  plyfile->num_elem_types = 0;
629
  plyfile->comments = NULL;
630
  plyfile->num_comments = 0;
631
  plyfile->obj_info = NULL;
632
  plyfile->num_obj_info = 0;
633
  plyfile->fp = fp;
634
  plyfile->other_elems = NULL;
635
  plyfile->rule_list = NULL;
636
 
637
  /* read and parse the file's header */
638
 
639
  words = get_words (plyfile->fp, &nwords, &orig_line);
640
  if (!words || !equal_strings (words[0], "ply"))
641
    return (NULL);
642
 
643
  while (words) {
644
 
645
    /* parse words */
646
 
647
    if (equal_strings (words[0], "format")) {
648
      if (nwords != 3)
649
        return (NULL);
650
      if (equal_strings (words[1], "ascii"))
651
        plyfile->file_type = PLY_ASCII;
652
      else if (equal_strings (words[1], "binary_big_endian"))
653
        plyfile->file_type = PLY_BINARY_BE;
654
      else if (equal_strings (words[1], "binary_little_endian"))
655
        plyfile->file_type = PLY_BINARY_LE;
656
      else
657
        return (NULL);
658
      plyfile->version = atof (words[2]);
659
      found_format = 1;
660
    }
661
    else if (equal_strings (words[0], "element"))
662
      add_element (plyfile, words, nwords);
663
    else if (equal_strings (words[0], "property"))
664
      add_property (plyfile, words, nwords);
665
    else if (equal_strings (words[0], "comment"))
666
      add_comment (plyfile, orig_line);
667
    else if (equal_strings (words[0], "obj_info"))
668
      add_obj_info (plyfile, orig_line);
669
    else if (equal_strings (words[0], "end_header"))
670
      break;
671
 
672
    /* free up words space */
673
    free (words);
674
 
675
    words = get_words (plyfile->fp, &nwords, &orig_line);
676
  }
677
 
678
  /* create tags for each property of each element, to be used */
679
  /* later to say whether or not to store each property for the user */
680
 
681
  for (i = 0; i < plyfile->num_elem_types; i++) {
682
    elem = plyfile->elems[i];
683
    elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
684
    for (j = 0; j < elem->nprops; j++)
685
      elem->store_prop[j] = DONT_STORE_PROP;
686
    elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
687
  }
688
 
689
  /* set return values about the elements */
690
 
691
  elist = (char **) myalloc (sizeof (char *) * plyfile->num_elem_types);
692
  for (i = 0; i < plyfile->num_elem_types; i++)
693
    elist[i] = strdup (plyfile->elems[i]->name);
694
 
695
  *elem_names = elist;
696
  *nelems = plyfile->num_elem_types;
697
 
698
  /* return a pointer to the file's information */
699
 
700
  return (plyfile);
701
}
702
 
703
 
704
/******************************************************************************
705
Open a polygon file for reading.
706
 
707
Entry:
708
  filename - name of file to read from
709
 
710
Exit:
711
  nelems     - number of elements in object
712
  elem_names - list of element names
713
  file_type  - file type, either ascii or binary
714
  version    - version number of PLY file
715
  returns a file identifier, used to refer to this file, or NULL if error
716
******************************************************************************/
717
 
718
PlyFile *ply_open_for_reading(
719
  char *filename,
720
  int *nelems,
721
  char ***elem_names,
722
  int *file_type,
723
  float *version
724
)
725
{
726
  FILE *fp;
727
  PlyFile *plyfile;
728
  char *name;
729
 
730
  /* tack on the extension .ply, if necessary */
731
 
732
  name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
733
  strcpy (name, filename);
734
  if (strlen (name) < 4 ||
735
      strcmp (name + strlen (name) - 4, ".ply") != 0)
736
      strcat (name, ".ply");
737
 
738
  /* open the file for reading */
739
 
740
  fp = fopen (name, "r");
741
  if (fp == NULL)
742
    return (NULL);
743
 
744
  /* create the PlyFile data structure */
745
 
746
  plyfile = ply_read (fp, nelems, elem_names);
747
 
748
  /* determine the file type and version */
749
 
750
  *file_type = plyfile->file_type;
751
  *version = plyfile->version;
752
 
753
  /* return a pointer to the file's information */
754
 
755
  return (plyfile);
756
}
757
 
758
 
759
/******************************************************************************
760
Get information about a particular element.
761
 
762
Entry:
763
  plyfile   - file identifier
764
  elem_name - name of element to get information about
765
 
766
Exit:
767
  nelems   - number of elements of this type in the file
768
  nprops   - number of properties
769
  returns a list of properties, or NULL if the file doesn't contain that elem
770
******************************************************************************/
771
 
772
PlyProperty **get_element_description_ply(
773
  PlyFile *plyfile,
774
  char *elem_name,
775
  int *nelems,
776
  int *nprops
777
)
778
{
779
  int i;
780
  PlyElement *elem;
781
  PlyProperty *prop;
782
  PlyProperty **prop_list;
783
 
784
  /* find information about the element */
785
  elem = find_element (plyfile, elem_name);
786
  if (elem == NULL)
787
    return (NULL);
788
 
789
  *nelems = elem->num;
790
  *nprops = elem->nprops;
791
 
792
  /* make a copy of the element's property list */
793
  prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
794
  for (i = 0; i < elem->nprops; i++) {
795
    prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
796
    copy_property (prop, elem->props[i]);
797
    prop_list[i] = prop;
798
  }
799
 
800
  /* return this duplicate property list */
801
  return (prop_list);
802
}
803
 
804
 
805
/******************************************************************************
806
Specify which properties of an element are to be returned.  This should be
807
called before a call to the routine get_element_ply().
808
 
809
Entry:
810
  plyfile   - file identifier
811
  elem_name - which element we're talking about
812
  nprops    - number of properties
813
  prop_list - list of properties
814
******************************************************************************/
815
 
816
void get_element_setup_ply(
817
  PlyFile *plyfile,
818
  char *elem_name,
819
  int nprops,
820
  PlyProperty *prop_list
821
)
822
{
823
  int i;
824
  PlyElement *elem;
825
  PlyProperty *prop;
826
  int index;
827
 
828
  /* find information about the element */
829
  elem = find_element (plyfile, elem_name);
830
  plyfile->which_elem = elem;
831
 
832
  /* deposit the property information into the element's description */
833
  for (i = 0; i < nprops; i++) {
834
 
835
    /* look for actual property */
836
    prop = find_property (elem, prop_list[i].name, &index);
837
    if (prop == NULL) {
838
      fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
839
               prop_list[i].name, elem_name);
840
      continue;
841
    }
842
 
843
    /* store its description */
844
    prop->internal_type = prop_list[i].internal_type;
845
    prop->offset = prop_list[i].offset;
846
    prop->count_internal = prop_list[i].count_internal;
847
    prop->count_offset = prop_list[i].count_offset;
848
 
849
    /* specify that the user wants this property */
850
    elem->store_prop[index] = STORE_PROP;
851
  }
852
}
853
 
854
 
855
/******************************************************************************
856
Specify a property of an element that is to be returned.  This should be
857
called (usually multiple times) before a call to the routine ply_get_element().
858
This routine should be used in preference to the less flexible old routine
859
called ply_get_element_setup().
860
 
861
Entry:
862
  plyfile   - file identifier
863
  elem_name - which element we're talking about
864
  prop      - property to add to those that will be returned
865
******************************************************************************/
866
 
867
void ply_get_property(
868
  PlyFile *plyfile,
869
  char *elem_name,
870
  PlyProperty *prop
871
)
872
{
873
  PlyElement *elem;
874
  PlyProperty *prop_ptr;
875
  int index;
876
 
877
  /* find information about the element */
878
  elem = find_element (plyfile, elem_name);
879
  plyfile->which_elem = elem;
880
 
881
  /* deposit the property information into the element's description */
882
 
883
  prop_ptr = find_property (elem, prop->name, &index);
884
  if (prop_ptr == NULL) {
885
    fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
886
             prop->name, elem_name);
887
    return;
888
  }
889
  prop_ptr->internal_type  = prop->internal_type;
890
  prop_ptr->offset         = prop->offset;
891
  prop_ptr->count_internal = prop->count_internal;
892
  prop_ptr->count_offset   = prop->count_offset;
893
 
894
  /* specify that the user wants this property */
895
  elem->store_prop[index] = STORE_PROP;
896
}
897
 
898
 
899
/******************************************************************************
900
Read one element from the file.  This routine assumes that we're reading
901
the type of element specified in the last call to the routine
902
ply_get_element_setup().
903
 
904
Entry:
905
  plyfile  - file identifier
906
  elem_ptr - pointer to location where the element information should be put
907
******************************************************************************/
908
 
909
void ply_get_element(PlyFile *plyfile, void *elem_ptr)
910
{
911
  if (plyfile->file_type == PLY_ASCII)
912
    ascii_get_element (plyfile, (char *) elem_ptr);
913
  else
914
    binary_get_element (plyfile, (char *) elem_ptr);
915
}
916
 
917
 
918
/******************************************************************************
919
Extract the comments from the header information of a PLY file.
920
 
921
Entry:
922
  plyfile - file identifier
923
 
924
Exit:
925
  num_comments - number of comments returned
926
  returns a pointer to a list of comments
927
******************************************************************************/
928
 
929
char **get_comments_ply(PlyFile *plyfile, int *num_comments)
930
{
931
  *num_comments = plyfile->num_comments;
932
  return (plyfile->comments);
933
}
934
 
935
 
936
/******************************************************************************
937
Extract the object information (arbitrary text) from the header information
938
of a PLY file.
939
 
940
Entry:
941
  plyfile - file identifier
942
 
943
Exit:
944
  num_obj_info - number of lines of text information returned
945
  returns a pointer to a list of object info lines
946
******************************************************************************/
947
 
948
char **get_obj_info_ply(PlyFile *plyfile, int *num_obj_info)
949
{
950
  *num_obj_info = plyfile->num_obj_info;
951
  return (plyfile->obj_info);
952
}
953
 
954
 
955
/******************************************************************************
956
Make ready for "other" properties of an element-- those properties that
957
the user has not explicitly asked for, but that are to be stashed away
958
in a special structure to be carried along with the element's other
959
information.
960
 
961
Entry:
962
  plyfile - file identifier
963
  elem    - element for which we want to save away other properties
964
******************************************************************************/
965
 
966
void setup_other_props(PlyFile *plyfile, PlyElement *elem)
967
{
968
  int i;
969
  PlyProperty *prop;
970
  int size = 0;
971
  int type_size;
972
 
973
  /* Examine each property in decreasing order of size. */
974
  /* We do this so that all data types will be aligned by */
975
  /* word, half-word, or whatever within the structure. */
976
 
977
  for (type_size = 8; type_size > 0; type_size /= 2) {
978
 
979
    /* add up the space taken by each property, and save this information */
980
    /* away in the property descriptor */
981
 
982
    for (i = 0; i < elem->nprops; i++) {
983
 
984
      /* don't bother with properties we've been asked to store explicitly */
985
      if (elem->store_prop[i])
986
        continue;
987
 
988
      prop = elem->props[i];
989
 
990
      /* internal types will be same as external */
991
      prop->internal_type = prop->external_type;
992
      prop->count_internal = prop->count_external;
993
 
994
      /* list case */
995
      if (prop->is_list == PLY_LIST) {
996
 
997
        /* pointer to list */
998
        if (type_size == sizeof (void *)) {
999
          prop->offset = size;
1000
          size += sizeof (void *);    /* always use size of a pointer here */
1001
        }
1002
 
1003
        /* count of number of list elements */
1004
        if (type_size == ply_type_size[prop->count_external]) {
1005
          prop->count_offset = size;
1006
          size += ply_type_size[prop->count_external];
1007
        }
1008
      }
1009
      /* string */
1010
      else if (prop->is_list == PLY_STRING) {
1011
        /* pointer to string */
1012
        if (type_size == sizeof (char *)) {
1013
          prop->offset = size;
1014
          size += sizeof (char *);
1015
        }
1016
      }
1017
      /* scalar */
1018
      else if (type_size == ply_type_size[prop->external_type]) {
1019
        prop->offset = size;
1020
        size += ply_type_size[prop->external_type];
1021
      }
1022
    }
1023
 
1024
  }
1025
 
1026
  /* save the size for the other_props structure */
1027
  elem->other_size = size;
1028
}
1029
 
1030
 
1031
/******************************************************************************
1032
Specify that we want the "other" properties of an element to be tucked
1033
away within the user's structure.
1034
 
1035
Entry:
1036
  plyfile - file identifier
1037
  elem    - the element that we want to store other_props in
1038
  offset  - offset to where other_props will be stored inside user's structure
1039
 
1040
Exit:
1041
  returns pointer to structure containing description of other_props
1042
******************************************************************************/
1043
 
1044
static PlyOtherProp *get_other_properties(
1045
  PlyFile *plyfile,
1046
  PlyElement *elem,
1047
  int offset
1048
)
1049
{
1050
  int i;
1051
  PlyOtherProp *other;
1052
  PlyProperty *prop;
1053
  int nprops;
1054
 
1055
  /* remember that this is the "current" element */
1056
  plyfile->which_elem = elem;
1057
 
1058
  /* save the offset to where to store the other_props */
1059
  elem->other_offset = offset;
1060
 
1061
  /* place the appropriate pointers, etc. in the element's property list */
1062
  setup_other_props (plyfile, elem);
1063
 
1064
  /* create structure for describing other_props */
1065
  other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
1066
  other->name = strdup (elem->name);
1067
#if 0
1068
  if (elem->other_offset == NO_OTHER_PROPS) {
1069
    other->size = 0;
1070
    other->props = NULL;
1071
    other->nprops = 0;
1072
    return (other);
1073
  }
1074
#endif
1075
  other->size = elem->other_size;
1076
  other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
1077
 
1078
  /* save descriptions of each "other" property */
1079
  nprops = 0;
1080
  for (i = 0; i < elem->nprops; i++) {
1081
    if (elem->store_prop[i])
1082
      continue;
1083
    prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
1084
    copy_property (prop, elem->props[i]);
1085
    other->props[nprops] = prop;
1086
    nprops++;
1087
  }
1088
  other->nprops = nprops;
1089
 
1090
  /* set other_offset pointer appropriately if there are NO other properties */
1091
  if (other->nprops == 0) {
1092
    elem->other_offset = NO_OTHER_PROPS;
1093
  }
1094
 
1095
  /* return structure */
1096
  return (other);
1097
}
1098
 
1099
 
1100
/******************************************************************************
1101
Specify that we want the "other" properties of an element to be tucked
1102
away within the user's structure.  The user needn't be concerned for how
1103
these properties are stored.
1104
 
1105
Entry:
1106
  plyfile   - file identifier
1107
  elem_name - name of element that we want to store other_props in
1108
  offset    - offset to where other_props will be stored inside user's structure
1109
 
1110
Exit:
1111
  returns pointer to structure containing description of other_props
1112
******************************************************************************/
1113
 
1114
PlyOtherProp *ply_get_other_properties(
1115
  PlyFile *plyfile,
1116
  char *elem_name,
1117
  int offset
1118
)
1119
{
1120
  PlyElement *elem;
1121
  PlyOtherProp *other;
1122
 
1123
  /* find information about the element */
1124
  elem = find_element (plyfile, elem_name);
1125
  if (elem == NULL) {
1126
    fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
1127
             elem_name);
1128
    return (NULL);
1129
  }
1130
 
1131
  other = get_other_properties (plyfile, elem, offset);
1132
  return (other);
1133
}
1134
 
1135
 
1136
 
1137
 
1138
/*************************/
1139
/*  Other Element Stuff  */
1140
/*************************/
1141
 
1142
 
1143
 
1144
 
1145
 
1146
/******************************************************************************
1147
Grab all the data for the current element that a user does not want to
1148
explicitly read in.  Stores this in the PLY object's data structure.
1149
 
1150
Entry:
1151
  plyfile - pointer to file
1152
 
1153
Exit:
1154
  returns pointer to ALL the "other" element data for this PLY file
1155
******************************************************************************/
1156
 
1157
PlyOtherElems *get_other_element_ply (PlyFile *plyfile)
1158
{
1159
  int i;
1160
  PlyElement *elem;
1161
  char *elem_name;
1162
  int elem_count;
1163
  PlyOtherElems *other_elems;
1164
  OtherElem *other;
1165
 
1166
  elem = plyfile->which_elem;
1167
  elem_name = elem->name;
1168
  elem_count = elem->num;
1169
 
1170
  /* create room for the new "other" element, initializing the */
1171
  /* other data structure if necessary */
1172
 
1173
  if (plyfile->other_elems == NULL) {
1174
    plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
1175
    other_elems = plyfile->other_elems;
1176
    other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
1177
    other = &(other_elems->other_list[0]);
1178
    other_elems->num_elems = 1;
1179
  }
1180
  else {
1181
    other_elems = plyfile->other_elems;
1182
    other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
1183
                              sizeof (OtherElem) * other_elems->num_elems + 1);
1184
    other = &(other_elems->other_list[other_elems->num_elems]);
1185
    other_elems->num_elems++;
1186
  }
1187
 
1188
  /* count of element instances in file */
1189
  other->elem_count = elem_count;
1190
 
1191
  /* save name of element */
1192
  other->elem_name = strdup (elem_name);
1193
 
1194
  /* create a list to hold all the current elements */
1195
  other->other_data = (OtherData **)
1196
                  malloc (sizeof (OtherData *) * other->elem_count);
1197
 
1198
  /* set up for getting elements */
1199
  other->other_props = ply_get_other_properties (plyfile, elem_name,
1200
                         offsetof(OtherData,other_props));
1201
 
1202
  /* grab all these elements */
1203
  for (i = 0; i < other->elem_count; i++) {
1204
    /* grab and element from the file */
1205
    other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
1206
    ply_get_element (plyfile, (void *) other->other_data[i]);
1207
  }
1208
 
1209
  /* return pointer to the other elements data */
1210
  return (other_elems);
1211
}
1212
 
1213
 
1214
/******************************************************************************
1215
Write out the "other" elements specified for this PLY file.
1216
 
1217
Entry:
1218
  plyfile - pointer to PLY file to write out other elements for
1219
******************************************************************************/
1220
 
1221
void put_other_elements_ply (PlyFile *plyfile)
1222
{
1223
  int i,j;
1224
  OtherElem *other;
1225
 
1226
  /* make sure we have other elements to write */
1227
  if (plyfile->other_elems == NULL)
1228
    return;
1229
 
1230
  /* write out the data for each "other" element */
1231
 
1232
  for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1233
 
1234
    other = &(plyfile->other_elems->other_list[i]);
1235
    put_element_setup_ply (plyfile, other->elem_name);
1236
 
1237
    /* write out each instance of the current element */
1238
    for (j = 0; j < other->elem_count; j++)
1239
      put_element_ply (plyfile, (void *) other->other_data[j]);
1240
  }
1241
}
1242
 
1243
 
1244
/******************************************************************************
1245
Free up storage used by an "other" elements data structure.
1246
 
1247
Entry:
1248
  other_elems - data structure to free up
1249
******************************************************************************/
1250
 
1251
void free_other_elements_ply (PlyOtherElems *other_elems)
1252
{
1253
 
1254
}
1255
 
1256
 
1257
 
1258
/*******************/
1259
/*  Miscellaneous  */
1260
/*******************/
1261
 
1262
 
1263
 
1264
/******************************************************************************
1265
Close a PLY file.
1266
 
1267
Entry:
1268
  plyfile - identifier of file to close
1269
******************************************************************************/
1270
 
1271
void ply_close(PlyFile *plyfile)
1272
{
1273
  fclose (plyfile->fp);
1274
 
1275
  /* free up memory associated with the PLY file */
1276
  free (plyfile);
1277
}
1278
 
1279
 
1280
/******************************************************************************
1281
Get version number and file type of a PlyFile.
1282
 
1283
Entry:
1284
  ply - pointer to PLY file
1285
 
1286
Exit:
1287
  version - version of the file
1288
  file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1289
******************************************************************************/
1290
 
1291
void get_info_ply(PlyFile *ply, float *version, int *file_type)
1292
{
1293
  if (ply == NULL)
1294
    return;
1295
 
1296
  *version = ply->version;
1297
  *file_type = ply->file_type;
1298
}
1299
 
1300
 
1301
/******************************************************************************
1302
Compare two strings.  Returns 1 if they are the same, 0 if not.
1303
******************************************************************************/
1304
 
1305
int equal_strings(char *s1, char *s2)
1306
{
1307
  int i;
1308
 
1309
  while (*s1 && *s2)
1310
    if (*s1++ != *s2++)
1311
      return (0);
1312
 
1313
  if (*s1 != *s2)
1314
    return (0);
1315
  else
1316
    return (1);
1317
}
1318
 
1319
 
1320
/******************************************************************************
1321
Re-create the command line that was used to invoke this program.
1322
 
1323
Entry:
1324
  argc - number of words in argv
1325
  argv - array of words in command line
1326
******************************************************************************/
1327
 
1328
char *recreate_command_line (int argc, char *argv[])
1329
{
1330
  int i;
1331
  char *line;
1332
  int len = 0;
1333
 
1334
  /* count total number of characters needed, including separating spaces */
1335
  for (i = 0; i < argc; i++)
1336
    len += strlen(argv[i]) + 1;
1337
 
1338
  /* create empty line */
1339
  line = (char *) malloc (sizeof(char) * len);
1340
  line[0] = '\0';
1341
 
1342
  /* repeatedly append argv */
1343
  for (i = 0; i < argc; i++) {
1344
    strcat (line, argv[i]);
1345
    if (i != argc - 1)
1346
      strcat (line, " ");
1347
  }
1348
 
1349
  return (line);
1350
}
1351
 
1352
 
1353
/******************************************************************************
1354
Find an element from the element list of a given PLY object.
1355
 
1356
Entry:
1357
  plyfile - file id for PLY file
1358
  element - name of element we're looking for
1359
 
1360
Exit:
1361
  returns the element, or NULL if not found
1362
******************************************************************************/
1363
 
1364
PlyElement *find_element(PlyFile *plyfile, char *element)
1365
{
1366
  int i;
1367
 
1368
  for (i = 0; i < plyfile->num_elem_types; i++)
1369
    if (equal_strings (element, plyfile->elems[i]->name))
1370
      return (plyfile->elems[i]);
1371
 
1372
  return (NULL);
1373
}
1374
 
1375
 
1376
/******************************************************************************
1377
Find a property in the list of properties of a given element.
1378
 
1379
Entry:
1380
  elem      - pointer to element in which we want to find the property
1381
  prop_name - name of property to find
1382
 
1383
Exit:
1384
  index - index to position in list
1385
  returns a pointer to the property, or NULL if not found
1386
******************************************************************************/
1387
 
1388
PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index)
1389
{
1390
  int i;
1391
 
1392
  for (i = 0; i < elem->nprops; i++)
1393
    if (equal_strings (prop_name, elem->props[i]->name)) {
1394
      *index = i;
1395
      return (elem->props[i]);
1396
    }
1397
 
1398
  *index = -1;
1399
  return (NULL);
1400
}
1401
 
1402
 
1403
/******************************************************************************
1404
Read an element from an ascii file.
1405
 
1406
Entry:
1407
  plyfile  - file identifier
1408
  elem_ptr - pointer to element
1409
******************************************************************************/
1410
 
1411
void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1412
{
1413
  int i,j,k;
1414
  PlyElement *elem;
1415
  PlyProperty *prop;
1416
  char **words;
1417
  int nwords;
1418
  int which_word;
1419
  FILE *fp = plyfile->fp;
1420
  char *elem_data,*item;
1421
  char *item_ptr;
1422
  int item_size;
1423
  int int_val;
1424
  unsigned int uint_val;
1425
  double double_val;
1426
  int list_count;
1427
  int store_it;
1428
  char **store_array;
1429
  char *orig_line;
1430
  char *other_data;
1431
  int other_flag;
1432
 
1433
  /* the kind of element we're reading currently */
1434
  elem = plyfile->which_elem;
1435
 
1436
  /* do we need to setup for other_props? */
1437
 
1438
  if (elem->other_offset != NO_OTHER_PROPS) {
1439
    char **ptr;
1440
    other_flag = 1;
1441
    /* make room for other_props */
1442
    other_data = (char *) myalloc (elem->other_size);
1443
    /* store pointer in user's structure to the other_props */
1444
    ptr = (char **) (elem_ptr + elem->other_offset);
1445
    *ptr = other_data;
1446
  }
1447
  else
1448
    other_flag = 0;
1449
 
1450
  /* read in the element */
1451
 
1452
  words = get_words (plyfile->fp, &nwords, &orig_line);
1453
  if (words == NULL) {
1454
    fprintf (stderr, "ply_get_element: unexpected end of file\n");
1455
    exit (-1);
1456
  }
1457
 
1458
  which_word = 0;
1459
 
1460
  for (j = 0; j < elem->nprops; j++) {
1461
 
1462
    prop = elem->props[j];
1463
    store_it = (elem->store_prop[j] | other_flag);
1464
 
1465
    /* store either in the user's structure or in other_props */
1466
    if (elem->store_prop[j])
1467
      elem_data = elem_ptr;
1468
    else
1469
      elem_data = other_data;
1470
 
1471
    if (prop->is_list == PLY_LIST) {       /* a list */
1472
 
1473
      /* get and store the number of items in the list */
1474
      get_ascii_item (words[which_word++], prop->count_external,
1475
                      &int_val, &uint_val, &double_val);
1476
      if (store_it) {
1477
        item = elem_data + prop->count_offset;
1478
        store_item(item, prop->count_internal, int_val, uint_val, double_val);
1479
      }
1480
 
1481
      /* allocate space for an array of items and store a ptr to the array */
1482
      list_count = int_val;
1483
      item_size = ply_type_size[prop->internal_type];
1484
      store_array = (char **) (elem_data + prop->offset);
1485
 
1486
      if (list_count == 0) {
1487
        if (store_it)
1488
          *store_array = NULL;
1489
      }
1490
      else {
1491
        if (store_it) {
1492
          item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1493
          item = item_ptr;
1494
          *store_array = item_ptr;
1495
        }
1496
 
1497
        /* read items and store them into the array */
1498
        for (k = 0; k < list_count; k++) {
1499
          get_ascii_item (words[which_word++], prop->external_type,
1500
                          &int_val, &uint_val, &double_val);
1501
          if (store_it) {
1502
            store_item (item, prop->internal_type,
1503
                        int_val, uint_val, double_val);
1504
            item += item_size;
1505
          }
1506
        }
1507
      }
1508
 
1509
    }
1510
    else if (prop->is_list == PLY_STRING) {   /* a string */
1511
      if (store_it) {
1512
	char *str;
1513
	char **str_ptr;
1514
	str = strdup (words[which_word++]);
1515
        item = elem_data + prop->offset;
1516
	str_ptr = (char **) item;
1517
	*str_ptr = str;
1518
      }
1519
      else {
1520
        which_word++;
1521
      }
1522
    }
1523
    else {                     /* a scalar */
1524
      get_ascii_item (words[which_word++], prop->external_type,
1525
                      &int_val, &uint_val, &double_val);
1526
      if (store_it) {
1527
        item = elem_data + prop->offset;
1528
        store_item (item, prop->internal_type, int_val, uint_val, double_val);
1529
      }
1530
    }
1531
 
1532
  }
1533
 
1534
  free (words);
1535
}
1536
 
1537
 
1538
/******************************************************************************
1539
Read an element from a binary file.
1540
 
1541
Entry:
1542
  plyfile  - file identifier
1543
  elem_ptr - pointer to an element
1544
******************************************************************************/
1545
 
1546
void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1547
{
1548
  int i,j,k;
1549
  PlyElement *elem;
1550
  PlyProperty *prop;
1551
  FILE *fp = plyfile->fp;
1552
  char *elem_data;
1553
  char *item;
1554
  char *item_ptr;
1555
  int item_size;
1556
  int int_val;
1557
  unsigned int uint_val;
1558
  double double_val;
1559
  int list_count;
1560
  int store_it;
1561
  char **store_array;
1562
  char *other_data;
1563
  int other_flag;
1564
 
1565
  /* the kind of element we're reading currently */
1566
  elem = plyfile->which_elem;
1567
 
1568
  /* do we need to setup for other_props? */
1569
 
1570
  if (elem->other_offset != NO_OTHER_PROPS) {
1571
    char **ptr;
1572
    other_flag = 1;
1573
    /* make room for other_props */
1574
    other_data = (char *) myalloc (elem->other_size);
1575
    /* store pointer in user's structure to the other_props */
1576
    ptr = (char **) (elem_ptr + elem->other_offset);
1577
    *ptr = other_data;
1578
  }
1579
  else
1580
    other_flag = 0;
1581
 
1582
  /* read in a number of elements */
1583
 
1584
  for (j = 0; j < elem->nprops; j++) {
1585
 
1586
    prop = elem->props[j];
1587
    store_it = (elem->store_prop[j] | other_flag);
1588
 
1589
    /* store either in the user's structure or in other_props */
1590
    if (elem->store_prop[j])
1591
      elem_data = elem_ptr;
1592
    else
1593
      elem_data = other_data;
1594
 
1595
    if (prop->is_list == PLY_LIST) {          /* list */
1596
 
1597
      /* get and store the number of items in the list */
1598
      get_binary_item (fp, prop->count_external,
1599
                      &int_val, &uint_val, &double_val);
1600
      if (store_it) {
1601
        item = elem_data + prop->count_offset;
1602
        store_item(item, prop->count_internal, int_val, uint_val, double_val);
1603
      }
1604
 
1605
      /* allocate space for an array of items and store a ptr to the array */
1606
      list_count = int_val;
1607
      item_size = ply_type_size[prop->internal_type];
1608
      store_array = (char **) (elem_data + prop->offset);
1609
      if (list_count == 0) {
1610
        if (store_it)
1611
          *store_array = NULL;
1612
      }
1613
      else {
1614
        if (store_it) {
1615
          item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1616
          item = item_ptr;
1617
          *store_array = item_ptr;
1618
        }
1619
 
1620
        /* read items and store them into the array */
1621
        for (k = 0; k < list_count; k++) {
1622
          get_binary_item (fp, prop->external_type,
1623
                          &int_val, &uint_val, &double_val);
1624
          if (store_it) {
1625
            store_item (item, prop->internal_type,
1626
                        int_val, uint_val, double_val);
1627
            item += item_size;
1628
          }
1629
        }
1630
      }
1631
 
1632
    }
1633
    else if (prop->is_list == PLY_STRING) {     /* string */
1634
      int len;
1635
      char *str;
1636
      fread (&len, sizeof(int), 1, fp);
1637
      str = (char *) myalloc (len);
1638
      fread (str, len, 1, fp);
1639
      if (store_it) {
1640
	char **str_ptr;
1641
        item = elem_data + prop->offset;
1642
	str_ptr = (char **) item;
1643
	*str_ptr = str;
1644
      }
1645
    }
1646
    else {                                      /* scalar */
1647
      get_binary_item (fp, prop->external_type,
1648
                      &int_val, &uint_val, &double_val);
1649
      if (store_it) {
1650
        item = elem_data + prop->offset;
1651
        store_item (item, prop->internal_type, int_val, uint_val, double_val);
1652
      }
1653
    }
1654
 
1655
  }
1656
}
1657
 
1658
 
1659
/******************************************************************************
1660
Write to a file the word that represents a PLY data type.
1661
 
1662
Entry:
1663
  fp   - file pointer
1664
  code - code for type
1665
******************************************************************************/
1666
 
1667
void write_scalar_type (FILE *fp, int code)
1668
{
1669
  /* make sure this is a valid code */
1670
 
1671
  if (code <= StartType || code >= EndType) {
1672
    fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
1673
    exit (-1);
1674
  }
1675
 
1676
  /* write the code to a file */
1677
 
1678
  fprintf (fp, "%s", type_names[code]);
1679
}
1680
 
1681
 
1682
/******************************************************************************
1683
Get a text line from a file and break it up into words.
1684
 
1685
IMPORTANT: The calling routine should call "free" on the returned pointer once
1686
finished with it.
1687
 
1688
Entry:
1689
  fp - file to read from
1690
 
1691
Exit:
1692
  nwords    - number of words returned
1693
  orig_line - the original line of characters
1694
  returns a list of words from the line, or NULL if end-of-file
1695
******************************************************************************/
1696
 
1697
char **get_words(FILE *fp, int *nwords, char **orig_line)
1698
{
1699
#define BIG_STRING 4096
1700
  int i,j;
1701
  static char str[BIG_STRING];
1702
  static char str_copy[BIG_STRING];
1703
  char **words;
1704
  int max_words = 10;
1705
  int num_words = 0;
1706
  char *ptr,*ptr2;
1707
  char *result;
1708
 
1709
  words = (char **) myalloc (sizeof (char *) * max_words);
1710
 
1711
  /* read in a line */
1712
  result = fgets (str, BIG_STRING, fp);
1713
  if (result == NULL) {
1714
    *nwords = 0;
1715
    *orig_line = NULL;
1716
    return (NULL);
1717
  }
1718
 
1719
  /* convert line-feed and tabs into spaces */
1720
  /* (this guarentees that there will be a space before the */
1721
  /*  null character at the end of the string) */
1722
 
1723
  str[BIG_STRING-2] = ' ';
1724
  str[BIG_STRING-1] = '\0';
1725
 
1726
  for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1727
    *ptr2 = *ptr;
1728
    if (*ptr == '\t') {
1729
      *ptr = ' ';
1730
      *ptr2 = ' ';
1731
    }
1732
    else if (*ptr == '\n') {
1733
      *ptr = ' ';
1734
      *ptr2 = '\0';
1735
      break;
1736
    }
1737
  }
1738
 
1739
  /* find the words in the line */
1740
 
1741
  ptr = str;
1742
  while (*ptr != '\0') {
1743
 
1744
    /* jump over leading spaces */
1745
    while (*ptr == ' ')
1746
      ptr++;
1747
 
1748
    /* break if we reach the end */
1749
    if (*ptr == '\0')
1750
      break;
1751
 
1752
    /* allocate more room for words if necessary */
1753
    if (num_words >= max_words) {
1754
      max_words += 10;
1755
      words = (char **) realloc (words, sizeof (char *) * max_words);
1756
    }
1757
 
1758
    if (*ptr == '\"') {  /* a quote indidicates that we have a string */
1759
 
1760
      /* skip over leading quote */
1761
      ptr++;
1762
 
1763
      /* save pointer to beginning of word */
1764
      words[num_words++] = ptr;
1765
 
1766
      /* find trailing quote or end of line */
1767
      while (*ptr != '\"' && *ptr != '\0')
1768
        ptr++;
1769
 
1770
      /* replace quote with a null character to mark the end of the word */
1771
      /* if we are not already at the end of the line */
1772
      if (*ptr != '\0')
1773
	*ptr++ = '\0';
1774
    }
1775
    else {               /* non-string */
1776
 
1777
      /* save pointer to beginning of word */
1778
      words[num_words++] = ptr;
1779
 
1780
      /* jump over non-spaces */
1781
      while (*ptr != ' ')
1782
	ptr++;
1783
 
1784
      /* place a null character here to mark the end of the word */
1785
      *ptr++ = '\0';
1786
    }
1787
  }
1788
 
1789
  /* return the list of words */
1790
  *nwords = num_words;
1791
  *orig_line = str_copy;
1792
  return (words);
1793
}
1794
 
1795
 
1796
/******************************************************************************
1797
Return the value of an item, given a pointer to it and its type.
1798
 
1799
Entry:
1800
  item - pointer to item
1801
  type - data type that "item" points to
1802
 
1803
Exit:
1804
  returns a double-precision float that contains the value of the item
1805
******************************************************************************/
1806
 
1807
double get_item_value(char *item, int type)
1808
{
1809
  unsigned char *puchar;
1810
  char *pchar;
1811
  short int *pshort;
1812
  unsigned short int *pushort;
1813
  int *pint;
1814
  unsigned int *puint;
1815
  float *pfloat;
1816
  double *pdouble;
1817
  int int_value;
1818
  unsigned int uint_value;
1819
  double double_value;
1820
 
1821
  switch (type) {
1822
    case Int8:
1823
      pchar = (char *) item;
1824
      int_value = *pchar;
1825
      return ((double) int_value);
1826
    case Uint8:
1827
      puchar = (unsigned char *) item;
1828
      int_value = *puchar;
1829
      return ((double) int_value);
1830
    case Int16:
1831
      pshort = (short int *) item;
1832
      int_value = *pshort;
1833
      return ((double) int_value);
1834
    case Uint16:
1835
      pushort = (unsigned short int *) item;
1836
      int_value = *pushort;
1837
      return ((double) int_value);
1838
    case Int32:
1839
      pint = (int *) item;
1840
      int_value = *pint;
1841
      return ((double) int_value);
1842
    case Uint32:
1843
      puint = (unsigned int *) item;
1844
      uint_value = *puint;
1845
      return ((double) uint_value);
1846
    case Float32:
1847
      pfloat = (float *) item;
1848
      double_value = *pfloat;
1849
      return (double_value);
1850
    case Float64:
1851
      pdouble = (double *) item;
1852
      double_value = *pdouble;
1853
      return (double_value);
1854
    default:
1855
      fprintf (stderr, "get_item_value: bad type = %d\n", type);
1856
      exit (-1);
1857
  }
1858
 
1859
  return (0.0);  /* never actually gets here */
1860
}
1861
 
1862
 
1863
/******************************************************************************
1864
Write out an item to a file as raw binary bytes.
1865
 
1866
Entry:
1867
  fp         - file to write to
1868
  int_val    - integer version of item
1869
  uint_val   - unsigned integer version of item
1870
  double_val - double-precision float version of item
1871
  type       - data type to write out
1872
******************************************************************************/
1873
 
1874
void write_binary_item(
1875
  FILE *fp,
1876
  int int_val,
1877
  unsigned int uint_val,
1878
  double double_val,
1879
  int type
1880
)
1881
{
1882
  unsigned char uchar_val;
1883
  char char_val;
1884
  unsigned short ushort_val;
1885
  short short_val;
1886
  float float_val;
1887
 
1888
  switch (type) {
1889
    case Int8:
1890
      char_val = int_val;
1891
      fwrite (&char_val, 1, 1, fp);
1892
      break;
1893
    case Int16:
1894
      short_val = int_val;
1895
      fwrite (&short_val, 2, 1, fp);
1896
      break;
1897
    case Int32:
1898
      fwrite (&int_val, 4, 1, fp);
1899
      break;
1900
    case Uint8:
1901
      uchar_val = uint_val;
1902
      fwrite (&uchar_val, 1, 1, fp);
1903
      break;
1904
    case Uint16:
1905
      ushort_val = uint_val;
1906
      fwrite (&ushort_val, 2, 1, fp);
1907
      break;
1908
    case Uint32:
1909
      fwrite (&uint_val, 4, 1, fp);
1910
      break;
1911
    case Float32:
1912
      float_val = double_val;
1913
      fwrite (&float_val, 4, 1, fp);
1914
      break;
1915
    case Float64:
1916
      fwrite (&double_val, 8, 1, fp);
1917
      break;
1918
    default:
1919
      fprintf (stderr, "write_binary_item: bad type = %d\n", type);
1920
      exit (-1);
1921
  }
1922
}
1923
 
1924
 
1925
/******************************************************************************
1926
Write out an item to a file as ascii characters.
1927
 
1928
Entry:
1929
  fp         - file to write to
1930
  int_val    - integer version of item
1931
  uint_val   - unsigned integer version of item
1932
  double_val - double-precision float version of item
1933
  type       - data type to write out
1934
******************************************************************************/
1935
 
1936
void write_ascii_item(
1937
  FILE *fp,
1938
  int int_val,
1939
  unsigned int uint_val,
1940
  double double_val,
1941
  int type
1942
)
1943
{
1944
  switch (type) {
1945
    case Int8:
1946
    case Int16:
1947
    case Int32:
1948
      fprintf (fp, "%d ", int_val);
1949
      break;
1950
    case Uint8:
1951
    case Uint16:
1952
    case Uint32:
1953
      fprintf (fp, "%u ", uint_val);
1954
      break;
1955
    case Float32:
1956
    case Float64:
1957
      fprintf (fp, "%g ", double_val);
1958
      break;
1959
    default:
1960
      fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
1961
      exit (-1);
1962
  }
1963
}
1964
 
1965
 
1966
/******************************************************************************
1967
Get the value of an item that is in memory, and place the result
1968
into an integer, an unsigned integer and a double.
1969
 
1970
Entry:
1971
  ptr  - pointer to the item
1972
  type - data type supposedly in the item
1973
 
1974
Exit:
1975
  int_val    - integer value
1976
  uint_val   - unsigned integer value
1977
  double_val - double-precision floating point value
1978
******************************************************************************/
1979
 
1980
void get_stored_item(
1981
  void *ptr,
1982
  int type,
1983
  int *int_val,
1984
  unsigned int *uint_val,
1985
  double *double_val
1986
)
1987
{
1988
  switch (type) {
1989
    case Int8:
1990
      *int_val = *((char *) ptr);
1991
      *uint_val = *int_val;
1992
      *double_val = *int_val;
1993
      break;
1994
    case Uint8:
1995
      *uint_val = *((unsigned char *) ptr);
1996
      *int_val = *uint_val;
1997
      *double_val = *uint_val;
1998
      break;
1999
    case Int16:
2000
      *int_val = *((short int *) ptr);
2001
      *uint_val = *int_val;
2002
      *double_val = *int_val;
2003
      break;
2004
    case Uint16:
2005
      *uint_val = *((unsigned short int *) ptr);
2006
      *int_val = *uint_val;
2007
      *double_val = *uint_val;
2008
      break;
2009
    case Int32:
2010
      *int_val = *((int *) ptr);
2011
      *uint_val = *int_val;
2012
      *double_val = *int_val;
2013
      break;
2014
    case Uint32:
2015
      *uint_val = *((unsigned int *) ptr);
2016
      *int_val = *uint_val;
2017
      *double_val = *uint_val;
2018
      break;
2019
    case Float32:
2020
      *double_val = *((float *) ptr);
2021
      *int_val = *double_val;
2022
      *uint_val = *double_val;
2023
      break;
2024
    case Float64:
2025
      *double_val = *((double *) ptr);
2026
      *int_val = *double_val;
2027
      *uint_val = *double_val;
2028
      break;
2029
    default:
2030
      fprintf (stderr, "get_stored_item: bad type = %d\n", type);
2031
      exit (-1);
2032
  }
2033
}
2034
 
2035
 
2036
/******************************************************************************
2037
Get the value of an item from a binary file, and place the result
2038
into an integer, an unsigned integer and a double.
2039
 
2040
Entry:
2041
  fp   - file to get item from
2042
  type - data type supposedly in the word
2043
 
2044
Exit:
2045
  int_val    - integer value
2046
  uint_val   - unsigned integer value
2047
  double_val - double-precision floating point value
2048
******************************************************************************/
2049
 
2050
void get_binary_item(
2051
  FILE *fp,
2052
  int type,
2053
  int *int_val,
2054
  unsigned int *uint_val,
2055
  double *double_val
2056
)
2057
{
2058
  char c[8];
2059
  void *ptr;
2060
 
2061
  ptr = (void *) c;
2062
 
2063
  switch (type) {
2064
    case Int8:
2065
      fread (ptr, 1, 1, fp);
2066
      *int_val = *((char *) ptr);
2067
      *uint_val = *int_val;
2068
      *double_val = *int_val;
2069
      break;
2070
    case Uint8:
2071
      fread (ptr, 1, 1, fp);
2072
      *uint_val = *((unsigned char *) ptr);
2073
      *int_val = *uint_val;
2074
      *double_val = *uint_val;
2075
      break;
2076
    case Int16:
2077
      fread (ptr, 2, 1, fp);
2078
      *int_val = *((short int *) ptr);
2079
      *uint_val = *int_val;
2080
      *double_val = *int_val;
2081
      break;
2082
    case Uint16:
2083
      fread (ptr, 2, 1, fp);
2084
      *uint_val = *((unsigned short int *) ptr);
2085
      *int_val = *uint_val;
2086
      *double_val = *uint_val;
2087
      break;
2088
    case Int32:
2089
      fread (ptr, 4, 1, fp);
2090
      *int_val = *((int *) ptr);
2091
      *uint_val = *int_val;
2092
      *double_val = *int_val;
2093
      break;
2094
    case Uint32:
2095
      fread (ptr, 4, 1, fp);
2096
      *uint_val = *((unsigned int *) ptr);
2097
      *int_val = *uint_val;
2098
      *double_val = *uint_val;
2099
      break;
2100
    case Float32:
2101
      fread (ptr, 4, 1, fp);
2102
      *double_val = *((float *) ptr);
2103
      *int_val = *double_val;
2104
      *uint_val = *double_val;
2105
      break;
2106
    case Float64:
2107
      fread (ptr, 8, 1, fp);
2108
      *double_val = *((double *) ptr);
2109
      *int_val = *double_val;
2110
      *uint_val = *double_val;
2111
      break;
2112
    default:
2113
      fprintf (stderr, "get_binary_item: bad type = %d\n", type);
2114
      exit (-1);
2115
  }
2116
}
2117
 
2118
 
2119
/******************************************************************************
2120
Extract the value of an item from an ascii word, and place the result
2121
into an integer, an unsigned integer and a double.
2122
 
2123
Entry:
2124
  word - word to extract value from
2125
  type - data type supposedly in the word
2126
 
2127
Exit:
2128
  int_val    - integer value
2129
  uint_val   - unsigned integer value
2130
  double_val - double-precision floating point value
2131
******************************************************************************/
2132
 
2133
void get_ascii_item(
2134
  char *word,
2135
  int type,
2136
  int *int_val,
2137
  unsigned int *uint_val,
2138
  double *double_val
2139
)
2140
{
2141
  switch (type) {
2142
    case Int8:
2143
    case Uint8:
2144
    case Int16:
2145
    case Uint16:
2146
    case Int32:
2147
      *int_val = atoi (word);
2148
      *uint_val = *int_val;
2149
      *double_val = *int_val;
2150
      break;
2151
 
2152
    case Uint32:
2153
      *uint_val = strtoul (word, (char **) NULL, 10);
2154
      *int_val = *uint_val;
2155
      *double_val = *uint_val;
2156
      break;
2157
 
2158
    case Float32:
2159
    case Float64:
2160
      *double_val = atof (word);
2161
      *int_val = (int) *double_val;
2162
      *uint_val = (unsigned int) *double_val;
2163
      break;
2164
 
2165
    default:
2166
      fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
2167
      exit (-1);
2168
  }
2169
}
2170
 
2171
 
2172
/******************************************************************************
2173
Store a value into a place being pointed to, guided by a data type.
2174
 
2175
Entry:
2176
  item       - place to store value
2177
  type       - data type
2178
  int_val    - integer version of value
2179
  uint_val   - unsigned integer version of value
2180
  double_val - double version of value
2181
 
2182
Exit:
2183
  item - pointer to stored value
2184
******************************************************************************/
2185
 
2186
void store_item (
2187
  char *item,
2188
  int type,
2189
  int int_val,
2190
  unsigned int uint_val,
2191
  double double_val
2192
)
2193
{
2194
  unsigned char *puchar;
2195
  short int *pshort;
2196
  unsigned short int *pushort;
2197
  int *pint;
2198
  unsigned int *puint;
2199
  float *pfloat;
2200
  double *pdouble;
2201
 
2202
  switch (type) {
2203
    case Int8:
2204
      *item = int_val;
2205
      break;
2206
    case Uint8:
2207
      puchar = (unsigned char *) item;
2208
      *puchar = uint_val;
2209
      break;
2210
    case Int16:
2211
      pshort = (short *) item;
2212
      *pshort = int_val;
2213
      break;
2214
    case Uint16:
2215
      pushort = (unsigned short *) item;
2216
      *pushort = uint_val;
2217
      break;
2218
    case Int32:
2219
      pint = (int *) item;
2220
      *pint = int_val;
2221
      break;
2222
    case Uint32:
2223
      puint = (unsigned int *) item;
2224
      *puint = uint_val;
2225
      break;
2226
    case Float32:
2227
      pfloat = (float *) item;
2228
      *pfloat = double_val;
2229
      break;
2230
    case Float64:
2231
      pdouble = (double *) item;
2232
      *pdouble = double_val;
2233
      break;
2234
    default:
2235
      fprintf (stderr, "store_item: bad type = %d\n", type);
2236
      exit (-1);
2237
  }
2238
}
2239
 
2240
 
2241
/******************************************************************************
2242
Add an element to a PLY file descriptor.
2243
 
2244
Entry:
2245
  plyfile - PLY file descriptor
2246
  words   - list of words describing the element
2247
  nwords  - number of words in the list
2248
******************************************************************************/
2249
 
2250
void add_element (PlyFile *plyfile, char **words, int nwords)
2251
{
2252
  PlyElement *elem;
2253
 
2254
  /* create the new element */
2255
  elem = (PlyElement *) myalloc (sizeof (PlyElement));
2256
  elem->name = strdup (words[1]);
2257
  elem->num = atoi (words[2]);
2258
  elem->nprops = 0;
2259
 
2260
  /* make room for new element in the object's list of elements */
2261
  if (plyfile->num_elem_types == 0)
2262
    plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
2263
  else
2264
    plyfile->elems = (PlyElement **) realloc (plyfile->elems,
2265
                     sizeof (PlyElement *) * (plyfile->num_elem_types + 1));
2266
 
2267
  /* add the new element to the object's list */
2268
  plyfile->elems[plyfile->num_elem_types] = elem;
2269
  plyfile->num_elem_types++;
2270
}
2271
 
2272
 
2273
/******************************************************************************
2274
Return the type of a property, given the name of the property.
2275
 
2276
Entry:
2277
  name - name of property type
2278
 
2279
Exit:
2280
  returns integer code for property, or 0 if not found
2281
******************************************************************************/
2282
 
2283
int get_prop_type(char *type_name)
2284
{
2285
  int i;
2286
 
2287
  /* try to match the type name */
2288
  for (i = StartType + 1; i < EndType; i++)
2289
    if (equal_strings (type_name, type_names[i]))
2290
      return (i);
2291
 
2292
  /* see if we can match an old type name */
2293
  for (i = StartType + 1; i < EndType; i++)
2294
    if (equal_strings (type_name, old_type_names[i]))
2295
      return (i);
2296
 
2297
  /* if we get here, we didn't find the type */
2298
  return (0);
2299
}
2300
 
2301
 
2302
/******************************************************************************
2303
Add a property to a PLY file descriptor.
2304
 
2305
Entry:
2306
  plyfile - PLY file descriptor
2307
  words   - list of words describing the property
2308
  nwords  - number of words in the list
2309
******************************************************************************/
2310
 
2311
void add_property (PlyFile *plyfile, char **words, int nwords)
2312
{
2313
  int prop_type;
2314
  int count_type;
2315
  PlyProperty *prop;
2316
  PlyElement *elem;
2317
 
2318
  /* create the new property */
2319
 
2320
  prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2321
 
2322
  if (equal_strings (words[1], "list")) {          /* list */
2323
    prop->count_external = get_prop_type (words[2]);
2324
    prop->external_type = get_prop_type (words[3]);
2325
    prop->name = strdup (words[4]);
2326
    prop->is_list = PLY_LIST;
2327
  }
2328
  else if (equal_strings (words[1], "string")) {   /* string */
2329
    prop->count_external = Int8;
2330
    prop->external_type = Int8;
2331
    prop->name = strdup (words[2]);
2332
    prop->is_list = PLY_STRING;
2333
  }
2334
  else {                                           /* scalar */
2335
    prop->external_type = get_prop_type (words[1]);
2336
    prop->name = strdup (words[2]);
2337
    prop->is_list = PLY_SCALAR;
2338
  }
2339
 
2340
  /* add this property to the list of properties of the current element */
2341
 
2342
  elem = plyfile->elems[plyfile->num_elem_types - 1];
2343
 
2344
  if (elem->nprops == 0)
2345
    elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2346
  else
2347
    elem->props = (PlyProperty **) realloc (elem->props,
2348
                  sizeof (PlyProperty *) * (elem->nprops + 1));
2349
 
2350
  elem->props[elem->nprops] = prop;
2351
  elem->nprops++;
2352
}
2353
 
2354
 
2355
/******************************************************************************
2356
Add a comment to a PLY file descriptor.
2357
 
2358
Entry:
2359
  plyfile - PLY file descriptor
2360
  line    - line containing comment
2361
******************************************************************************/
2362
 
2363
void add_comment (PlyFile *plyfile, char *line)
2364
{
2365
  int i;
2366
 
2367
  /* skip over "comment" and leading spaces and tabs */
2368
  i = 7;
2369
  while (line[i] == ' ' || line[i] == '\t')
2370
    i++;
2371
 
2372
  append_comment_ply (plyfile, &line[i]);
2373
}
2374
 
2375
 
2376
/******************************************************************************
2377
Add a some object information to a PLY file descriptor.
2378
 
2379
Entry:
2380
  plyfile - PLY file descriptor
2381
  line    - line containing text info
2382
******************************************************************************/
2383
 
2384
void add_obj_info (PlyFile *plyfile, char *line)
2385
{
2386
  int i;
2387
 
2388
  /* skip over "obj_info" and leading spaces and tabs */
2389
  i = 8;
2390
  while (line[i] == ' ' || line[i] == '\t')
2391
    i++;
2392
 
2393
  append_obj_info_ply (plyfile, &line[i]);
2394
}
2395
 
2396
 
2397
/******************************************************************************
2398
Copy a property.
2399
******************************************************************************/
2400
 
2401
void copy_property(PlyProperty *dest, PlyProperty *src)
2402
{
2403
  dest->name = strdup (src->name);
2404
  dest->external_type = src->external_type;
2405
  dest->internal_type = src->internal_type;
2406
  dest->offset = src->offset;
2407
 
2408
  dest->is_list = src->is_list;
2409
  dest->count_external = src->count_external;
2410
  dest->count_internal = src->count_internal;
2411
  dest->count_offset = src->count_offset;
2412
}
2413
 
2414
 
2415
/******************************************************************************
2416
Allocate some memory.
2417
 
2418
Entry:
2419
  size  - amount of memory requested (in bytes)
2420
  lnum  - line number from which memory was requested
2421
  fname - file name from which memory was requested
2422
******************************************************************************/
2423
 
2424
static char *my_alloc(int size, int lnum, char *fname)
2425
{
2426
  char *ptr;
2427
 
2428
  ptr = (char *) malloc (size);
2429
 
2430
  if (ptr == 0) {
2431
    fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname);
2432
  }
2433
 
2434
  return (ptr);
2435
}
2436
 
2437
 
2438
/**** NEW STUFF ****/
2439
/**** NEW STUFF ****/
2440
/**** NEW STUFF ****/
2441
/**** NEW STUFF ****/
2442
 
2443
 
2444
 
2445
/******************************************************************************
2446
Given a file pointer, get ready to read PLY data from the file.
2447
 
2448
Entry:
2449
  fp - the given file pointer
2450
 
2451
Exit:
2452
  nelems     - number of elements in object
2453
  elem_names - list of element names
2454
  returns a pointer to a PlyFile, used to refer to this file, or NULL if error
2455
******************************************************************************/
2456
 
2457
PlyFile *read_ply(FILE *fp)
2458
{
2459
  PlyFile *ply;
2460
  int num_elems;
2461
  char **elem_names;
2462
 
2463
  ply = ply_read (fp, &num_elems, &elem_names);
2464
 
2465
  return (ply);
2466
}
2467
 
2468
 
2469
/******************************************************************************
2470
Given a file pointer, get ready to write PLY data to the file.
2471
 
2472
Entry:
2473
  fp         - the given file pointer
2474
  nelems     - number of elements in object
2475
  elem_names - list of element names
2476
  file_type  - file type, either ascii or binary
2477
 
2478
Exit:
2479
  returns a pointer to a PlyFile, used to refer to this file, or NULL if error
2480
******************************************************************************/
2481
 
2482
PlyFile *write_ply(
2483
  FILE *fp,
2484
  int nelems,
2485
  char **elem_names,
2486
  int file_type
2487
)
2488
{
2489
  PlyFile *ply;
2490
 
2491
  ply = ply_write (fp, nelems, elem_names, file_type);
2492
 
2493
  return (ply);
2494
}
2495
 
2496
 
2497
/******************************************************************************
2498
Return a list of the names of the elements in a particular PLY file.
2499
 
2500
Entry:
2501
  ply - PLY file whose element name list we want
2502
 
2503
Exit:
2504
  num_elems  - the number of element names in the list
2505
  returns the list of names
2506
******************************************************************************/
2507
 
2508
char **get_element_list_ply(PlyFile *ply, int *num_elems)
2509
{
2510
  int i;
2511
  char **elist;
2512
 
2513
  /* create the list of element names */
2514
 
2515
  elist = (char **) myalloc (sizeof (char *) * ply->num_elem_types);
2516
  for (i = 0; i < ply->num_elem_types; i++)
2517
    elist[i] = strdup (ply->elems[i]->name);
2518
 
2519
  /* return the number of elements and the list of element names */
2520
  *num_elems = ply->num_elem_types;
2521
  return (elist);
2522
}
2523
 
2524
 
2525
/******************************************************************************
2526
Append a comment to a PLY file.
2527
 
2528
Entry:
2529
  ply     - file to append comment to
2530
  comment - the comment to append
2531
******************************************************************************/
2532
 
2533
void append_comment_ply(PlyFile *ply, char *comment)
2534
{
2535
  /* (re)allocate space for new comment */
2536
  if (ply->num_comments == 0)
2537
    ply->comments = (char **) myalloc (sizeof (char *));
2538
  else
2539
    ply->comments = (char **) realloc (ply->comments,
2540
		     sizeof (char *) * (ply->num_comments + 1));
2541
 
2542
  /* add comment to list */
2543
  ply->comments[ply->num_comments] = strdup (comment);
2544
  ply->num_comments++;
2545
}
2546
 
2547
 
2548
/******************************************************************************
2549
Copy the comments from one PLY file to another.
2550
 
2551
Entry:
2552
  out_ply - destination file to copy comments to
2553
  in_ply  - the source of the comments
2554
******************************************************************************/
2555
 
2556
void copy_comments_ply(PlyFile *out_ply, PlyFile *in_ply)
2557
{
2558
  int i;
2559
 
2560
  for (i = 0; i < in_ply->num_comments; i++)
2561
    append_comment_ply (out_ply, in_ply->comments[i]);
2562
}
2563
 
2564
 
2565
/******************************************************************************
2566
Append object information (arbitrary text) to a PLY file.
2567
 
2568
Entry:
2569
  ply      - file to append object info to
2570
  obj_info - the object info to append
2571
******************************************************************************/
2572
 
2573
void append_obj_info_ply(PlyFile *ply, char *obj_info)
2574
{
2575
  /* (re)allocate space for new info */
2576
  if (ply->num_obj_info == 0)
2577
    ply->obj_info = (char **) myalloc (sizeof (char *));
2578
  else
2579
    ply->obj_info = (char **) realloc (ply->obj_info,
2580
		     sizeof (char *) * (ply->num_obj_info + 1));
2581
 
2582
  /* add info to list */
2583
  ply->obj_info[ply->num_obj_info] = strdup (obj_info);
2584
  ply->num_obj_info++;
2585
}
2586
 
2587
 
2588
/******************************************************************************
2589
Copy the object information from one PLY file to another.
2590
 
2591
Entry:
2592
  out_ply - destination file to copy object information to
2593
  in_ply  - the source of the object information
2594
******************************************************************************/
2595
 
2596
void copy_obj_info_ply(PlyFile *out_ply, PlyFile *in_ply)
2597
{
2598
  int i;
2599
 
2600
  for (i = 0; i < in_ply->num_obj_info; i++)
2601
    append_obj_info_ply (out_ply, in_ply->obj_info[i]);
2602
}
2603
 
2604
 
2605
/******************************************************************************
2606
Close a PLY file.
2607
 
2608
Entry:
2609
  plyfile - identifier of file to close
2610
******************************************************************************/
2611
 
2612
void close_ply(PlyFile *plyfile)
2613
{
2614
  fclose (plyfile->fp);
2615
}
2616
 
2617
 
2618
/******************************************************************************
2619
Free the memory used by a PLY file.
2620
 
2621
Entry:
2622
  plyfile - identifier of file
2623
******************************************************************************/
2624
 
2625
void free_ply(PlyFile *plyfile)
2626
{
2627
  /* free up memory associated with the PLY file */
2628
  free (plyfile);
2629
}
2630
 
2631
 
2632
/******************************************************************************
2633
Specify the index of the next element to be read in from a PLY file.
2634
 
2635
Entry:
2636
  ply - file to read from
2637
  index - index of the element to be read
2638
 
2639
Exit:
2640
  elem_count - the number of elements in the file
2641
  returns pointer to the name of this next element
2642
******************************************************************************/
2643
 
2644
char *setup_element_read_ply (PlyFile *ply, int index, int *elem_count)
2645
{
2646
  PlyElement *elem;
2647
 
2648
  if (index < 0 || index > ply->num_elem_types) {
2649
    fprintf (stderr, "Warning:  No element with index %d\n", index);
2650
    return (0);
2651
  }
2652
 
2653
  elem = ply->elems[index];
2654
 
2655
  /* set this to be the current element */
2656
  ply->which_elem = elem;
2657
 
2658
  /* return the number of such elements in the file and the element's name */
2659
  *elem_count = elem->num;
2660
  return (elem->name);
2661
}
2662
 
2663
 
2664
/******************************************************************************
2665
Read one element from the file.  This routine assumes that we're reading
2666
the type of element specified in the last call to the routine
2667
setup_element_read_ply().
2668
 
2669
Entry:
2670
  plyfile  - file identifier
2671
  elem_ptr - pointer to location where the element information should be put
2672
******************************************************************************/
2673
 
2674
void get_element_ply (PlyFile *plyfile, void *elem_ptr)
2675
{
2676
  if (plyfile->file_type == PLY_ASCII)
2677
    ascii_get_element (plyfile, (char *) elem_ptr);
2678
  else
2679
    binary_get_element (plyfile, (char *) elem_ptr);
2680
}
2681
 
2682
 
2683
/******************************************************************************
2684
Specify one of several properties of the current element that is to be
2685
read from a file.  This should be called (usually multiple times) before a
2686
call to the routine get_element_ply().
2687
 
2688
Entry:
2689
  plyfile - file identifier
2690
  prop    - property to add to those that will be returned
2691
******************************************************************************/
2692
 
2693
void setup_property_ply(
2694
  PlyFile *plyfile,
2695
  PlyProperty *prop
2696
)
2697
{
2698
  PlyElement *elem;
2699
  PlyProperty *prop_ptr;
2700
  int index;
2701
 
2702
  elem = plyfile->which_elem;
2703
 
2704
  /* deposit the property information into the element's description */
2705
 
2706
  prop_ptr = find_property (elem, prop->name, &index);
2707
  if (prop_ptr == NULL) {
2708
    fprintf (stderr, "Warning:  Can't find property '%s' in element '%s'\n",
2709
             prop->name, elem->name);
2710
    return;
2711
  }
2712
  prop_ptr->internal_type  = prop->internal_type;
2713
  prop_ptr->offset         = prop->offset;
2714
  prop_ptr->count_internal = prop->count_internal;
2715
  prop_ptr->count_offset   = prop->count_offset;
2716
 
2717
  /* specify that the user wants this property */
2718
  elem->store_prop[index] = STORE_PROP;
2719
}
2720
 
2721
 
2722
/******************************************************************************
2723
Specify that we want the "other" properties of the current element to be tucked
2724
away within the user's structure.
2725
 
2726
Entry:
2727
  plyfile - file identifier
2728
  offset  - offset to where other_props will be stored inside user's structure
2729
 
2730
Exit:
2731
  returns pointer to structure containing description of other_props
2732
******************************************************************************/
2733
 
2734
PlyOtherProp *get_other_properties_ply(
2735
  PlyFile *plyfile,
2736
  int offset
2737
)
2738
{
2739
  PlyOtherProp *other;
2740
 
2741
  other = get_other_properties (plyfile, plyfile->which_elem, offset);
2742
  return (other);
2743
}
2744
 
2745
 
2746
/******************************************************************************
2747
Describe which element is to be written next and state how many of them will
2748
be written.
2749
 
2750
Entry:
2751
  plyfile   - file identifier
2752
  elem_name - name of element that information is being described
2753
  nelems    - number of elements of this type to be written
2754
******************************************************************************/
2755
 
2756
void describe_element_ply(
2757
  PlyFile *plyfile,
2758
  char *elem_name,
2759
  int nelems
2760
)
2761
{
2762
  int i;
2763
  PlyElement *elem;
2764
  PlyProperty *prop;
2765
 
2766
  /* look for appropriate element */
2767
  elem = find_element (plyfile, elem_name);
2768
  if (elem == NULL) {
2769
    fprintf(stderr,"describe_element_ply: can't find element '%s'\n",elem_name);
2770
    exit (-1);
2771
  }
2772
 
2773
  elem->num = nelems;
2774
 
2775
  /* now this element is the current element */
2776
  plyfile->which_elem = elem;
2777
}
2778
 
2779
 
2780
/******************************************************************************
2781
Describe a property of an element.
2782
 
2783
Entry:
2784
  plyfile   - file identifier
2785
  prop      - the new property
2786
******************************************************************************/
2787
 
2788
void describe_property_ply(
2789
  PlyFile *plyfile,
2790
  PlyProperty *prop
2791
)
2792
{
2793
  PlyElement *elem;
2794
  PlyProperty *elem_prop;
2795
 
2796
  elem = plyfile->which_elem;
2797
 
2798
  /* create room for new property */
2799
 
2800
  if (elem->nprops == 0) {
2801
    elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2802
    elem->store_prop = (char *) myalloc (sizeof (char));
2803
    elem->nprops = 1;
2804
  }
2805
  else {
2806
    elem->nprops++;
2807
    elem->props = (PlyProperty **)
2808
                  realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
2809
    elem->store_prop = (char *)
2810
                  realloc (elem->store_prop, sizeof (char) * elem->nprops);
2811
  }
2812
 
2813
  /* copy the new property */
2814
 
2815
  elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2816
  elem->props[elem->nprops - 1] = elem_prop;
2817
  elem->store_prop[elem->nprops - 1] = NAMED_PROP;
2818
  copy_property (elem_prop, prop);
2819
}
2820
 
2821
 
2822
/******************************************************************************
2823
Describe what the "other" properties are that are to be stored, and where
2824
they are in an element.
2825
******************************************************************************/
2826
 
2827
void describe_other_properties_ply(
2828
  PlyFile *plyfile,
2829
  PlyOtherProp *other,
2830
  int offset
2831
)
2832
{
2833
  int i;
2834
  PlyElement *elem;
2835
  PlyProperty *prop;
2836
 
2837
  /* look for appropriate element */
2838
  elem = find_element (plyfile, other->name);
2839
  if (elem == NULL) {
2840
    fprintf(stderr, "describe_other_properties_ply: can't find element '%s'\n",
2841
            other->name);
2842
    return;
2843
  }
2844
 
2845
  /* create room for other properties */
2846
 
2847
  if (elem->nprops == 0) {
2848
    elem->props = (PlyProperty **)
2849
                  myalloc (sizeof (PlyProperty *) * other->nprops);
2850
    elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
2851
    elem->nprops = 0;
2852
  }
2853
  else {
2854
    int newsize;
2855
    newsize = elem->nprops + other->nprops;
2856
    elem->props = (PlyProperty **)
2857
                  realloc (elem->props, sizeof (PlyProperty *) * newsize);
2858
    elem->store_prop = (char *)
2859
                  realloc (elem->store_prop, sizeof (char) * newsize);
2860
  }
2861
 
2862
  /* copy the other properties */
2863
 
2864
  for (i = 0; i < other->nprops; i++) {
2865
    prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2866
    copy_property (prop, other->props[i]);
2867
    elem->props[elem->nprops] = prop;
2868
    elem->store_prop[elem->nprops] = OTHER_PROP;
2869
    elem->nprops++;
2870
  }
2871
 
2872
  /* save other info about other properties */
2873
  elem->other_size = other->size;
2874
  elem->other_offset = offset;
2875
}
2876
 
2877
 
2878
/******************************************************************************
2879
Pass along a pointer to "other" elements that we want to save in a given
2880
PLY file.  These other elements were presumably read from another PLY file.
2881
 
2882
Entry:
2883
  plyfile     - file pointer in which to store this other element info
2884
  other_elems - info about other elements that we want to store
2885
******************************************************************************/
2886
 
2887
void describe_other_elements_ply (
2888
  PlyFile *plyfile,
2889
  PlyOtherElems *other_elems
2890
)
2891
{
2892
  int i;
2893
  OtherElem *other;
2894
 
2895
  /* ignore this call if there is no other element */
2896
  if (other_elems == NULL)
2897
    return;
2898
 
2899
  /* save pointer to this information */
2900
  plyfile->other_elems = other_elems;
2901
 
2902
  /* describe the other properties of this element */
2903
 
2904
  for (i = 0; i < other_elems->num_elems; i++) {
2905
    other = &(other_elems->other_list[i]);
2906
    element_count_ply (plyfile, other->elem_name, other->elem_count);
2907
    describe_other_properties_ply (plyfile, other->other_props,
2908
                                   offsetof(OtherData,other_props));
2909
  }
2910
}
2911
 
2912
 
2913
 
2914
/**** Property Propagation Rules ****/
2915
 
2916
 
2917
typedef struct RuleName {
2918
  int code;
2919
  char *name;
2920
} RuleName;
2921
 
2922
RuleName rule_name_list[] = {
2923
  AVERAGE_RULE, "avg",
2924
  RANDOM_RULE, "rnd",
2925
  MINIMUM_RULE, "max",
2926
  MAXIMUM_RULE, "min",
2927
  MAJORITY_RULE, "major",
2928
  SAME_RULE, "same",
2929
  -1, "end_marker",
2930
};
2931
 
2932
 
2933
 
2934
/******************************************************************************
2935
Initialize the property propagation rules for an element.  Default is to
2936
use averaging (AVERAGE_RULE) for creating all new properties.
2937
 
2938
Entry:
2939
  ply       - PLY object that this is for
2940
  elem_name - name of the element that we're making the rules for
2941
 
2942
Exit:
2943
  returns pointer to the default rules
2944
******************************************************************************/
2945
 
2946
PlyPropRules *init_rule_ply (PlyFile *ply, char *elem_name)
2947
{
2948
  int i,j;
2949
  PlyElement *elem;
2950
  PlyPropRules *rules;
2951
  PlyRuleList *list;
2952
  int found_prop;
2953
 
2954
  elem = find_element (ply, elem_name);
2955
  if (elem == NULL) {
2956
    fprintf (stderr, "init_rule_ply: Can't find element '%s'\n", elem_name);
2957
    exit (-1);
2958
  }
2959
 
2960
  rules = (PlyPropRules *) myalloc (sizeof (PlyPropRules));
2961
  rules->elem = elem;
2962
  rules->rule_list = (int *) myalloc (sizeof(int) * elem->nprops);
2963
  rules->max_props = 0;
2964
  rules->nprops = 0;
2965
 
2966
  /* default is to use averaging rule */
2967
  for (i = 0; i < elem->nprops; i++)
2968
    rules->rule_list[i] = AVERAGE_RULE;
2969
 
2970
  /* see if there are other rules we should use */
2971
 
2972
  if (ply->rule_list == NULL)
2973
    return (rules);
2974
 
2975
  /* try to match the element, property and rule name */
2976
 
2977
  for (list = ply->rule_list; list != NULL; list = list->next) {
2978
 
2979
    if (!equal_strings (list->element, elem->name))
2980
      continue;
2981
 
2982
    found_prop = 0;
2983
 
2984
    for (i = 0; i < elem->nprops; i++)
2985
      if (equal_strings (list->property, elem->props[i]->name)) {
2986
 
2987
        found_prop = 1;
2988
 
2989
        /* look for matching rule name */
2990
        for (j = 0; rule_name_list[j].code != -1; j++)
2991
          if (equal_strings (list->name, rule_name_list[j].name)) {
2992
            rules->rule_list[i] = rule_name_list[j].code;
2993
            break;
2994
          }
2995
      }
2996
 
2997
    if (!found_prop) {
2998
      fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
2999
               list->property, list->name);
3000
      continue;
3001
    }
3002
  }
3003
 
3004
  return (rules);
3005
}
3006
 
3007
 
3008
/******************************************************************************
3009
Modify a property propagation rule.
3010
 
3011
Entry:
3012
  rules - rules for the element
3013
  prop_name - name of the property whose rule we're modifying
3014
  rule_type - type of rule (MAXIMUM_RULE, MINIMUM_RULE, MAJORITY_RULE, etc.)
3015
******************************************************************************/
3016
 
3017
void modify_rule_ply (PlyPropRules *rules, char *prop_name, int rule_type)
3018
{
3019
  int i;
3020
  PlyElement *elem = rules->elem;
3021
 
3022
  /* find the property and modify its rule type */
3023
 
3024
  for (i = 0; i < elem->nprops; i++)
3025
    if (equal_strings (elem->props[i]->name, prop_name)) {
3026
      rules->rule_list[i] = rule_type;
3027
      return;
3028
    }
3029
 
3030
  /* we didn't find the property if we get here */
3031
  fprintf (stderr, "modify_rule_ply: Can't find property '%s'\n", prop_name);
3032
  exit (-1);
3033
}
3034
 
3035
 
3036
/******************************************************************************
3037
Begin to create a set of properties from a set of propagation rules.
3038
 
3039
Entry:
3040
  ply   - PLY object whose rules we're preparing to use
3041
  rules - rules for the element
3042
******************************************************************************/
3043
 
3044
void start_props_ply (PlyFile *ply, PlyPropRules *rules)
3045
{
3046
  int i;
3047
  int count;
3048
  PlyElement *elem = rules->elem;
3049
 
3050
  /* save pointer to the rules in the PLY object */
3051
  ply->current_rules = rules;
3052
 
3053
  /* get ready for new sets of properties to combine */
3054
  rules->nprops = 0;
3055
}
3056
 
3057
 
3058
/******************************************************************************
3059
Remember a set of properties and their weights for creating a new set of
3060
properties.
3061
 
3062
Entry:
3063
  weight      - weights for this set of properties
3064
  other_props - the properties to use
3065
******************************************************************************/
3066
 
3067
void weight_props_ply (PlyFile *ply, float weight, void *other_props)
3068
{
3069
  PlyPropRules *rules = ply->current_rules;
3070
 
3071
  /* allocate space for properties and weights, if necessary */
3072
  if (rules->max_props == 0) {
3073
    rules->max_props = 6;
3074
    rules->props = (void **) myalloc (sizeof (void *) * rules->max_props);
3075
    rules->weights = (float *) myalloc (sizeof (float) * rules->max_props);
3076
  }
3077
  if (rules->nprops == rules->max_props) {
3078
    rules->max_props *= 2;
3079
    rules->props = (void **) realloc (rules->props,
3080
                   sizeof (void *) * rules->max_props);
3081
    rules->weights = (float *) realloc (rules->weights,
3082
                     sizeof (float) * rules->max_props);
3083
  }
3084
 
3085
  /* remember these new properties and their weights */
3086
 
3087
  rules->props[rules->nprops] = other_props;
3088
  rules->weights[rules->nprops] = weight;
3089
  rules->nprops++;
3090
}
3091
 
3092
 
3093
/******************************************************************************
3094
Return a pointer to a new set of properties that have been created using
3095
a specified set of property combination rules and a given collection of
3096
"other" properties.
3097
 
3098
Exit:
3099
  returns a pointer to the new properties
3100
******************************************************************************/
3101
 
3102
void *get_new_props_ply(PlyFile *ply)
3103
{
3104
  int i,j;
3105
  static double *vals;
3106
  static int max_vals = 0;
3107
  PlyPropRules *rules = ply->current_rules;
3108
  PlyElement *elem = rules->elem;
3109
  PlyProperty *prop;
3110
  char *data;
3111
  char *new_data;
3112
  void *ptr;
3113
  int offset;
3114
  int type;
3115
  double double_val;
3116
  int int_val;
3117
  unsigned int uint_val;
3118
  int random_pick;
3119
 
3120
  /* return NULL if we've got no "other" properties */
3121
  if (elem->other_size == 0) {
3122
    return (NULL);
3123
  }
3124
 
3125
  /* create room for combined other properties */
3126
  new_data = (char *) myalloc (sizeof (char) * elem->other_size);
3127
 
3128
  /* make sure there is enough room to store values we're to combine */
3129
 
3130
  if (max_vals == 0) {
3131
    max_vals = rules->nprops;
3132
    vals = (double *) myalloc (sizeof (double) * rules->nprops);
3133
  }
3134
  if (rules->nprops >= max_vals) {
3135
    max_vals = rules->nprops;
3136
    vals = (double *) realloc (vals, sizeof (double) * rules->nprops);
3137
  }
3138
 
3139
  /* in case we need a random choice */
365 jab 3140
#ifndef WIN32
337 jab 3141
  random_pick = (int) floor (rules->nprops * drand48());
365 jab 3142
#else
3143
  random_pick = (int) floor (rules->nprops * rand()/(double)RAND_MAX);
3144
#endif
337 jab 3145
 
3146
  /* calculate the combination for each "other" property of the element */
3147
 
3148
  for (i = 0; i < elem->nprops; i++) {
3149
 
3150
    /* don't bother with properties we've been asked to store explicitly */
3151
    if (elem->store_prop[i])
3152
      continue;
3153
 
3154
    prop = elem->props[i];
3155
    offset = prop->offset;
3156
    type = prop->external_type;
3157
 
3158
    /* collect together all the values we're to combine */
3159
 
3160
    for (j = 0; j < rules->nprops; j++) {
3161
      data = (char *) rules->props[j];
3162
      ptr = (void *) (data + offset);
3163
      get_stored_item ((void *) ptr, type, &int_val, &uint_val, &double_val);
3164
      vals[j] = double_val;
3165
    }
3166
 
3167
    /* calculate the combined value */
3168
 
3169
    switch (rules->rule_list[i]) {
3170
      case AVERAGE_RULE: {
3171
	double sum = 0;
3172
	double weight_sum = 0;
3173
	for (j = 0; j < rules->nprops; j++) {
3174
	  sum += vals[j] * rules->weights[j];
3175
	  weight_sum += rules->weights[j];
3176
	}
3177
	double_val = sum / weight_sum;
3178
        break;
3179
      }
3180
      case MINIMUM_RULE: {
3181
	double_val = vals[0];
3182
	for (j = 1; j < rules->nprops; j++)
3183
	  if (double_val > vals[j])
3184
	    double_val = vals[j];
3185
        break;
3186
      }
3187
      case MAXIMUM_RULE: {
3188
	double_val = vals[0];
3189
	for (j = 1; j < rules->nprops; j++)
3190
	  if (double_val < vals[j])
3191
	    double_val = vals[j];
3192
        break;
3193
      }
3194
      case RANDOM_RULE: {
3195
	double_val = vals[random_pick];
3196
        break;
3197
      }
3198
      case SAME_RULE: {
3199
	double_val = vals[0];
3200
	for (j = 1; j < rules->nprops; j++)
3201
	  if (double_val != vals[j]) {
3202
	    fprintf (stderr,
3203
    "get_new_props_ply: Error combining properties that should be the same.\n");
3204
            exit (-1);
3205
	  }
3206
        break;
3207
      }
3208
      default:
3209
        fprintf (stderr, "get_new_props_ply: Bad rule = %d\n",
3210
	         rules->rule_list[i]);
3211
	exit (-1);
3212
    }
3213
 
3214
    /* store the combined value */
3215
 
3216
    int_val = (int) double_val;
3217
    uint_val = (unsigned int) double_val;
3218
    ptr = (void *) (new_data + offset);
3219
    store_item ((char *) ptr, type, int_val, uint_val, double_val);
3220
  }
3221
 
3222
  return ((void *) new_data);
3223
}
3224
 
3225
 
3226
/******************************************************************************
3227
Set the list of user-specified property combination rules.
3228
******************************************************************************/
3229
 
3230
void set_prop_rules_ply (PlyFile *ply, PlyRuleList *prop_rules)
3231
{
3232
  ply->rule_list = prop_rules;
3233
}
3234
 
3235
 
3236
/******************************************************************************
3237
Append a property rule to a growing list of user-specified rules.
3238
 
3239
Entry:
3240
  rule_list - current rule list
3241
  name      - name of property combination rule
3242
  property  - "element.property" says which property the rule affects
3243
 
3244
Exit:
3245
  returns pointer to the new rule list
3246
******************************************************************************/
3247
 
3248
PlyRuleList *append_prop_rule (
3249
  PlyRuleList *rule_list,
3250
  char *name,
3251
  char *property
3252
)
3253
{
3254
  PlyRuleList *rule;
3255
  PlyRuleList *rule_ptr;
3256
  char *str,*str2;
3257
  char *ptr;
3258
 
3259
  /* find . */
3260
  str = strdup (property);
3261
  for (ptr = str; *ptr != '\0' && *ptr != '.'; ptr++) ;
3262
 
3263
  /* split string at . */
3264
  if (*ptr == '.') {
3265
    *ptr = '\0';
3266
    str2 = ptr + 1;
3267
  }
3268
  else {
3269
    fprintf (stderr, "Can't find property '%s' for rule '%s'\n",
3270
             property, name);
3271
    return (rule_list);
3272
  }
3273
 
3274
  rule = (PlyRuleList *) malloc (sizeof (PlyRuleList));
3275
  rule->name = name;
3276
  rule->element = str;
3277
  rule->property = str2;
3278
  rule->next = NULL;
3279
 
3280
  /* either start rule list or append to it */
3281
 
3282
  if (rule_list == NULL)
3283
    rule_list = rule;
3284
  else {                      /* append new rule to current list */
3285
    rule_ptr = rule_list;
3286
    while (rule_ptr->next != NULL)
3287
      rule_ptr = rule_ptr->next;
3288
    rule_ptr->next = rule;
3289
  }
3290
 
3291
  /* return pointer to list */
3292
 
3293
  return (rule_list);
3294
}
3295
 
3296
 
3297
/******************************************************************************
3298
See if a name matches the name of any property combination rules.
3299
 
3300
Entry:
3301
  name - name of rule we're trying to match
3302
 
3303
Exit:
3304
  returns 1 if we find a match, 0 if not
3305
******************************************************************************/
3306
 
3307
int matches_rule_name (char *name)
3308
{
3309
  int i;
3310
 
3311
  for (i = 0; rule_name_list[i].code != -1; i++)
3312
    if (equal_strings (rule_name_list[i].name, name))
3313
      return (1);
3314
 
3315
  return (0);
3316
}
3317