source: proiecte/pmake3d/make3d_original/Make3dSingleImageStanford_version0.1/third_party/vrippack-0.31/src/plytools/plysubtract.cc @ 37

Last change on this file since 37 was 37, checked in by (none), 14 years ago

Added original make3d

File size: 20.0 KB
Line 
1/*
2plysubtract:
3  Read in two ply files, A and B, and write out A-B, namely,
4  all triangles in A that are not in B.
5
6Algorithm:
7  Read in A and B.
8  For each vertex in B, find the closest vertex in A
9  (within a limited neighborhood search size).  Then, for each
10  triangle in B, search A for a corresponding triangle to nuke.
11  Finally, write out the non-nuked triangles.
12
13Authors:
14  Lucas Pereira, 1-13-99
15  based on plyshared, written by Greg Turk, Aug 1994
16*/
17
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <math.h>
22#include <strings.h>
23#include <ply.h>
24
25
26/* user's vertex and face definitions for a polygonal object */
27
28
29struct _Face;
30typedef struct _Flist {
31  struct _Face *f;
32  struct _Flist *next;
33} Flist;
34
35typedef struct Vertex {
36  float x,y,z;
37  int index;
38  bool isA;                // True if vertex belongs to mesh A
39  struct Vertex *closest;  // Points to the closest vertex in the other mesh
40  struct Vertex *next;
41  void *other_props;       /* other properties */
42  int nfaces;
43  Flist *faces;
44} Vertex;
45
46typedef struct _Face {
47  unsigned char nverts;    /* number of vertex indices in list */
48  int *verts;              /* vertex index list */
49  Vertex **vptrs;           /* vertex pointer list */
50  void *other_props;       /* other properties */
51  bool has_match;          // does a match exist in the other file?
52} Face;
53
54char *elem_names[] = { /* list of the kinds of elements in the user's object */
55  "vertex", "face"
56};
57
58PlyProperty vert_props[] = { /* list of property information for a vertex */
59  {"x", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,x), 0, 0, 0, 0},
60  {"y", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,y), 0, 0, 0, 0},
61  {"z", PLY_FLOAT, PLY_FLOAT, offsetof(Vertex,z), 0, 0, 0, 0},
62};
63
64PlyProperty face_props[] = { /* list of property information for a vertex */
65  {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
66   1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
67};
68
69
70/*** the PLY object ***/
71
72typedef struct _PlyObject {
73  int nverts,nfaces;
74  Vertex **vlist;
75  Face **flist;
76  PlyOtherElems *other_elements;
77  PlyOtherProp *vert_other,*face_other;
78  int nelems;
79  char **elist;
80  int num_comments;
81  char **comments;
82  int num_obj_info;
83  char **obj_info;
84  int file_type;
85} PlyObject;
86
87static PlyObject A;
88static PlyObject B;
89
90static bool DO_INTERSECTION = false;  // if true, intersect, not subtract
91static float tolerance = 0.0001;   /* what constitutes "near" */
92
93
94/* hash table for near neighbor searches */
95/* A few randomly chosen prime numbers... */
96
97#define PR1  17
98#define PR2 101
99
100#define TABLE_SIZE1       5003
101#define TABLE_SIZE2      17011
102#define TABLE_SIZE3      53003
103#define TABLE_SIZE4     107021
104#define TABLE_SIZE5     233021
105#define TABLE_SIZE6     472019
106#define TABLE_SIZE7     600169
107#define TABLE_SIZE8    1111189
108#define TABLE_SIZE9    2222177
109#define TABLE_SIZE10   4444147
110#define TABLE_SIZE11   9374153
111#define TABLE_SIZE12  20123119
112#define TABLE_SIZE13  30123139
113#define TABLE_SIZE14  50123011
114#define TABLE_SIZE15  70123117
115#define TABLE_SIZE16 100123171
116#define TABLE_SIZE17 140123143
117#define TABLE_SIZE18 200123111
118#define TABLE_SIZE19 400123123
119#define TABLE_SIZE20 800123119
120
121
122
123
124typedef struct Hash_Table {     /* uniform spatial subdivision, with hash */
125  int npoints;                  /* number of points placed in table */
126  Vertex **verts;               /* array of hash cells */
127  int num_entries;              /* number of array elements in verts */
128  float scale;                  /* size of cell */
129} Hash_Table;
130
131
132Hash_Table *init_table(int, float);
133void add_to_hash (Vertex *, Hash_Table *, float);
134void usage(char *progname);
135void write_file(PlyObject &o);
136void read_file(FILE *inFile, PlyObject &o);
137void mark_mesh(PlyObject &o, bool isA);
138void set_flists(PlyObject &o);
139void set_vptrs(PlyObject &o);
140bool find_match(Face *f, PlyObject &A, PlyObject &B);
141void subtract_vertices(PlyObject &A, PlyObject &B);
142
143
144/******************************************************************************
145Main program.
146******************************************************************************/
147
148int
149main(int argc, char *argv[])
150{
151  int i,j;
152  char *s;
153  char *progname;
154  FILE *inA;
155  FILE *inB;
156
157  progname = argv[0];
158
159  /* Parse -flags */
160  while (--argc > 0 && (*++argv)[0]=='-') {
161    for (s = argv[0]+1; *s; s++)
162      switch (*s) {
163        case 't':
164          if (argc < 2) {
165            usage(progname);
166          }
167          tolerance = atof (*++argv);
168          argc -= 1;
169          break;
170        case 'i':
171          DO_INTERSECTION = true;
172          break;
173        default:
174          usage (progname);
175          exit (-1);
176          break;
177      }
178  }
179
180  /* both input files must be specified on the command line */
181  if (argc > 1 && *argv[0] != '-' && *argv[1] != '-') {
182    inA = fopen(argv[0], "r");
183    if (inA == NULL) {
184      fprintf(stderr, "Error: Couldn't open input file %s\n", argv[0]);
185      usage(progname);
186      exit(-1);
187    }
188    inB = fopen(argv[1], "r");
189    if (inB == NULL) {
190      fprintf(stderr, "Error: Couldn't open input file %s\n", argv[1]);
191      usage(progname);
192      exit(-1);
193    }
194    argc -=2;
195    argv +=2;
196  } else {
197    usage(progname);
198  }
199
200   /* Check no extra args */
201   if (argc > 0) {
202     fprintf(stderr, "Error: Unhandled arg: %s\n", argv[0]);
203     usage(progname);
204     exit(-1);
205   }
206
207  read_file(inA, A);
208  mark_mesh(A, true);
209  read_file(inB, B);
210  mark_mesh(B, false);
211
212  // Make Face vptrs point to verts
213  set_vptrs(A);
214  set_vptrs(B);
215
216  // Make B vertices point to B triangles
217  set_flists(A);
218  set_flists(B);
219
220  // For each triangle of A
221  subtract_vertices(A, B);
222
223  write_file(A);
224}
225
226
227/******************************************************************************
228Print out usage information.
229******************************************************************************/
230
231void
232usage(char *progname)
233{
234  fprintf (stderr, "\n");
235  fprintf (stderr, "usage: %s [flags] [A.ply] [B.ply] > out.ply\n", progname);
236  fprintf (stderr, "flags:\n");
237  fprintf (stderr, "       -i           (does intersection instead of subtraction)\n");
238  fprintf (stderr, "       -t tolerance (default = %g)\n", tolerance);
239  fprintf (stderr, "\n");
240  fprintf (stderr, "This program computes (A-B), namely, those faces in A\n");
241  fprintf (stderr, "that do not occur in B.  \"Face equivalence\" is defined\n");
242  fprintf (stderr, "as two faces, a' and b', such that every vertex in a' has\n");
243  fprintf (stderr, "a 1-1 mapping to vertices in b'.  The distance between\n");
244  fprintf (stderr, "corresponding pairs must be less than tolerance, and for each\n");
245  fprintf (stderr, "vertex of b', the corresponding a' vertex must be the closest\n");
246  fprintf (stderr, "vertex in A.\n");
247  fprintf (stderr, "\n");
248  fprintf (stderr, "With the -i flag, it outputs (A^B), with the same definition\n");
249  fprintf (stderr, "for face equivalence.\n");
250  fprintf (stderr, "\n");
251  exit(-1);
252}
253
254/******************************************************************************
255Mark vertices as belonging to A or not...
256******************************************************************************/
257
258void
259mark_mesh(PlyObject &o, bool isA) {
260  int i;
261  for (i=0; i < o.nverts; i++) {
262    o.vlist[i]->isA = isA;
263  }
264}
265
266
267/******************************************************************************
268Make face vptrs point to the vertices...
269******************************************************************************/
270
271void
272set_vptrs(PlyObject &o) {
273  int i,j;
274  Face *f;
275  Vertex *v;
276  Flist *fl;
277
278  // Malloc vptrs array, set the pointers.
279  for (i=0; i < o.nfaces; i++) {
280    f = o.flist[i];
281    f->vptrs = (Vertex **) malloc(f->nverts * sizeof(Vertex *));
282    for (j=0; j < f->nverts; j++) {
283      v = o.vlist[f->verts[j]];
284      f->vptrs[j] = v;
285    }
286  }
287}
288
289
290/******************************************************************************
291Make vertices point to the faces...
292******************************************************************************/
293
294void
295set_flists(PlyObject &o) {
296  int i,j;
297  Face *f;
298  Vertex *v;
299  Flist *fl;
300
301  // First set all vert facecounters to 0
302  for (i=0; i < o.nverts; i++) {
303    v = o.vlist[i];
304    v->nfaces = 0;
305  }
306
307  for (i=0; i < o.nfaces; i++) {
308    f = o.flist[i];
309    for (j=0; j < f->nverts; j++) {
310      v = o.vlist[f->verts[j]];
311      if ((fl = (Flist *) malloc(sizeof(Flist))) == NULL) {
312        fprintf(stderr, "Error, out of memory.\n");
313        exit(-1);
314      }
315      // Make fl point to the face, and add it to head of linked list
316      // so that the vertex knows about this face.
317      fl->f = f;
318      fl->next = v->faces;
319      v->faces = fl;
320      v->nfaces++;
321    }
322  }
323}
324
325/******************************************************************************
326See if face has a match in B...
327******************************************************************************/
328
329bool 
330find_match(Face *f, PlyObject &A, PlyObject &B) {
331  int i;
332  Vertex *v;
333  Flist *fl;
334  Face *of;
335
336  if (!f->nverts) return false;
337 
338  // Find v, the matching vertex for the first vertex in f
339  v = A.vlist[f->verts[0]]->closest;
340  if (v==NULL) return false;
341 
342  for (fl = v->faces;fl != NULL; fl = fl->next) {
343    of = fl->f;
344    if (of->nverts != f->nverts) continue;
345    // See if f, of are matches
346
347    for (int offset=0; offset < f->nverts; offset++) {
348    bool diffFound = false;
349      for (i=0; i < f->nverts; i++) {
350        Vertex *v1 = A.vlist[f->verts[i]];
351        Vertex *v2 = B.vlist[of->verts[(i+offset)%f->nverts]];
352        if (v1->closest != v2) {
353          diffFound = true;
354          break;
355        }
356      }
357      // If we get here, this particular offset gives a match
358      if (!diffFound) return true;
359    }
360  }
361
362  // if we get here, didn't find a match, so return false
363  return false;
364
365}
366
367/******************************************************************************
368Figure out which vertices are close enough to share.
369******************************************************************************/
370
371void
372subtract_vertices(PlyObject &A, PlyObject &B)
373{
374  int i,j,k;
375  int jj;
376  Hash_Table *table;
377  float squared_dist;
378  Vertex *vert;
379  Face *face;
380
381  table = init_table (A.nverts+B.nverts, tolerance);
382
383  squared_dist = tolerance * tolerance;
384
385  /* place all vertices in the hash table, and in the process */
386  /* learn which ones should be shared */
387
388  for (i = 0; i < A.nverts; i++)
389    add_to_hash (A.vlist[i], table, squared_dist);
390  for (i = 0; i < B.nverts; i++)
391    add_to_hash (B.vlist[i], table, squared_dist);
392
393  // For each triangle in A, see if it has a match in B
394  for (i = 0; i < A.nfaces; i++) {
395    if (find_match(A.flist[i], A, B)) {
396      A.flist[i]->has_match = true;
397      // Decrement the face counters for each vertex
398      for (j=0; j < A.flist[i]->nverts; j++) {
399        A.vlist[A.flist[i]->verts[j]]->nfaces--;
400        if (DO_INTERSECTION) {
401          // Set completely to 0 for intersection, so it's marked
402          A.vlist[A.flist[i]->verts[j]]->nfaces = 0;
403        }
404      }
405    }
406  }
407}
408
409
410/******************************************************************************
411Add a vertex to it's hash table.
412
413Entry:
414  vert    - vertex to add
415  table   - hash table to add to
416  sq_dist - squared value of distance tolerance
417******************************************************************************/
418
419void 
420add_to_hash(Vertex *vert, Hash_Table *table, float sq_dist)
421{
422  int index;
423  int a,b,c;
424  int aa,bb,cc;
425  float scale;
426  Vertex *ptr;
427  float dx,dy,dz;
428  float sq;
429  float min_dist;
430  Vertex *min_ptr;
431
432  /* determine which cell the position lies within */
433
434  scale = table->scale;
435  aa = int (floor (vert->x * scale));
436  bb = int (floor (vert->y * scale));
437  cc = int (floor (vert->z * scale));
438
439  /* examine vertices in table to see if we're very close */
440
441  min_dist = 1e20;
442  min_ptr = NULL;
443
444  /* look at nine cells, centered at cell containing location */
445  // Do this only for points in B.  A just gets added.
446  if (!(vert->isA)) {
447    for (a = aa-1; a <= aa+1; a++) {
448      for (b = bb-1; b <= bb+1; b++) {
449        for (c = cc-1; c <= cc+1; c++) {
450
451          /* compute position in hash table */
452          index = (a * PR1 + b * PR2 + c) % table->num_entries;
453          if (index < 0)
454            index += table->num_entries;
455
456          /* examine all points hashed to this cell */
457          for (ptr = table->verts[index]; ptr != NULL; ptr = ptr->next) {
458            if (ptr->isA) {
459              /* distance (squared) to this point */
460              dx = ptr->x - vert->x;
461              dy = ptr->y - vert->y;
462              dz = ptr->z - vert->z;
463              sq = dx*dx + dy*dy + dz*dz;
464
465              /* maybe we've found new closest point */
466              if (sq <= min_dist) {
467                min_dist = sq;
468                min_ptr = ptr;
469              }
470            }
471          }
472        }       
473      }
474    }
475  }
476
477  /* If we found a match, have new vertex point to the matching vertex. */
478  /* If we didn't find a match, add new vertex to the table. */
479
480  if (min_ptr && min_dist < sq_dist) {  /* match */
481    vert->closest = min_ptr;
482    min_ptr->closest = vert;
483  }
484  else {          /* no match */
485    index = (aa * PR1 + bb * PR2 + cc) % table->num_entries;
486    if (index < 0)
487      index += table->num_entries;
488    vert->next = table->verts[index];
489    table->verts[index] = vert;
490    vert->closest = NULL;
491  }
492}
493
494
495/******************************************************************************
496Initialize a uniform spatial subdivision table.  This structure divides
4973-space into cubical cells and deposits points into their appropriate
498cells.  It uses hashing to make the table a one-dimensional array.
499
500Entry:
501  nverts - number of vertices that will be placed in the table
502  size   - size of a cell
503
504Exit:
505  returns pointer to hash table
506******************************************************************************/
507
508Hash_Table *
509init_table(int nverts, float size)
510{
511  int i;
512  int index;
513  int a,b,c;
514  Hash_Table *table;
515  float scale;
516
517  /* allocate new hash table */
518
519  table = (Hash_Table *) malloc (sizeof (Hash_Table));
520
521  if (nverts < TABLE_SIZE1)
522    table->num_entries = TABLE_SIZE1;
523  else if (nverts < TABLE_SIZE2)
524    table->num_entries = TABLE_SIZE2;
525  else if (nverts < TABLE_SIZE3)
526    table->num_entries = TABLE_SIZE3;
527  else if (nverts < TABLE_SIZE4)
528    table->num_entries = TABLE_SIZE4;
529  else if (nverts < TABLE_SIZE5)
530    table->num_entries = TABLE_SIZE5;
531  else if (nverts < TABLE_SIZE6)
532    table->num_entries = TABLE_SIZE6;
533  else if (nverts < TABLE_SIZE7)
534    table->num_entries = TABLE_SIZE7;
535  else if (nverts < TABLE_SIZE8)
536    table->num_entries = TABLE_SIZE8;
537  else if (nverts < TABLE_SIZE9)
538    table->num_entries = TABLE_SIZE9;
539  else if (nverts < TABLE_SIZE10)
540    table->num_entries = TABLE_SIZE10;
541  else if (nverts < TABLE_SIZE11)
542    table->num_entries = TABLE_SIZE11;
543  else if (nverts < TABLE_SIZE12)
544    table->num_entries = TABLE_SIZE12;
545  else if (nverts < TABLE_SIZE13)
546    table->num_entries = TABLE_SIZE13;
547  else if (nverts < TABLE_SIZE14)
548    table->num_entries = TABLE_SIZE14;
549  else if (nverts < TABLE_SIZE15)
550    table->num_entries = TABLE_SIZE15;
551  else if (nverts < TABLE_SIZE16)
552    table->num_entries = TABLE_SIZE16;
553  else if (nverts < TABLE_SIZE17)
554    table->num_entries = TABLE_SIZE17;
555  else if (nverts < TABLE_SIZE18)
556    table->num_entries = TABLE_SIZE18;
557  else if (nverts < TABLE_SIZE19)
558    table->num_entries = TABLE_SIZE19;
559  else
560    table->num_entries = TABLE_SIZE20;
561
562  table->verts = (Vertex **) malloc (sizeof (Vertex *) * table->num_entries);
563
564  /* set all table elements to NULL */
565  for (i = 0; i < table->num_entries; i++)
566    table->verts[i] = NULL;
567
568  /* place each point in table */
569
570  scale = 1 / size;
571  table->scale = scale;
572
573  return (table);
574}
575
576
577/******************************************************************************
578Read in the PLY file from standard in.
579******************************************************************************/
580
581void
582read_file(FILE *inFile, PlyObject &o)
583{
584  int i,j,k;
585  PlyFile *ply;
586  int nprops;
587  int num_elems;
588  char *elem_name;
589  float version;
590  PlyProperty **plist;
591
592
593  /*** Read in the original PLY object ***/
594  o.other_elements = NULL;
595
596  ply  = ply_read (inFile, &(o.nelems), &(o.elist));
597  ply_get_info (ply, &(version), &(o.file_type));
598
599  for (i = 0; i < o.nelems; i++) {
600
601    /* get the description of the first element */
602    elem_name = o.elist[i];
603    plist = ply_get_element_description(ply, elem_name, &num_elems, &nprops);
604
605    if (equal_strings ("vertex", elem_name)) {
606
607      /* create a vertex list to hold all the vertices */
608      o.vlist = (Vertex **) malloc (sizeof (Vertex *) * num_elems);
609      o.nverts = num_elems;
610
611      /* set up for getting vertex elements */
612
613      ply_get_property (ply, elem_name, &vert_props[0]);
614      ply_get_property (ply, elem_name, &vert_props[1]);
615      ply_get_property (ply, elem_name, &vert_props[2]);
616      o.vert_other = ply_get_other_properties (ply, elem_name,
617                                                offsetof(Vertex,other_props));
618
619      /* grab all the vertex elements */
620      for (j = 0; j < num_elems; j++) {
621        o.vlist[j] = (Vertex *) malloc (sizeof (Vertex));
622        ply_get_element (ply, (void *) o.vlist[j]);
623        o.vlist[j]->index = j;
624        o.vlist[j]->faces = NULL;
625      }
626     
627
628
629    }
630    else if (equal_strings ("face", elem_name)) {
631
632      /* create a list to hold all the face elements */
633      o.flist = (Face **) malloc (sizeof (Face *) * num_elems);
634      o.nfaces = num_elems;
635
636      /* set up for getting face elements */
637
638      ply_get_property (ply, elem_name, &face_props[0]);
639      o.face_other = ply_get_other_properties (ply, elem_name,
640                     offsetof(Face,other_props));
641
642      /* grab all the face elements */
643      for (j = 0; j < num_elems; j++) {
644        o.flist[j] = (Face *) malloc (sizeof (Face));
645        ply_get_element (ply, (void *) o.flist[j]);
646      }
647    }
648    else
649      o.other_elements = ply_get_other_element (ply, elem_name, num_elems);
650  }
651
652  o.comments = ply_get_comments (ply, &(o.num_comments));
653  o.obj_info = ply_get_obj_info (ply, &(o.num_obj_info));
654
655  ply_close (ply);
656}
657
658
659/******************************************************************************
660Write out the PLY file to standard out.
661******************************************************************************/
662
663void
664write_file(PlyObject &o)
665{
666  int i,j,k;
667  PlyFile *ply;
668  int num_elems;
669  char *elem_name;
670  int vert_count;
671  int face_count;
672
673  /*** Write out the final PLY object ***/
674
675
676  ply = ply_write (stdout, o.nelems, o.elist, o.file_type);
677
678  /* count the vertices that are in the hash table */
679
680  vert_count = 0;
681  for (i = 0; i < o.nverts; i++) {
682    if ((!DO_INTERSECTION && o.vlist[i]->nfaces > 0) || 
683        (DO_INTERSECTION && !(o.vlist[i]->nfaces > 0))) {
684      // renumber vertices.
685      o.vlist[i]->index = vert_count;
686      vert_count++;
687    }
688  }
689
690  /* count the faces that do not have matches */
691  face_count = 0;
692  for (i = 0; i < o.nfaces; i++) {
693    if ((!DO_INTERSECTION && o.flist[i]->has_match == false) ||
694        (DO_INTERSECTION && !(o.flist[i]->has_match == false))) {
695      face_count++;
696    }
697  }
698
699  /* describe what properties go into the vertex and face elements */
700
701  ply_element_count (ply, "vertex", vert_count);
702  ply_describe_property (ply, "vertex", &vert_props[0]);
703  ply_describe_property (ply, "vertex", &vert_props[1]);
704  ply_describe_property (ply, "vertex", &vert_props[2]);
705  ply_describe_other_properties (ply, o.vert_other, offsetof(Vertex,other_props));
706
707  ply_element_count (ply, "face", face_count);
708  ply_describe_property (ply, "face", &face_props[0]);
709  ply_describe_other_properties (ply, o.face_other, offsetof(Face,other_props));
710
711  ply_describe_other_elements (ply, o.other_elements);
712
713  for (i = 0; i < o.num_comments; i++)
714    ply_put_comment (ply, o.comments[i]);
715
716  for (i = 0; i < o.num_obj_info; i++)
717    ply_put_obj_info (ply, o.obj_info[i]);
718
719  ply_header_complete (ply);
720
721  /* set up and write the vertex elements */
722
723  ply_put_element_setup (ply, "vertex");
724
725  for (i = 0; i < o.nverts; i++) {
726    if ((!DO_INTERSECTION && o.vlist[i]->nfaces > 0) || 
727        (DO_INTERSECTION && !(o.vlist[i]->nfaces > 0))) {
728      ply_put_element (ply, (void *) o.vlist[i]);
729    }
730  }
731  /* set up and write the face elements */
732
733  ply_put_element_setup (ply, "face");
734
735  for (i = 0; i < o.nfaces; i++) {
736    if ((!DO_INTERSECTION && o.flist[i]->has_match == true) ||
737        (DO_INTERSECTION && !(o.flist[i]->has_match == true))) {
738      continue;
739    }
740    // Reset the numbering scheme
741    for (j = 0; j < o.flist[i]->nverts; j++) {
742      o.flist[i]->verts[j] = o.flist[i]->vptrs[j]->index;
743    }
744    // write out tri
745    ply_put_element (ply, (void *) o.flist[i]);
746  }
747
748  ply_put_other_elements (ply);
749
750  /* close the PLY file */
751  ply_close (ply);
752}
753
Note: See TracBrowser for help on using the repository browser.