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

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

Added original make3d

File size: 54.4 KB
Line 
1//
2// plyclean:
3// Clean up a ply file triangle mesh, getting rid
4// of degenerate triangles and slivers.
5//
6// Lucas Pereira, October 1998
7// A merging of Brian Curless' triedgecol and trisliver
8// programs.  Combined them into one program, because
9// we often want to do them both, and this cuts the file
10// i/o in half.
11//
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <math.h>
16#include <ply.h>
17#include <Linear.h>
18#include <string.h>
19#include <strings.h>
20
21#include "Mesh.h"
22#include "plyio.h"
23#include "undo.h"
24
25#ifdef linux
26#include <float.h>
27#endif
28
29//////////////////////////////////////////////////////////////////////
30// Define Variables, Helper Functions
31//////////////////////////////////////////////////////////////////////
32
33bool paranoid=FALSE;
34bool verbose=FALSE;
35bool quiet=FALSE;
36bool superQuiet=FALSE;
37
38// default values -- get overwritten
39float lengthThresh = 0.00035;
40float featureThresh = -1;
41float angleThresh = -1;
42
43// Options
44// If an argument is relative, then we need to compute mean edge length
45bool needMeanLength = FALSE;   
46// Meanlength = sum / weight
47float meanLengthSum=0.0;
48float meanLengthWt=0.0;
49float meanLength=0.0;
50
51// If this is true, then don't allow an edge collapse that will cause
52// a triangle to change normal drastically
53bool neverFlipTris = TRUE;
54float flipDotThresh = .5;
55
56// Never move boundary vertices?
57bool neverMoveBoundary = TRUE;
58
59// Global stat counters...
60int vertsDeleted = 0;
61int trisDeleted = 0;
62int edgesFlipped = 0;
63int trisUnkinked = 0;
64int trisUnfinned = 0;
65int prevVertsDeleted = 0;
66int prevTrisDeleted = 0;
67int prevEdgesFlipped = 0;
68int prevTrisUnkinked = 0;
69int prevTrisUnfinned = 0;
70
71// Usage
72void usage(char *progname);
73void RunCommands(Mesh *mesh, int argc, char **argv);
74
75// triedgecol Helper functions
76void collapse_mesh_edges(Mesh *mesh);
77void collapse_vert_edges(Vertex *vert);
78
79// trisliver Helper functions
80void remove_mesh_slivers(Mesh *mesh);
81// If returns true, then it also returns two
82// vertices to collapse
83bool shouldCollapseTri(Triangle *tri, Vertex **vcol1, Vertex **vcol2);
84
85// edgeflip Helper functions
86void flip_mesh_edges(Mesh *mesh);
87void flip_quad_edges(Vertex *v1, Vertex *v2, Vertex *v3, 
88                     Vertex *v4, Triangle *t1, Triangle *t2);
89
90// unkink helper functions
91void unkink_mesh_slivers(Mesh *mesh);
92Vertex *findSliverTop(Triangle *tri);
93bool facesBackward(Triangle *tri);
94void moveSliverTop(Vertex *slivertop);
95
96// unfin helper functions
97void unfin_mesh_slivers(Mesh *mesh);
98Triangle *findTwin(Triangle *tri);
99void removeFin(Triangle *tri1, Triangle *tri2);
100
101// both Helper functions
102Mesh *readMeshFromPly(FILE *inFile);
103void detectBoundaries(Mesh *mesh);
104bool updateNormal(Triangle *tri);
105int  collapse_edge(Vertex *v1, Vertex *v2);
106void count_verts_tris(Mesh *mesh, int *numVerts, int *numTris);
107void removeTriangleRefs(Triangle *tri);
108bool pruneNeighbors(Vertex *v);
109void CheckVertPointers(Vertex *vert, char *comment="");
110void replaceVert(Vertex *v1, Vertex *v2, Vertex *v3);
111void addTriangle(Vertex *vert, Triangle *tri);
112void delTriangle(Vertex *vert, Triangle *tri);
113void disconnectVert(Vertex *v1, Vertex *v2);
114void addVert(Vertex *v1, Vertex *v2);
115void addNeighbors(Vertex *v1, Vertex *v2);
116static void reallocTris(Vertex *v);
117static void reallocVerts(Vertex *v);
118
119
120void usage(char *progname)
121{
122  fprintf(stderr, "\n");
123  fprintf(stderr, "Usage: %s [options] [command sequence] [-o out.ply] [in.ply]\n",
124          progname);
125  fprintf(stderr, "   or: %s [options] [command sequence] < in.ply > out.ply\n",
126          progname);
127  fprintf(stderr, "\n");
128  fprintf(stderr, "Options:\n");
129  fprintf(stderr, "       -h prints usage\n");
130  fprintf(stderr, "       -v turns on verbose mode (not too useful)\n");
131  fprintf(stderr, "       -p turns on paranoid mode (lots of topology \n");
132  fprintf(stderr, "          checks, and warns of slightest suspicions..)\n");
133  fprintf(stderr, "       -q turns on quiet mode (paranoia is incompatible\n");
134  fprintf(stderr, "          with being quiet.)\n");
135  fprintf(stderr, "       -Q turns on superQuiet mode (paranoia is incompatible\n");
136  fprintf(stderr, "          with being quiet.)\n");
137  fprintf(stderr, "\n");
138  fprintf(stderr, "[command sequence] contains an unlimited number of the following operations:\n");
139  fprintf(stderr, "       -defaults\n");
140  //  fprintf(stderr, "       -keepbound (default -- don't allow boundary vertices to move)\n");
141  //  fprintf(stderr, "       -movebound (allow boundary vertices to move --NOT! (implemented))\n");
142  fprintf(stderr, "       -decimate <quality>\n");
143  fprintf(stderr, "          (Aggressively cleans, acting as decimator.  Quality should be a\n");
144  fprintf(stderr, "           number between 0 (destroy it) and 100 (do nothing).  It has no\n");
145  fprintf(stderr, "           guarantees how many polygons it will remove.)\n");
146  fprintf(stderr, "       -edgecol <edge-length> <feature-angle>\n");
147  fprintf(stderr, "          (collapses edges shorter than length, if surrounding tris are planar\n");
148  fprintf(stderr, "           to within feature-angle (180 collapses nothing, 0 everything).)\n");
149  fprintf(stderr, "       -edgeflip <feature-angle>\n");
150  fprintf(stderr, "          (Flips edges when the two triangles are planar within feature-angle,\n");
151  fprintf(stderr, "           and tesselating quad other way reduces max tri angle.)\n");
152  fprintf(stderr, "       -sliver  <max-angle>\n");
153  fprintf(stderr, "          (Edge-collapses smallest side of slivers with angle greater than max-angle)\n");
154  fprintf(stderr, "       -unkink <max-angle> <max-norm-diff>\n");
155  fprintf(stderr, "          (Moves 'top' vertex of slivers with angle greater than max-angle, if\n");
156  fprintf(stderr, "           it differs from EVERY neighbor by at least max-norm-diff.  CAUTION:\n");
157  fprintf(stderr, "           no safety checks. Might not fix problem, _might_ cause others.)\n");
158  fprintf(stderr, "       -unfin\n");
159  fprintf(stderr, "           removes fins (pairs of triangles that are mirrors of each other.)\n");
160  fprintf(stderr, "\n");
161  fprintf(stderr, "Examples:\n");
162  fprintf(stderr, "       %s -defaults a.ply > b.ply\n", progname);
163  fprintf(stderr, "       (does a set of ops designed to clean up marching cubes)\n");
164  fprintf(stderr, "\n");
165  fprintf(stderr, "       %s -decimate 50 a.ply > b.ply\n", progname);
166  fprintf(stderr, "       (does a set of ops designed to decimate mesh till it looks half as good)\n");
167  fprintf(stderr, "\n");
168  fprintf(stderr, "       %s -edgecol .6 150 a.ply > b.ply\n", progname);
169  fprintf(stderr, "       (collapses edges shorter than .6 units in length\n");
170  fprintf(stderr, "        that are more planar than 150 degrees)\n");
171  fprintf(stderr, "\n");
172  fprintf(stderr, "       %s -edgecol 40%% 170 -sliver 160 -edgecol .7 140 < a.ply > b.ply\n", 
173          progname);
174  fprintf(stderr, "       (Does a cautious edge-collapse (edges to 40%% of mean length),\n");
175  fprintf(stderr, "        remove slivers, and then another edge collapse)\n");
176  fprintf(stderr, "\n");
177  exit(-1);
178}
179
180int
181main(int argc, char **argv)
182{
183  int numVerts = 0, numTris = 0, i;
184  char *inName = NULL;
185  FILE *inFile = stdin;
186  char *outName = NULL;
187  FILE *outFile = stdout;
188  char *progname = argv[0];
189
190  // Print usage if no args, because this does nothing anyway
191  if (argc == 1) {
192    usage(progname);
193  }
194
195  // Read through the arguments, to make sure they're ok.
196  // Want to check bad args before we waste time reading the file...
197  // Also, identify the input file name, if given...
198  for (i=1; i < argc; i++) {
199    if (!strcmp(argv[i], "-h")) {
200      usage(progname);
201    } 
202    else if (!strcmp(argv[i], "-p")) {
203      paranoid = TRUE;
204      needMeanLength=TRUE;
205    } 
206    else if (!strcmp(argv[i], "-v")) {
207      verbose = TRUE;
208    } 
209    else if (!strcmp(argv[i], "-q")) {
210      quiet = TRUE;
211    } 
212    else if (!strcmp(argv[i], "-Q")) {
213      quiet = TRUE;
214      superQuiet = TRUE;
215    } 
216    else if (!strcmp(argv[i], "-o")) {
217      if (argc-i < 2) usage(progname);
218      if (argv[i+1][0] == '-') {
219        fprintf(stderr, "Error: -o should be followed by a file name...\n");
220        usage(progname);
221      }
222      outName = argv[i+1];
223      i++;
224    } 
225    else if (!strcmp(argv[i], "-edgecol")) {
226      if (argc-i < 3) usage(progname);
227      if (!quiet) {
228        fprintf(stderr, "Will run edge collapse, edge length=%s, "
229                "feature angle = %s\n", argv[i+1], argv[i+2]);
230      }
231      if (argv[i+1][strlen(argv[i+1])-1] == '%') needMeanLength = TRUE;
232      i += 2;
233    } 
234    else if (!strcmp(argv[i], "-sliver")) {
235      if (argc-i < 2) usage(progname);
236      if (!quiet) {
237        fprintf(stderr, "Will run sliver removal, max tri angle=%s\n",
238                argv[i+1]);
239      }
240      i++;
241    } 
242    else if (!strcmp(argv[i], "-edgeflip")) {
243      if (argc-i < 2) usage(progname);
244      if (!quiet) {
245        fprintf(stderr, "Will run Edge flip, max feature angle = %s\n",
246                argv[i+1]);
247      }
248      i++;
249    } 
250    else if (!strcmp(argv[i], "-unkink")) {
251      if (argc-i < 3) usage(progname);
252      if (!quiet) {
253        fprintf(stderr, "Will run unkink, max tri angle = %s, "
254                "max feature angle = %s\n",
255                argv[i+1], argv[i+2]);
256      }
257      i+=2;
258    } 
259    else if (!strcmp(argv[i], "-unfin")) {
260      if (!quiet) {
261        fprintf(stderr, "Will run unfin.\n");
262      }
263      i += 0;
264    } 
265    else if (!strcmp(argv[i], "-defaults")) {
266      if (!quiet) {
267        fprintf(stderr, "Will run defaults (for post-marching-cubes)\n");
268      }
269      i += 0;
270      needMeanLength = TRUE;
271    } 
272    else if (!strcmp(argv[i], "-decimate")) {
273      if (argc-i < 2) usage(progname);
274      float quality = atof(argv[i+1]);
275      // Check that the quality arg is reasonable.
276      if (quality <= 0 || quality >= 100) {
277        fprintf(stderr, "Error, decimate quality must be between 0 and 100.\n");
278        usage(progname);
279        exit(-1);
280      }
281      if (!quiet) {
282        fprintf(stderr, "Will run decimation, quality %.1f%%\n", quality);
283      }
284      i += 1;
285      needMeanLength = TRUE;
286    } 
287    /*
288    else if (!strcmp(argv[i], "-keepbound")) {
289      // print nothing
290    }
291    else if (!strcmp(argv[i], "-movebound")) {
292      // print nothing
293    }
294    */
295    else if (argv[i][0] != '-' && inName == NULL) {
296      inName = argv[i];
297      inFile = fopen(inName, "r");
298      if (inFile == NULL) {
299        fprintf(stderr, "Error: Could not open input ply file %s\n", inName);
300        usage(progname);
301        exit(-1);
302      }
303    } 
304    else {
305      fprintf(stderr, "Error:  Unhandled arg: %s\n", argv[i]);
306      usage(progname);
307      exit(-1);
308    }
309  }
310
311  // Now actually read in the input ply file...
312  if (!quiet) {
313    fprintf(stderr, "Reading input from %s...\n", 
314            (inName == NULL) ? "<stdin>" : inName);
315  }
316
317  Mesh *mesh = readMeshFromPly(inFile);
318
319  // Run through the args a second time, actually executing the
320  // commands
321  RunCommands(mesh, argc, argv);
322
323  // Count the number of vertices/triangles actually used
324  count_verts_tris(mesh, &numVerts, &numTris);
325 
326  if (!quiet) {
327    fprintf(stderr, "Writing file %s...\n", 
328            (outName == NULL)? "<stdout>" : outName);
329  }
330 
331  // Write out.  Pass along active numbers for ply header.
332  if (outName != NULL) {
333    outFile = fopen(outName, "w");
334    if (outFile == NULL) {
335      fprintf(stderr, "Error: Could not open output ply file %s\n", outName);
336      usage(progname);
337      exit(-1);
338    }   
339  }
340  writePlyFile(outFile, mesh, numVerts, numTris);
341 
342  return 0;
343}
344
345void RunCommands(Mesh *mesh, int argc, char **argv)
346{
347  int i;
348  for (i=1; i < argc; i++) {
349    if (!strcmp(argv[i], "-edgecol")) {
350      float lengthThresh_orig = atof(argv[i+1]);
351      // If relative ( X% )
352      if (argv[i+1][strlen(argv[i+1])-1] == '%') {
353        // Make the length relative to the mean...
354        lengthThresh_orig *= 0.01 * meanLength;
355      }
356      float angle = atof(argv[i+2]);
357      featureThresh = cos(M_PI/180*(180-angle));
358      lengthThresh = lengthThresh_orig;
359
360      // reset stat counters
361      prevVertsDeleted = vertsDeleted;
362      prevTrisDeleted = trisDeleted;
363
364      // Collapse the Edges
365      if (!quiet)
366        fprintf(stderr, "Collapsing edges (%f,%s deg)... ", lengthThresh, argv[i+2]);
367
368      collapse_mesh_edges(mesh);
369      i += 2;
370
371      if (!quiet)
372        fprintf(stderr, "%d verts (%d tris) removed.\n", 
373                vertsDeleted-prevVertsDeleted, 
374                trisDeleted -prevTrisDeleted);
375    } 
376    else if (!strcmp(argv[i], "-sliver")) {
377
378      float angle = atof(argv[i+1]);
379      angleThresh = cos(M_PI/180.*(180.-angle));
380      featureThresh = -1.0;
381
382
383      // reset stat counters
384      prevVertsDeleted = vertsDeleted;
385      prevTrisDeleted = trisDeleted;
386
387      // Remove the Slivers
388      if (!quiet)
389        fprintf(stderr, "Removing slivers (%s deg)... ", argv[i+1]);
390     
391      remove_mesh_slivers(mesh);
392      i++;
393
394      if (!quiet)
395        fprintf(stderr, "%d verts (%d tris) removed.\n", 
396                vertsDeleted-prevVertsDeleted, 
397                trisDeleted -prevTrisDeleted);
398    } 
399    else if (!strcmp(argv[i], "-edgeflip")) {
400      float angle = atof(argv[i+1]);
401      featureThresh = cos(M_PI/180.*(180.-angle));
402
403      // reset stat counters
404      prevEdgesFlipped = edgesFlipped;
405
406      // Flip the Edges
407      if (!quiet)
408        fprintf(stderr, "Flipping Edges... ");
409
410      flip_mesh_edges(mesh);
411      i++;
412     
413      if (!quiet)
414        fprintf(stderr, "%d edges flipped.\n", edgesFlipped);
415
416    } 
417    else if (!strcmp(argv[i], "-unkink")) {
418      float angle = atof(argv[i+1]);
419      angleThresh = cos(M_PI/180.*(180.-angle));
420      angle = atof(argv[i+2]);
421      // Note below, angle, not 180-angle
422      featureThresh = cos(M_PI/180.*(angle));
423
424      // reset stat counters
425      prevTrisUnkinked = trisUnkinked;
426
427      // Unkink...
428      if (!quiet)
429        fprintf(stderr, "Unkinking sliver tris... ");
430
431      unkink_mesh_slivers(mesh);
432      i+=2;
433     
434      if (!quiet)
435        fprintf(stderr, "%d tris unkinked.\n", trisUnkinked);
436    }
437    else if (!strcmp(argv[i], "-unfin")) {
438      // reset stat counters
439      prevTrisUnfinned = trisUnfinned;
440     
441      // Unfin...
442      if (!quiet)
443        fprintf(stderr, "Unfinning twin tris... ");
444
445      unfin_mesh_slivers(mesh);
446     
447      if (!quiet)
448        fprintf(stderr, "%d tris unfinned.\n", trisUnfinned);
449
450    } 
451    else if (!strcmp(argv[i], "-defaults")) {
452      char *newargs[] = {"plyclean", 
453                         "-edgecol", "10%", "0", 
454                         "-sliver", "165",
455                         "-edgecol", "35%", "155", 
456                         "-edgecol", "50%", "165", 
457                         "-sliver", "165", 
458                         "-edgecol", "65%", "170", 
459                         "-edgecol", "20%", "0", 
460                         "-sliver", "170", 
461                         "-edgecol", "20%", "0"}; 
462      int newargc = sizeof(newargs)/sizeof(char *);
463      if (!quiet) 
464        fprintf(stderr, "running defaults...\n");
465      RunCommands(mesh, newargc, newargs);
466    }
467    else if (!strcmp(argv[i], "-decimate")) {
468      // Get the quality number, between 0 and 100
469      float quality = atof(argv[i+1]);
470      // Now figure out the max edge length we'll produce:
471      // qual=100 -> maxedgelen = 0
472      // qual= 50 -> maxedgelen = 100%
473      // qual= 25 -> maxedgelen = 300%
474      // qual=  0 -> maxedgelen = infinity
475      float maxEdgeLen = 100 * ((100 - quality) / quality);
476      // And figure out the max angle feature we'll mess with:
477      // qual= 100 -> maxAng = 180
478      // qual= 50 -> maxAng = 154
479      // qual= 25 -> maxAng = 120
480      float maxAng = 180 * (1.20*quality / (20+ quality));
481
482      // Allocate arrays where we'll fill in the args...
483      char edgeLens[10][100];
484      char edgeAngs[10][100];
485
486      int nEdgeIters = 7;
487      // edgelength factor to do each iteration.  Make this grow
488      // geometrically (each number is 43% bigger...)
489      float edgeLenFactor[] = {.12, .17, .24, .34, .49, .70, 1.00};
490      float edgeAngFactor[] = {1.0, .95, .90, .82, .75, .65, .50};
491      for (int edgeIter = 0; edgeIter < nEdgeIters; edgeIter++) {
492        // edgelen linearly increases to maxedgelen...
493        sprintf(&(edgeLens[edgeIter][0]), "%f%%", maxEdgeLen * edgeLenFactor[edgeIter]);
494        // edgeAngs falls, so that bigger features get less blurred
495        sprintf(&(edgeAngs[edgeIter][0]), "%f", ((1.0 - edgeAngFactor[edgeIter]) * 180 +
496                                                 (edgeAngFactor[edgeIter]) * maxAng));
497      }
498
499      // Do a couple sliver removals...
500      char sliverAng[100];
501      // sliver angle is 2/3 of the way from maxAng to 180...
502      sprintf(&(sliverAng[0]), "%f", 120 + maxAng / 3);
503
504      char *newargs[] = {"plyclean", 
505                         "-edgecol", &(edgeLens[0][0]), &(edgeAngs[0][0]),
506                         "-edgecol", &(edgeLens[1][0]), &(edgeAngs[1][0]),
507                         "-sliver", &(sliverAng[0]),
508                         "-edgecol", &(edgeLens[2][0]), &(edgeAngs[2][0]),
509                         "-edgecol", &(edgeLens[3][0]), &(edgeAngs[3][0]),
510                         "-sliver", &(sliverAng[0]),
511                         "-edgecol", &(edgeLens[4][0]), &(edgeAngs[4][0]),
512                         "-edgecol", &(edgeLens[5][0]), &(edgeAngs[5][0]),
513                         "-sliver", &(sliverAng[0])};
514
515      int newargc = sizeof(newargs)/sizeof(char *);
516      if (!quiet) 
517        fprintf(stderr, "running decimate %.1f%%...\n", quality);
518      RunCommands(mesh, newargc, newargs);
519    }
520    else if (!strcmp(argv[i], "-keepbound")) {
521      neverMoveBoundary = TRUE;
522    }
523    else if (!strcmp(argv[i], "-movebound")) {
524      neverMoveBoundary = FALSE;
525    }
526    else if (!strcmp(argv[i], "-v")) {
527      // verbose already turned on, skip....
528    } 
529    else if (!strcmp(argv[i], "-p")) {
530      // paranoid already turned on, skip....
531    } 
532    else if (!strcmp(argv[i], "-q")) {
533      // quiet already turned on, skip....
534    } 
535    else if (!strcmp(argv[i], "-Q")) {
536      // superQuiet already turned on, skip....
537    } 
538    else if (!strcmp(argv[i], "-o")) {
539      // output file already handled
540      i++;
541    } 
542    else if (argv[i][0] != '-') {
543      // Skip input filename arg -- already opened...
544    } 
545    else {
546      fprintf(stderr, "Bad Arg uncaught in first pass: %s\n", argv[i]);
547      usage("plyclean");
548      exit(-1);
549    }
550  }
551}
552
553
554//////////////////////////////////////////////////////////////////////
555// triedgecol helper functions
556//////////////////////////////////////////////////////////////////////
557
558void
559collapse_mesh_edges(Mesh *mesh)
560{
561  Vertex *vert;
562  int i, j;
563 
564  /* Cycle over vertices and collapse edges */
565
566  for (i = 0; i < mesh->numVerts; i++) {
567    vert = &mesh->verts[i];
568    // Invalidate vertex if it has no triangles...
569    if (vert->numTris == 0) {
570      vert->index = -1;
571      if (vert->numVerts > 0) {
572        if (paranoid)
573          fprintf(stderr, "Potential problem:  Vertex "
574                  "%d has 0 tris, and %d neighbor verts...(fixing)\n", 
575                  vert->index, vert->numVerts);
576        for (j = 0; j < vert->numVerts; j++) {
577          disconnectVert(vert->verts[j], vert);
578          disconnectVert(vert, vert->verts[j]);
579        }
580        vert->numVerts = 0;
581      }
582    } 
583    if (vert->index < 0)
584      continue;
585
586    if (paranoid) CheckVertPointers(vert, "before");
587
588    collapse_vert_edges(vert);
589
590    if (paranoid) CheckVertPointers(vert, "after");
591  }
592}
593
594
595void
596collapse_vert_edges(Vertex *vert)
597{
598  int i;
599  Vertex *other;
600  Vec3f vedge;
601  float length;
602   
603  // Cycle over nearest neighbors and possibly remove edge
604  // if too short
605  for (i = 0; i < vert->numVerts; i++) {
606    other = vert->verts[i];
607    vedge = vert->coord - other->coord;
608    length = vedge.length();
609    if (length < lengthThresh) {
610      if (collapse_edge(vert, other)) {
611        // reset i -- basically a new vertex, now...
612        i=-1;   
613      }
614    }   
615  }
616}
617
618//////////////////////////////////////////////////////////////////////
619// trisliver helper functions
620//////////////////////////////////////////////////////////////////////
621
622void
623remove_mesh_slivers(Mesh *mesh)
624{
625  Triangle *tri;
626  int i;
627  Vertex *vcollapse1=NULL, *vcollapse2=NULL;
628 
629  // Check each triangle to see if it's a sliver
630  for (i = 0; i < mesh->numTris; i++) {
631    tri = &mesh->tris[i];
632
633    // Check to make sure it's a valid triangle...
634    if (tri->vert1 != tri->vert2 &&
635        tri->vert1 != tri->vert3 &&
636        tri->vert2 != tri->vert3 &&
637        tri->vert1->index > -1 &&
638        tri->vert2->index > -1 &&
639        tri->vert3->index > -1) {
640
641      // If it is a sliver, shouldCollapseTri returns true, and
642      // fills the vertex pointers with the two vertices to be
643      // collapsed.
644      if (shouldCollapseTri(tri, &vcollapse1, &vcollapse2)) {
645       
646        if (paranoid) {
647          CheckVertPointers(vcollapse1, "v1 slivers before");
648          CheckVertPointers(vcollapse2, "v2 slivers before");
649        }
650       
651        if (collapse_edge(vcollapse1, vcollapse2))
652          i--;
653        if (paranoid) {
654          CheckVertPointers(vcollapse1, "v1 slivers after");
655          CheckVertPointers(vcollapse2, "v2 slivers after");
656        }
657
658      }
659    }
660  }
661}
662
663
664bool shouldCollapseTri(Triangle *tri, Vertex **vcol1, Vertex **vcol2)
665{
666   Vec3f vedge1, vedge2, vedge3;
667   float len1, len2, len3, dot1, dot2, dot3;
668
669   vedge1 = tri->vert1->coord - tri->vert2->coord;
670   vedge2 = tri->vert2->coord - tri->vert3->coord;
671   vedge3 = tri->vert3->coord - tri->vert1->coord;
672
673   len1 = vedge1.length();
674   len2 = vedge2.length();
675   len3 = vedge3.length();
676
677   // normalize edges...
678   vedge1 /= len1;
679   vedge2 /= len2;
680   vedge3 /= len3;
681
682   dot1 = vedge1.dot(vedge2);
683   dot2 = vedge2.dot(vedge3);
684   dot3 = vedge3.dot(vedge1);
685
686   // If any of the 3 corners are bigger than the threshold angle,
687   // then return the shortest edge.  This, by the law of signs,
688   // must be adjacent to the largest angle, not opposite it....
689   if (dot1 > angleThresh || dot2 > angleThresh || dot3 > angleThresh) {
690     // Find the shortest edge, set the vcol pointers to be
691     // the vertex on either end...
692     if (len1 < len2 && len1 < len3) {
693       *vcol1 = tri->vert1;
694       *vcol2 = tri->vert2;
695     }
696     else if (len2 < len1 && len2 < len3) {
697       *vcol1 = tri->vert2;
698       *vcol2 = tri->vert3;
699     }
700     else { // (len3 < len2 && len3 < len1)
701       *vcol1 = tri->vert1;
702       *vcol2 = tri->vert3;
703     }
704     return(TRUE);
705   } else {
706     // All angles are below threshold -- no need to collapse
707     return(FALSE);
708   }
709}
710
711//////////////////////////////////////////////////////////////////////
712// edgeflip helper functions
713//////////////////////////////////////////////////////////////////////
714
715void flip_mesh_edges(Mesh *mesh)
716{
717  Vertex *v1, *v2, *v3, *v4;
718  int i, j, k;
719  Triangle *t;
720  Triangle *t1, *t2;
721   
722  // Cycle over the vertices, and find each edge that is shared by
723  // two triangles.  In particular, it assumes that the vertices
724  // are ordered in this way:
725  //
726  //     v1---v3
727  //      \   | \
728  //       \T1|T2\
729  //        \ |   \
730  //         v2---v4
731  //
732  // And it will consider whether or not it would be better to
733  // re-tesselate it as:
734  //
735  //     v1---v3
736  //      \`. T2\
737  //       \ `.  \
738  //        \T1`. \
739  //         v2--`v4
740  //
741
742  for (i = 0; i < mesh->numVerts; i++) {
743    v2 = &mesh->verts[i];
744    if (v2->index == -1) continue;
745
746    // Try each neighbor.  Consider only neighbors numbered
747    // higher, so we don't consider the edge twice.
748    for (j=0; j < v2->numVerts; j++) {
749      v3 = v2->verts[j];
750      if (v3->index <= v2->index) continue;
751      if (v3->index == -1) continue;
752      v1 = NULL;
753      v4 = NULL;
754      int numfound = 0;
755
756      // Now try to find the other two vertices...
757      for (k=0; k < v2->numTris; k++) {
758        t = v2->tris[k];
759        // Look for v1
760        if (t->vert1->index == v2->index &&
761            t->vert2->index == v3->index) {
762          v1 = t->vert3;
763          t1 = t;
764          numfound++;
765        } 
766        else if (t->vert2->index == v2->index &&
767                 t->vert3->index == v3->index) {
768          v1 = t->vert1;
769          t1 = t;
770          numfound++;
771        } 
772        else if (t->vert3->index == v2->index &&
773                 t->vert1->index == v3->index) {
774          v1 = t->vert2;
775          t1 = t;
776          numfound++;
777        } 
778        // Look for v4
779        if (t->vert2->index == v2->index &&
780            t->vert1->index == v3->index) {
781          v4 = t->vert3;
782          t2 = t;
783          numfound++;
784        } 
785        else if (t->vert3->index == v2->index &&
786                 t->vert2->index == v3->index) {
787          v4 = t->vert1;
788          t2 = t;
789          numfound++;
790        } 
791        else if (t->vert1->index == v2->index &&
792                 t->vert3->index == v3->index) {
793          v4 = t->vert2;
794          t2 = t;
795          numfound++;
796        } 
797      }
798
799      if (numfound != 2) {
800        // the edge is not shared by exactly two triangles....
801        if (paranoid) {
802          fprintf(stderr, "Cannot flip edge %d %d, shared by %d tris.\n",
803                  v2->index, v3->index, numfound);
804        }
805        continue;
806      }
807
808      flip_quad_edges(v1, v2, v3, v4, t1, t2);
809    }
810  }
811}
812
813void flip_quad_edges(Vertex *v1, Vertex *v2, Vertex *v3, 
814                     Vertex *v4, Triangle *t1, Triangle *t2)
815{
816  // See diagram in the function above for the meaning of the
817  // input args.  Basically, try to see if we should replace
818  // the 2-3 edge with a 1-4 edge.  If so, t1 and t2 would
819  // take on the new meanings...
820
821  if (paranoid) {
822    CheckVertPointers(v1, "v1 before flipedge");
823    CheckVertPointers(v2, "v2 before flipedge");
824    CheckVertPointers(v3, "v3 before flipedge");
825    CheckVertPointers(v4, "v4 before flipedge");
826  }
827
828  // First, make sure that the two are basically coplanar
829  float normdot = t1->norm.dot(t2->norm);
830  if (normdot < featureThresh) {
831    // Not planar enough -- throw it away
832    return;
833  }
834
835  // And make sure that v1 and v4 are not already connected by
836  // a triangle, because if so, and we add two more triangles,
837  // we'll have an edge with more than two triangles....
838  for (int i =0; i < v1->numVerts; i++) {
839    if (v1->verts[i] == v4) {
840      // Dohp!
841      if (verbose) {
842        fprintf(stderr, 
843                "Cannot flip edge %d %d, because %d and %d "
844                "are already connected.\n",
845                v2->index, v3->index, v1->index, v4->index);
846      }
847      return;
848    }
849  }
850
851  Vec3f vedge12 = v2->coord - v1->coord;
852  Vec3f vedge24 = v4->coord - v2->coord;
853  Vec3f vedge43 = v3->coord - v4->coord;
854  Vec3f vedge31 = v1->coord - v3->coord;
855  vedge12.normalize();
856  vedge24.normalize();
857  vedge43.normalize();
858  vedge31.normalize();
859
860  // Compute the cosine of the angle of the quadrilateral at
861  // each vertex....
862  float cos1 = -(vedge12.dot(vedge31));
863  float cos2 = -(vedge24.dot(vedge12));
864  float cos4 = -(vedge43.dot(vedge24));
865  float cos3 = -(vedge31.dot(vedge43));
866
867  // If the widest angle is at vertex 1 or 4...
868  if ((cos1 < cos2 && cos1 < cos3) ||
869      (cos4 < cos2 && cos4 < cos3)) {
870
871    // Disconnect v2 and v3
872    disconnectVert(v2, v3);
873    disconnectVert(v3, v2);
874   
875    // Connect v1 and v4
876    addVert(v1, v4);
877    addVert(v4, v1);
878
879    // Reassign the triangles to point to the new vertices
880    if      (t1->vert1->index == v3->index) t1->vert1 = v4;
881    else if (t1->vert2->index == v3->index) t1->vert2 = v4;
882    else if (t1->vert3->index == v3->index) t1->vert3 = v4;
883    else fprintf(stderr, "Hey, t1 doesn't touch v3????\n");
884
885    if      (t2->vert1->index == v2->index) t2->vert1 = v1;
886    else if (t2->vert2->index == v2->index) t2->vert2 = v1;
887    else if (t2->vert3->index == v2->index) t2->vert3 = v1;
888    else fprintf(stderr, "Hey, t2 doesn't touch v2????\n");
889
890    // Reassign the vertices to point to their triangles
891    addTriangle(v1, t2);
892    delTriangle(v2, t2);
893    delTriangle(v3, t1);
894    addTriangle(v4, t1);
895
896    // Check... should not be needed, but prints debug...
897    if (paranoid) {
898      bool pruned = FALSE;
899      pruned |= pruneNeighbors(v1);
900      pruned |= pruneNeighbors(v2);
901      pruned |= pruneNeighbors(v3);
902      pruned |= pruneNeighbors(v4);
903      if (pruned) {
904        fprintf(stderr, "Flip edges: doing edge %d--%d, pruned neighbors.\n",
905                v2->index, v3->index);
906      }
907    }
908
909    // Recompute the normals...
910    updateNormal(t1);
911    updateNormal(t2);
912
913    edgesFlipped++;
914  }
915
916  if (paranoid) {
917    CheckVertPointers(v1, "v1 after flipedge");
918    CheckVertPointers(v2, "v2 after flipedge");
919    CheckVertPointers(v3, "v3 after flipedge");
920    CheckVertPointers(v4, "v4 after flipedge");
921  }
922
923}
924
925//////////////////////////////////////////////////////////////////////
926// unkink helper functions
927//////////////////////////////////////////////////////////////////////
928
929// Detect sliver triangles with normals that differ significantly
930// from every other triangle.  If so, do something about it...
931void 
932unkink_mesh_slivers(Mesh *mesh)
933{
934  int i;
935  Triangle *tri;
936
937  // Loop through all the triangles
938  for (i = 0; i < mesh->numTris; i++) {
939    tri = &mesh->tris[i];
940
941    // Check to make sure it's a valid triangle...
942    if (tri->vert1 != tri->vert2 &&
943        tri->vert1 != tri->vert3 &&
944        tri->vert2 != tri->vert3 &&
945        tri->vert1->index > -1 &&
946        tri->vert2->index > -1 &&
947        tri->vert3->index > -1) {
948
949      // findSliverTOP returns NULL if it ain't a sliver
950      Vertex *slivertop = findSliverTop(tri);
951
952      if (slivertop != NULL && !(slivertop->onBoundary) &&
953          facesBackward(tri)) {
954        // Move slivertop towards its neighbors.  This routine is
955        // also expected to update the relevant normals of any
956        // triangles that touch the vertex that mooooooved.
957        moveSliverTop(slivertop);
958        trisUnkinked++;
959
960        if (paranoid) {
961          CheckVertPointers(tri->vert1, "tri->vert1 after");
962          CheckVertPointers(tri->vert2, "tri->vert2 after");
963          CheckVertPointers(tri->vert3, "tri->vert3 after");
964        }
965
966      }
967    }
968  }
969}
970
971// This function detects slivers.  If so, it returns the vertex
972// at the top (wide angle) of the sliver.  If not, returns null.
973Vertex *
974findSliverTop(Triangle *tri)
975{
976   Vec3f vedge1, vedge2, vedge3;
977   float len1, len2, len3, dot1, dot2, dot3;
978
979   vedge1 = tri->vert1->coord - tri->vert2->coord;
980   vedge2 = tri->vert2->coord - tri->vert3->coord;
981   vedge3 = tri->vert3->coord - tri->vert1->coord;
982
983   len1 = vedge1.length();
984   len2 = vedge2.length();
985   len3 = vedge3.length();
986
987   // normalize edges...
988   vedge1 /= len1;
989   vedge2 /= len2;
990   vedge3 /= len3;
991
992   // Check each angle, one by one, to see if its over thresh
993   if (vedge1.dot(vedge2) > angleThresh) return tri->vert2;
994   else if (vedge2.dot(vedge3) > angleThresh) return tri->vert3;
995   else if (vedge3.dot(vedge1) > angleThresh) return tri->vert1;
996   else return NULL;
997}
998
999// This function compares the tri to all of its neighbors.
1000// If it differs from ALL of its neighbors by a certain amount,
1001// then it is considered "backward-facing".
1002bool 
1003facesBackward(Triangle *tri)
1004{
1005  // for all the vertices
1006  for (int i=0; i < 3; i++) {
1007    Vertex *v = ((i==0) ? tri->vert1 :
1008                 (i==1) ? tri->vert2 :
1009                 tri->vert3);
1010    // for all the triangles
1011    for (int j=0; j < v->numTris; j++) {
1012      Triangle *tri2 = v->tris[j];
1013      if (tri2 == tri) continue;
1014      // if normals are too similar, return false (not backward)
1015      if (tri2->norm.dot(tri->norm) > featureThresh) {
1016        return false;
1017      }
1018    }
1019  }
1020
1021  // If we make it to here, it was sufficiently different to be
1022  // considered backfacing
1023  return true;
1024}
1025
1026// This function actually moves the vertex to be more centered
1027// around its neighbors, thus (in theory) fixing the sliver.
1028void 
1029moveSliverTop(Vertex *slivertop)
1030{
1031  // Compute another point, which is the average of all its neighbors
1032  Vec3f avg(0,0,0);
1033
1034  int i;
1035  for (i=0; i < slivertop->numVerts; i++) {
1036    avg += slivertop->verts[i]->coord;
1037  }     
1038  avg /= slivertop->numVerts;
1039 
1040  // lerp slivertop and avg
1041  slivertop->coord = (slivertop->coord + avg);
1042  slivertop->coord *= 0.5;
1043  // Recompute normals
1044  for (i=0; i < slivertop->numTris; i++) {
1045    updateNormal(slivertop->tris[i]);
1046  }
1047}
1048
1049//////////////////////////////////////////////////////////////////////
1050// unfin helper functions
1051//////////////////////////////////////////////////////////////////////
1052
1053// Detect pairs of triangles that are fins (mirror images of each other),
1054// and remove them both.
1055void 
1056unfin_mesh_slivers(Mesh *mesh)
1057{
1058  int i;
1059  Triangle *tri;
1060
1061  // Loop through all the triangles
1062  for (i = 0; i < mesh->numTris; i++) {
1063    tri = &mesh->tris[i];
1064
1065    // Check to make sure it's a valid triangle...
1066    if (tri->vert1 != tri->vert2 &&
1067        tri->vert1 != tri->vert3 &&
1068        tri->vert2 != tri->vert3 &&
1069        tri->vert1->index > -1 &&
1070        tri->vert2->index > -1 &&
1071        tri->vert3->index > -1) {
1072
1073      // findTwin returns NULL if no twin exists
1074      Triangle *twin = findTwin(tri);
1075
1076      if (twin != NULL) {
1077        removeFin(tri, twin);
1078
1079        if (paranoid) {
1080          CheckVertPointers(tri->vert1, "tri->vert1 after");
1081          CheckVertPointers(tri->vert2, "tri->vert2 after");
1082          CheckVertPointers(tri->vert3, "tri->vert3 after");
1083        }
1084
1085      }
1086    }
1087  }
1088}
1089
1090// This function looks for a "twin" of the current triangle --
1091// e.g. a triangle that has the same vertices, but in the
1092// opposite order.
1093Triangle *
1094findTwin(Triangle *tri)
1095{
1096  bool twinfound = false;
1097  Vertex *v1 = tri->vert1;
1098  Vertex *v2 = tri->vert2;
1099  Vertex *v3 = tri->vert3;
1100
1101  // Loop through all the adjacent triangles of the
1102  // vertex with the fewest neighbors.
1103  Vertex *visolated = ((v1->numTris < v2->numTris) ? 
1104                       ((v1->numTris < v3->numTris) ? v1 : v3) :
1105                       ((v2->numTris < v3->numTris) ? v2 : v3));
1106  Triangle *tri2;
1107
1108  for (int j = 0; j < visolated->numTris; j++) {
1109    tri2 = visolated->tris[j];
1110    if (tri2 == tri) continue;
1111
1112    twinfound = 
1113      ((v1 == tri2->vert3) && (v2 == tri2->vert2) && (v3 == tri2->vert1)) ||
1114      ((v1 == tri2->vert2) && (v2 == tri2->vert1) && (v3 == tri2->vert3)) ||
1115      ((v1 == tri2->vert1) && (v2 == tri2->vert3) && (v3 == tri2->vert2));
1116    if (twinfound) {
1117      return tri2;
1118    }
1119  }
1120
1121  // if we get here, no twinfound
1122  return NULL;
1123}
1124
1125// This function removes the two twins.
1126void
1127removeFin(Triangle *tri1, Triangle *tri2)
1128{
1129 
1130  // Disconnect the 3 pairs of vertices, if another
1131  // triangle doesn't exist.
1132  Vertex *v1 = tri1->vert1;
1133  Vertex *v2 = tri1->vert2;
1134  Vertex *v3 = tri1->vert3;
1135 
1136  // Local vars for disconnecting verts
1137  int i;
1138  Triangle *tri3;
1139  bool shouldDisconnect;
1140  Vertex *vv1, *vv2;
1141 
1142  // Run through all the triangles of vv1.  If we find a third
1143  // triangle connecting vv1 and vv2, don't disconnect them.
1144  // (Iterate 3 times, for all v1/v2....
1145  for (int j=0; j < 3; j++) {
1146    // depending on j, set virtual v1 and vv2 to be one of
1147    // the three combinations of pairs.
1148    if (j == 0)    { vv1 = v1; vv2 = v2; }
1149    else if (j==1) { vv1 = v1; vv2 = v3; }
1150    else           { vv1 = v2; vv2 = v3; }
1151
1152    shouldDisconnect = true;
1153    for (i=0; i < vv1->numTris; i++) {
1154      tri3 = vv1->tris[i];
1155      if (tri3 != tri1 && tri3 != tri2 &&
1156          (tri3->vert1 == vv2 || 
1157           tri3->vert2 == vv2 ||
1158           tri3->vert3 == vv2)) {
1159        shouldDisconnect = false;
1160        break;
1161      }
1162    }
1163    if (shouldDisconnect) {
1164      disconnectVert(vv1, vv2);
1165      disconnectVert(vv2, vv1);
1166    }   
1167  }
1168
1169  removeTriangleRefs(tri1);
1170  removeTriangleRefs(tri2);
1171  trisUnfinned += 2;
1172  trisDeleted += 2; 
1173 
1174  // At this point, Look at each vertex.  If it has zero
1175  // triangles, Set the vertex index to -1...
1176  if (v1->numTris == 0) { v1->index = -1; vertsDeleted++; }
1177  if (v2->numTris == 0) { v2->index = -1; vertsDeleted++; }
1178  if (v3->numTris == 0) { v3->index = -1; vertsDeleted++; }
1179}
1180
1181
1182//////////////////////////////////////////////////////////////////////
1183// General functions
1184//////////////////////////////////////////////////////////////////////
1185
1186
1187// count_verts_tris:
1188// At the very end, before we write out the ply header,
1189// we need to figure out how many vertices and triangles
1190// are left. 
1191void
1192count_verts_tris(Mesh *mesh, int *numVerts, int *numTris)
1193{
1194  Triangle *tri;
1195  Vertex *vert;
1196  int count, i;
1197
1198  // Count vertices, reassign indices so they are contiguous
1199  count = 0;
1200  for (i = 0; i < mesh->numVerts; i++) {
1201    vert = &mesh->verts[i];
1202   
1203    if (paranoid) {
1204      CheckVertPointers(vert, "Counting verts");
1205    }
1206
1207    // Toss out verts without tris
1208    if (vert->numTris == 0 && vert->index != -1) {
1209      if (paranoid) {
1210        fprintf(stderr, "Tossing out vertex %d, has 0 triangles...\n",
1211                vert->index);
1212      }
1213      vert->index = -1;
1214    }
1215    // Count it if valid
1216    if (vert->index != -1) {
1217      vert->index = count;
1218      count++;
1219    }
1220  }
1221  *numVerts = count;
1222
1223  // Count triangles
1224  count = 0;
1225  for (i = 0; i < mesh->numTris; i++) {
1226    tri = &mesh->tris[i];
1227    if ((tri->vert1->index >= 0 && 
1228         tri->vert2->index >= 0 && 
1229         tri->vert3->index >= 0) &&
1230        (tri->vert1->index != tri->vert2->index &&
1231         tri->vert2->index != tri->vert3->index &&
1232         tri->vert3->index != tri->vert1->index)) {
1233      count++;
1234    }
1235  }
1236  *numTris = count;
1237 
1238  if (!superQuiet) {
1239    fprintf(stderr, "Count: %d vertices, %d triangles.\n", 
1240            *numVerts, *numTris);
1241    int vdel = mesh->numVerts - *numVerts;
1242    int tdel = mesh->numTris -  *numTris;
1243    fprintf(stderr, "Deleted: %d vertices (%.1f%%), %d triangles (%.1f%%)\n",
1244            vdel, (100.0 * vdel) / mesh->numVerts,
1245            tdel, (100.0 * tdel) / mesh->numTris);
1246  }
1247}
1248
1249
1250int
1251collapse_edge(Vertex *v1, Vertex *v2)
1252{
1253    Vec3f norm;
1254    float minDot;
1255    int i, j, found, mirrorfound;
1256    Triangle *tri2;
1257    Triangle *tri3;
1258
1259    // If either one is a boundary, then don't collapse the edge
1260    if (neverMoveBoundary && (v1->onBoundary || v2->onBoundary)) {
1261      return 0;
1262    }
1263
1264    if (paranoid) {
1265      CheckVertPointers(v1, "v1 entering collapse_edge");
1266      CheckVertPointers(v2, "v2 entering collapse_edge");
1267    }
1268
1269    /* Compute an average normal (1 or 2 triangles will get counted twice) */
1270
1271    norm.setValue(0,0,0);
1272
1273    for (i = 0; i < v1->numTris; i++)
1274        norm += v1->tris[i]->norm;
1275
1276    for (i = 0; i < v2->numTris; i++)
1277        norm += v2->tris[i]->norm;
1278
1279    norm.normalize();
1280
1281    /* Find the minimum dot product between face normals and average normal */
1282
1283    minDot = FLT_MAX;
1284    for (i = 0; i < v1->numTris; i++) {
1285        minDot = MIN(norm.dot(v1->tris[i]->norm), minDot);
1286    }
1287
1288    for (i = 0; i < v2->numTris; i++) {
1289        minDot = MIN(norm.dot(v2->tris[i]->norm), minDot);
1290    }
1291
1292
1293    /* If minimum dot product is too low, then don't collapse edge */
1294    if (minDot < featureThresh) {
1295      return 0;
1296    }
1297
1298    /* Else collapse edge */
1299   
1300    // Initialize undo buffer -- commits every operation so far...
1301    SaveCheckpoint();
1302
1303    /* Average coordinates */
1304    save(v1->coord);
1305    v1->coord += v2->coord;
1306    v1->coord /= 2;     
1307
1308    disconnectVert(v1, v2);
1309    disconnectVert(v2, v1);
1310
1311    // Keep track of stats
1312    save(vertsDeleted);
1313    vertsDeleted++;
1314
1315    /* Loop through triangles of v2 */
1316    for (i = 0; i < v2->numTris; i++) {
1317        tri2 = v2->tris[i];
1318
1319        // Check for valid triangle
1320        int alreadydeleted = (tri2->vert1 == tri2->vert2 ||
1321                              tri2->vert1 == tri2->vert3 ||
1322                              tri2->vert2 == tri2->vert3 ||
1323                              tri2->vert1->index == -1 ||
1324                              tri2->vert2->index == -1 ||
1325                              tri2->vert3->index == -1);
1326        if (alreadydeleted) {
1327          if (0 && paranoid) {
1328            fprintf(stderr, "tri (%d %d %d) already deleted.\n",
1329                    tri2->vert1->index, tri2->vert2->index, 
1330                    tri2->vert3->index);
1331          }
1332          break;
1333        }
1334       
1335        /* See if triangle is shared by v1 and v2 */
1336        found = 0;
1337        for (j = 0; j < v1->numTris; j++) {
1338            found = (tri2 == v1->tris[j]);
1339            if (found) break;
1340        }
1341
1342        // See if the triangle is a mirror reflection of some other tri
1343        // already attached to v1...  Long logic, because we have to
1344        // check every possible orientation... :-/
1345        mirrorfound = 0;
1346        if (!found) {
1347          for (j = 0; j < v1->numTris; j++) {
1348            tri3 = v1->tris[j];
1349                   
1350            mirrorfound = 
1351              ((tri2->vert1 == tri3->vert3 &&
1352                tri2->vert2 == tri3->vert2 &&
1353                tri2->vert3 == v2 &&
1354                v1          == tri3->vert1)) ||
1355              ((tri2->vert1 == tri3->vert3 &&
1356                tri2->vert2 == v2 &&
1357                v1          == tri3->vert2 &&
1358                tri2->vert3 == tri3->vert1)) ||
1359              ((v1          == tri3->vert3 &&
1360                tri2->vert1 == v2 &&
1361                tri2->vert2 == tri3->vert2 &&
1362                tri2->vert3 == tri3->vert1)) ||
1363
1364              ((tri2->vert1 == tri3->vert2 &&
1365                tri2->vert2 == tri3->vert1 &&
1366                tri2->vert3 == v2 &&
1367                v1          == tri3->vert3)) ||
1368              ((tri2->vert1 == tri3->vert2 &&
1369                tri2->vert2 == v2 &&
1370                v1          == tri3->vert1 &&
1371                tri2->vert3 == tri3->vert3)) ||
1372              ((v1          == tri3->vert2 &&
1373                tri2->vert1 == v2 &&
1374                tri2->vert2 == tri3->vert1 &&
1375                tri2->vert3 == tri3->vert3)) ||
1376
1377              ((tri2->vert1 == tri3->vert1 &&
1378                tri2->vert2 == tri3->vert3 &&
1379                tri2->vert3 == v2 &&
1380                v1          == tri3->vert2)) ||
1381              ((tri2->vert1 == tri3->vert1 &&
1382                tri2->vert2 == v2 &&
1383                v1          == tri3->vert3 &&
1384                tri2->vert3 == tri3->vert2)) ||
1385              ((v1          == tri3->vert1 &&
1386                tri2->vert1 == v2 &&
1387                tri2->vert2 == tri3->vert3 &&
1388                tri2->vert3 == tri3->vert2));
1389            if (mirrorfound) {
1390              break;
1391            }
1392          }
1393        }
1394
1395        /* If shared, remove all references to this triangle */
1396        if (found) {
1397          // Remove links to/from disappearing vertex...
1398          if (tri2->vert1 != v1 && tri2->vert1 != v2) {
1399            disconnectVert(tri2->vert1, v2);
1400            disconnectVert(v2, tri2->vert1);
1401          }
1402          else if (tri2->vert2 != v1 && tri2->vert2 != v2) {
1403            disconnectVert(tri2->vert2, v2);
1404            disconnectVert(v2, tri2->vert2);
1405          }
1406          else if (tri2->vert3 != v1 && tri2->vert3 != v2) {
1407            disconnectVert(tri2->vert3, v2);
1408            disconnectVert(v2, tri2->vert3);
1409          } 
1410          else {
1411            fprintf(stderr, "Umm, deleting v2, not in tri...\n");
1412          }
1413
1414          removeTriangleRefs(tri2);
1415          i--;
1416
1417          // Keep track of stats
1418          save(trisDeleted);
1419          trisDeleted++;
1420        }
1421       
1422        // If mirrored, nuke em both....
1423        else if (mirrorfound) {
1424          // Disconnect the common edge joining the two vertices
1425          // (other than v1 and v2).  They are no longer directly
1426          // connected by an edge...  Only need to check tri2,
1427          // since tri3 shares the same edge.
1428          if (tri2->vert1 == v1 || tri2->vert1 == v2) {
1429            disconnectVert(tri2->vert2, tri2->vert3);
1430            disconnectVert(tri2->vert3, tri2->vert2);
1431          } 
1432          else if (tri2->vert2 == v1 || tri2->vert2 == v2) {
1433            disconnectVert(tri2->vert1, tri2->vert3);
1434            disconnectVert(tri2->vert3, tri2->vert1);
1435          } 
1436          else if (tri2->vert3 == v1 || tri2->vert3 == v2) {
1437            disconnectVert(tri2->vert1, tri2->vert2);
1438            disconnectVert(tri2->vert2, tri2->vert1);
1439          } else {
1440            fprintf(stderr, "Mirrorfound tri2: no common edge?!?!?\n");
1441          }
1442
1443          removeTriangleRefs(tri2);
1444          removeTriangleRefs(tri3);
1445          i--;
1446
1447          // Keep track of stats
1448          save(trisDeleted);
1449          trisDeleted += 2;
1450
1451        }
1452
1453        /* Else, substitute v1 for v2 and add triangle to v1's list*/
1454        else {
1455           
1456          /* If a vertex of the triangle is v1,
1457             then simply replace it with v2.
1458             Otherwise, replace v2 with v1 in the neighboring
1459             vertex lists and add the neighboring vertex to v1's list */
1460
1461          if (tri2->vert1 == v2) {
1462            save(tri2->vert1);
1463            tri2->vert1 = v1;
1464          } else {
1465            replaceVert(tri2->vert1, v2, v1);
1466            addVert(v1, tri2->vert1);
1467            disconnectVert(v2, tri2->vert1);
1468          }
1469
1470          if (tri2->vert2 == v2) {
1471            save(tri2->vert2);
1472            tri2->vert2 = v1;
1473          } else {
1474            replaceVert(tri2->vert2, v2, v1);
1475            addVert(v1, tri2->vert2);
1476            disconnectVert(v2, tri2->vert2);
1477          }
1478
1479          if (tri2->vert3 == v2) {
1480            save(tri2->vert3);
1481            tri2->vert3 = v1;
1482          } else {
1483            replaceVert(tri2->vert3, v2, v1);
1484            addVert(v1, tri2->vert3);
1485            disconnectVert(v2, tri2->vert3);
1486          }
1487
1488          addTriangle(v1, tri2);
1489          delTriangle(v2, tri2);
1490          i--;
1491        }
1492    }
1493
1494    // Ok, now check and make sure all the edge connections are
1495    // supported by a triangle.  (For example, mirror polygons
1496    // that nuke each other might leave dangling vertex neighbor
1497    // pointers, but it's hard to figure out until now, when we've
1498    // nuked all the triangles..
1499    pruneNeighbors(v1);
1500    // Remove all neighbor pointers for v2, too... :-)
1501    pruneNeighbors(v2);
1502
1503    /* Update normals of triangles around v1 */
1504    for (i = 0; i < v1->numTris; i++) {
1505      if (updateNormal(v1->tris[i])) {
1506        // A normal changed too much
1507        undo();
1508        return(0);     
1509      }
1510    }
1511
1512    // Make sure every edge is mentioned twice...
1513    // Otherwise, we made a topology change
1514    if (!(v1->onBoundary)) {
1515      int bedges = 0;
1516      for (j=0; j < v1->numVerts; j++) {
1517        Vertex *n = v1->verts[j];
1518        // Count how many times a triangle refers to this vertex
1519        int nrefs = 0;
1520        for (int k=0; k < v1->numTris; k++) {
1521          if (v1->tris[k]->vert1 == n ||
1522              v1->tris[k]->vert2 == n ||
1523              v1->tris[k]->vert3 == n) {
1524            nrefs++;
1525          }
1526        }
1527        if (nrefs != 2) {
1528          if (verbose) {
1529            fprintf(stderr, 
1530                    "Undoing collapse of %d and %d, because it would change the\n"
1531                    "topology such that new edge %d -- %d would have %d triangles.\n",
1532                    v1->index, v2->index,
1533                    v1->index, n->index, nrefs);
1534          }
1535          undo();
1536          return(0);
1537        }
1538      }
1539    }
1540
1541    if (paranoid) {
1542      // Check to make sure that edge and triangle numbers agree...
1543      CheckVertPointers(v1, "v1 exiting collapse_edge");
1544      CheckVertPointers(v2, "v2 exiting collapse_edge");
1545    }
1546
1547    /* v2 no longer exists */
1548    save(v2->index);
1549    v2->index = -1;
1550
1551    // We're committed to this change -- turn saving off
1552    SaveOff();
1553
1554    return 1;
1555}
1556
1557void 
1558CheckVertPointers(Vertex *vert, char *comment)
1559{
1560  // Check to make sure that every triangle mentioned by this
1561  // vertex includes this vertex just once.
1562  int i;
1563  for (i=0; i < vert->numTris; i++) {
1564    int count = 
1565      ((vert->tris[i]->vert1 == vert)?1:0) +
1566      ((vert->tris[i]->vert2 == vert)?1:0) +
1567      ((vert->tris[i]->vert3 == vert)?1:0);
1568    if (count != 1) {
1569      fprintf(stderr, "%s vert %d: tri (%d %d %d) refs %d times...\n", 
1570              comment, vert->index, vert->tris[i]->vert1->index,
1571              vert->tris[i]->vert2->index, vert->tris[i]->vert3->index,
1572              count);
1573    }
1574  }
1575
1576  // Check to make sure that every vertex mentioned as a neighbor
1577  // points back to this guy.
1578  for (i=0; i < vert->numVerts; i++) {
1579    Vertex *v2  = vert->verts[i];
1580    int count=0;
1581    for (int j=0; j < v2->numVerts; j++) {
1582      if (v2->verts[j]->index == vert->index) {
1583        count++;
1584      }
1585    }
1586    if (count != 1) {
1587      fprintf(stderr, "%s vert %d: neighbor %d points back %d times.\n", 
1588              comment, vert->index, v2->index, count);
1589    }
1590  }
1591
1592  // Check to make sure that either:
1593  //  - it is not a boundary vertex, and every edge has two tris, or
1594  //  - it is a boundary vertex, and edges have 1 or two tris.
1595  for (i=0; i < vert->numVerts; i++) {
1596    Vertex *v2  = vert->verts[i];
1597    int count=0;
1598    for (int j=0; j < vert->numTris; j++) {
1599      Triangle *t = vert->tris[j];
1600      if (t->vert1 == v2 || t->vert2 == v2 || t->vert3 == v2) {
1601        count++;
1602      }
1603    }
1604    if ((!(vert->onBoundary)) && (count != 2)) {
1605      fprintf(stderr, "%s internal vert %d: neighbor %d shares %d tris.\n", 
1606              comment, vert->index, v2->index, count);
1607    } else if (vert->onBoundary && (count == 0) || (count > 2)) {
1608      fprintf(stderr, "%s boundary vert %d: neighbor %d shares %d tris.\n", 
1609              comment, vert->index, v2->index, count);
1610    }
1611  } 
1612}
1613
1614
1615// This routine removes any neighbors not actually connected by a
1616// triangle.  Returns TRUE if it made any prunings.
1617bool 
1618pruneNeighbors(Vertex *v)
1619{
1620  int i, j;
1621  Vertex *v2;
1622  Triangle *t2;
1623  bool pruned = FALSE;
1624
1625  for (i=0; i < v->numVerts; i++) {     
1626    v2 = v->verts[i];
1627    bool found = FALSE;
1628    for (j=0; j < v->numTris; j++) {
1629      t2 = v->tris[j];
1630      if (t2->vert1 == v2 ||
1631          t2->vert2 == v2 || 
1632          t2->vert3 == v2) {
1633        found = TRUE;
1634        break;
1635      }
1636    }
1637    if (!found) {
1638      disconnectVert(v, v2);
1639      disconnectVert(v2, v);
1640      pruned = TRUE;
1641    }
1642  }
1643  return(pruned);
1644}
1645
1646
1647void
1648disconnectVert(Vertex *v1, Vertex *v2)
1649{
1650    int i;
1651
1652    for (i = 0; i < v1->numVerts; i++) {
1653        if (v1->verts[i] == v2) {
1654            save(v1->verts[i]);
1655            v1->verts[i] = v1->verts[v1->numVerts-1];
1656            save(v1->numVerts);
1657            v1->numVerts--;
1658            break;
1659        }
1660    }
1661}
1662
1663
1664void
1665addVert(Vertex *v1, Vertex *v2)
1666{
1667    int i;
1668
1669    for (i = 0; i < v1->numVerts; i++) {
1670        if (v1->verts[i] == v2)
1671            return;
1672    }
1673
1674    if (v1->numVerts == v1->maxVerts)
1675        reallocVerts(v1);
1676
1677    save(v1->verts[v1->numVerts]);
1678    v1->verts[v1->numVerts] = v2;
1679    save(v1->numVerts);
1680    v1->numVerts++;
1681}
1682
1683void
1684removeTriangleRefs(Triangle *tri)
1685{
1686  int i;
1687  Vertex *vert;
1688
1689  /* Find each reference to the triangle in the vertex lists
1690       and replace it with the last triangle in the list
1691       and decrement the list length */
1692
1693  vert = tri->vert1;
1694  for (i = 0; i < vert->numTris; i++) {
1695    if (vert->tris[i] == tri) {
1696      save(vert->tris[i]);
1697      vert->tris[i] = vert->tris[vert->numTris-1];
1698      save (vert->numTris);
1699      vert->numTris--;
1700      break;
1701    }
1702  }
1703
1704  vert = tri->vert2;
1705  for (i = 0; i < vert->numTris; i++) {
1706    if (vert->tris[i] == tri) {
1707      save(vert->tris[i]);
1708      vert->tris[i] = vert->tris[vert->numTris-1];
1709      save(vert->numTris);
1710      vert->numTris--;
1711      break;
1712    }
1713  }
1714
1715  vert = tri->vert3;
1716  for (i = 0; i < vert->numTris; i++) {
1717    if (vert->tris[i] == tri) {
1718      save(vert->tris[i]);
1719      vert->tris[i] = vert->tris[vert->numTris-1];
1720      save(vert->numTris);
1721      vert->numTris--;
1722      break;
1723    }
1724  }
1725}
1726
1727
1728void
1729replaceVert(Vertex *v1, Vertex *v2, Vertex *v3)
1730{
1731  int i, pos2, found3;
1732
1733  found3 = 0;
1734  pos2 = -1;
1735  for (i = 0; i < v1->numVerts; i++) {
1736    if (v1->verts[i] == v2)
1737      pos2 = i;
1738    if (v1->verts[i] == v3)
1739      found3 = 1;
1740  }
1741
1742  if (pos2 < 0)
1743    return;
1744  else if (!found3) {
1745    save(v1->verts[pos2]);
1746    v1->verts[pos2] = v3;
1747  } else {
1748    save(v1->verts[pos2]);
1749    v1->verts[pos2] = v1->verts[v1->numVerts-1];
1750    save(v1->numVerts);
1751    v1->numVerts--;
1752  }
1753}
1754
1755
1756void
1757addTriangle(Vertex *vert, Triangle *tri)
1758{
1759    if (vert->numTris == vert->maxTris)
1760        reallocTris(vert);
1761
1762    save(vert->tris[vert->numTris]);
1763    vert->tris[vert->numTris] = tri;
1764    save(vert->numTris);
1765    vert->numTris++;
1766}
1767
1768// This does the opposite of addTriangle -- removes
1769// a pointer from a vertex to a triangle....
1770void
1771delTriangle(Vertex *vert, Triangle *tri)
1772{
1773  int i;
1774  for (i=0; i < vert->numTris; i++) {
1775    if (vert->tris[i] == tri) {
1776      save(vert->tris[i]);
1777      vert->tris[i] = vert->tris[vert->numTris-1];
1778      save(vert->numTris);
1779      vert->numTris--;
1780      break;
1781    }
1782  }
1783}
1784
1785
1786
1787bool
1788updateNormal(Triangle *tri)
1789{
1790    Vec3f v1, v2, v3;
1791    Vec3f oldnorm = tri->norm;
1792
1793    v1.setValue(tri->vert1->coord);
1794    v2.setValue(tri->vert2->coord);
1795    v3.setValue(tri->vert3->coord);
1796
1797    v2.setValue(v1 - v2);
1798    v3 = v1 - v3;
1799    save(tri->norm);
1800    tri->norm = v3.cross(v2);
1801    tri->norm.normalize();
1802
1803    if ((oldnorm.x || oldnorm.y || oldnorm.z) &&
1804        tri->norm.dot(oldnorm) < flipDotThresh) {
1805      // Aborting collapse -- mindot too small
1806      return(TRUE);
1807    } else {
1808      return(FALSE);
1809    }
1810   
1811}
1812
1813
1814Mesh *
1815readMeshFromPly(FILE *inFile)
1816{
1817    int i, j, k;
1818    Mesh *mesh;
1819
1820    mesh = readPlyFile(inFile);
1821    if (mesh == NULL)
1822        return NULL;
1823   
1824    // Initialize Vertex variables
1825    for (i = 0; i < mesh->numVerts; i++) {
1826      // Stuff for edgecol
1827      mesh->verts[i].numVerts = 0;
1828      mesh->verts[i].maxVerts = 8;
1829      mesh->verts[i].verts = new Vertex*[mesh->verts[i].maxVerts];
1830     
1831      mesh->verts[i].numTris = 0;   
1832      mesh->verts[i].maxTris = 8;
1833      mesh->verts[i].tris = new Triangle*[mesh->verts[i].maxTris];
1834     
1835      // Clear onBoundary flag -- we'll detect it below...
1836      mesh->verts[i].onBoundary = FALSE;
1837    }
1838
1839    // Initialize Triangle variables
1840    for (i = 0; i < mesh->numTris; i++) {
1841        Triangle *tri = &mesh->tris[i];
1842
1843        updateNormal(tri);
1844
1845        Vertex *vert1 = tri->vert1;
1846        Vertex *vert2 = tri->vert2;
1847        Vertex *vert3 = tri->vert3;     
1848       
1849        // stuff for edgecol
1850        if (vert1->numTris == vert1->maxTris) {
1851            reallocTris(vert1);
1852        }
1853        if (vert2->numTris == vert2->maxTris) {
1854            reallocTris(vert2);
1855        }
1856        if (vert3->numTris == vert3->maxTris) {
1857            reallocTris(vert3);
1858        }
1859
1860        vert1->tris[vert1->numTris++] = tri;
1861        vert2->tris[vert2->numTris++] = tri;
1862        vert3->tris[vert3->numTris++] = tri;
1863
1864        // Make each vertex point to each other as neighbors.
1865        addNeighbors(vert1,vert2);
1866        addNeighbors(vert1,vert3);
1867        addNeighbors(vert2,vert3);
1868    }
1869
1870    // Print stats
1871    if (!superQuiet) {
1872      fprintf(stderr, "Loaded %d vertices (%d triangles).\n",
1873              mesh->numVerts, mesh->numTris);
1874    }
1875
1876    // Compute mean edge length, if necessary....
1877    if (needMeanLength) {
1878      if (!quiet)
1879        fprintf(stderr, "Computing mean length...\n");
1880      for (i = 0; i < mesh->numVerts; i++) {
1881        Vertex *v = &(mesh->verts[i]);
1882        for (j=0; j < v->numVerts; j++) {
1883          Vertex *n = v->verts[j];
1884          if (n->index > v->index) {
1885            Vec3f vedge = n->coord - v->coord;
1886            meanLengthSum += vedge.length();
1887            meanLengthWt += 1.0;
1888          }
1889        }
1890      }
1891      meanLength = meanLengthSum / meanLengthWt;
1892    }
1893
1894    // Set the onBoundary flag, and do a few sanity checks
1895    // on the connectivity for each vertex.
1896    detectBoundaries(mesh);
1897
1898    // If paranoid, check vertex pointers right away
1899    if (paranoid) {
1900      for (i=0; i < mesh->numVerts; i++) {
1901        Vertex *v = &(mesh->verts[i]);
1902        CheckVertPointers(v, "Reading file");
1903      }
1904    }
1905
1906    return mesh;
1907}
1908
1909
1910void detectBoundaries(Mesh *mesh)
1911{
1912  int i, j, k;
1913
1914  if (!quiet) 
1915    fprintf(stderr, "Detecting boundary vertices...\n");
1916
1917  // Always compute the boundary.  It's a goodThing(tm)
1918  // if (!neverMoveBoundary) return;
1919 
1920  // Set the onBoundary flag for each vertex
1921  // If numVerts == numTris, it is not on Boundary.
1922  // Optionally, do heavier-duty check, to make sure every
1923  // edge is mentioned once or twice...
1924   
1925  // Do this the quick way -- check the count for the number
1926  // of edges, and the number of triangles -- if the number
1927  // of edges is 1 greater than the number of triangles, then
1928  // it is an edge vertex.  If it's not 0 or 1 difference,
1929  // then something bad is happening....
1930   
1931  for (i = 0; i < mesh->numVerts; i++) {
1932    Vertex *v = &(mesh->verts[i]);
1933     
1934    if (v->numTris == v->numVerts) {
1935      v->onBoundary = FALSE;
1936    } else if (v->numTris + 1 == v->numVerts) {
1937      v->onBoundary = TRUE;
1938    } else {
1939      if (paranoid) {
1940        fprintf(stderr, "2D-manifold warn: Vert %d: %d edges, "
1941                "%d tris. Marking as boundary...\n", 
1942                v->index, v->numVerts, v->numTris);
1943      }
1944      v->onBoundary = TRUE;
1945    }
1946
1947    // Optionally, do heavier-duty check, to make sure every
1948    // edge is mentioned once or twice...
1949    if (paranoid) {
1950      int bedges = 0;
1951      for (j=0; j < v->numVerts; j++) {
1952        Vertex *n = v->verts[j];
1953        // Count how many times a triangle refers to this vertex
1954        int nrefs = 0;
1955        for (k=0; k < v->numTris; k++) {
1956          if (v->tris[k]->vert1 == n ||
1957              v->tris[k]->vert2 == n ||
1958              v->tris[k]->vert3 == n) {
1959            nrefs++;
1960          }
1961        }
1962        if (nrefs ==1) {
1963          // Count the boundary edges
1964          bedges++;     
1965        } else if (nrefs == 2) {
1966          // do nothing -- just fine for internal edges
1967        } else {
1968          fprintf(stderr, "Error:  Vertex %d, neighbor %d, is mentioned "
1969                  "by %d triangles....\n", v->index, n->index, nrefs);
1970        }       
1971      }
1972       
1973      // Check bedges is sane -- at very least, even-numbered
1974      // (Since we already printed the 2D-manifold warn above)
1975      if (bedges%2) {
1976        fprintf(stderr, "Error: Vertex %d has %d boundary edges. (ODD?)\n",
1977                v->index, bedges);
1978      }
1979    }
1980  }
1981}
1982
1983
1984static void
1985reallocTris(Vertex *v)
1986{
1987    int i;
1988    Triangle **newTris;
1989
1990    save(v->maxTris);
1991    v->maxTris *= 2;
1992    newTris = new Triangle*[v->maxTris];
1993    for (i = 0; i < v->numTris; i++) {
1994        newTris[i] = v->tris[i];
1995    }
1996   
1997    // BUGBUG: Memory leak for now...
1998    // delete [] v->tris;
1999
2000    save(v->tris);
2001    v->tris = newTris;
2002}
2003
2004
2005// This function doesn't save(), since it
2006// is only called when loading in the mesh.
2007// Thus it can't be undone.
2008void
2009addNeighbors(Vertex *v1, Vertex *v2)
2010{
2011  int found = 0;
2012 
2013  for (int i = 0; i < v1->numVerts; i++) {
2014    if (v1->verts[i] == v2) {
2015      found = 1;
2016      break;
2017    }
2018  }
2019 
2020  if (!found) {
2021    if (v1->numVerts == v1->maxVerts) {
2022      reallocVerts(v1);
2023    }
2024    if (v2->numVerts == v2->maxVerts) {
2025      reallocVerts(v2);
2026    }
2027    v1->verts[v1->numVerts++] = v2;
2028    v2->verts[v2->numVerts++] = v1;
2029  }
2030}
2031
2032
2033static void
2034reallocVerts(Vertex *v)
2035{
2036    int i;
2037    Vertex **newVerts;
2038
2039    save(v->maxVerts);
2040    v->maxVerts *= 2;
2041    newVerts = new Vertex*[v->maxVerts];
2042    for (i = 0; i < v->numVerts; i++) {
2043        newVerts[i] = v->verts[i];
2044    }
2045 
2046    //  BUGBUG: Memory leak for now
2047    // delete [] v->verts;
2048
2049    save(v->verts);
2050    v->verts = newVerts;
2051}
2052
2053
Note: See TracBrowser for help on using the repository browser.