Codebase list octave-iso2mesh / debian/1.9.6+ds-5 meshfix / meshfix.cpp
debian/1.9.6+ds-5

Tree @debian/1.9.6+ds-5 (Download .tar.gz)

meshfix.cpp @debian/1.9.6+ds-5raw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
#include "exttrimesh.h"
#include <string.h>
#include <stdlib.h>

const char *input_filename;

double closestPair(List *bl1, List *bl2, Vertex **closest_on_bl1, Vertex **closest_on_bl2)
{
 Node *n, *m;
 Vertex *v,*w;
 double adist, mindist = DBL_MAX;

 FOREACHVVVERTEX(bl1, v, n)
  FOREACHVVVERTEX(bl2, w, m)
   if ((adist = w->squaredDistance(v))<mindist)
   {
    mindist=adist;
    *closest_on_bl1 = v;
    *closest_on_bl2 = w;
   }

 return mindist;
}

/**
 * Joins the closest components, that have boundaries (holes).
 */
bool joinClosestComponents(ExtTriMesh *tin, bool justconnect = false, bool refine = true, bool fair = true) {
    Vertex *v,*w, *gv, *gw;
    Triangle *t, *s;
    Node *n;
    List triList, boundary_loops, *one_loop;
    List **bloops_array;
    int i, j, numloops;

    i=0;
    // delete info of all triangles
    FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
    // initialize info of all triangles with their component number starting by 1.
    FOREACHVTTRIANGLE((&(tin->T)), t, n) {
        if (t->info == NULL) {
            i++;
            triList.appendHead(t);
            t->info = (void *)i;
            while(triList.numels()) {
                t = (Triangle *)triList.popHead();
                if ((s = t->t1()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)i;}
                if ((s = t->t2()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)i;}
                if ((s = t->t3()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)i;}
            }
        }
    }
    // if less then 2 components
    if (i<2) {
        // unset info again
        FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
        JMesh::info("Mesh is a single component. Nothing done.");
        return false;
    }
    // copy triangle component number to the vertices
    FOREACHVTTRIANGLE((&(tin->T)), t, n) {
        t->v1()->info = t->v2()->info = t->v3()->info = t->info;
    }
    // create list boundary loop lists (= lists of connected vertices on a boundary)
    FOREACHVVVERTEX((&(tin->V)), v, n) {
        // find next vertex of an unmarked boundary
        if (!IS_VISITED2(v) && v->isOnBoundary()) {
            w = v;
            one_loop = new List;
            // mark all vertices at this boundary
            do {
                one_loop->appendHead(w);
                MARK_VISIT2(w);
                w = w->nextOnBoundary();
            } while (w != v);
            boundary_loops.appendHead(one_loop);
        }
    }
    FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_VISIT2(v);

    bloops_array = (List **)boundary_loops.toArray();
    numloops = boundary_loops.numels();

    int numtris = tin->T.numels();
    double adist, mindist=DBL_MAX;

    gv=NULL;
    for (i=0; i<numloops; i++) {
        for (j=0; j<numloops; j++) {
            // if i,j are indices of vertices of different boundary loops, search for the closes pair of vertices and update mindist
            if (((Vertex *)bloops_array[i]->head()->data)->info != ((Vertex *)bloops_array[j]->head()->data)->info) {
                adist = closestPair(bloops_array[i], bloops_array[j], &v, &w);
                if (adist<mindist) {mindist=adist; gv=v; gw=w;}
            }
        }
    }
    if (gv!=NULL) tin->joinBoundaryLoops(gv, gw, justconnect, refine, fair);

    FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
    FOREACHVVVERTEX((&(tin->V)), v, n) v->info = NULL;

    free(bloops_array);
    while ((one_loop=(List *)boundary_loops.popHead())!=NULL) delete one_loop;

    return (gv!=NULL);
}

//#define DISCLAIMER

void usage()
{
 printf("%s v%s - by %s.\n================================================================================\n", JMesh::app_name, JMesh::app_version, JMesh::app_authors);
 printf("USAGE: meshfix <file1> [<file2>] [OPTIONS]\n");
 printf("  Processes file1 and saves the result to <file1>_fixed.off.\n");
 printf("  An optionally passed file2 is merged with the first one.\n");
 printf("OPTIONS:\n");
 printf(" -a <epsilon_angle>  Allowed range: 0 < epsilon_angle < 2, default: 0 (degrees).\n");
 printf(" -j                  Join 2 biggest components if they overlap, remove the rest.\n");
 printf(" -jc                 Join the closest pair of components.\n");
 printf(" -h, --help          Print this help and exit.\n");
 printf(" --shells <n>        Only the n biggest shells are kept.\n");
 printf(" -o <output>         Set the output filename (without extension).\n");
 printf(" -q                  Quiet mode, don't write much to stdout.\n");
 printf(" --remove-handles    Remove all handles of the mesh.\n");
 printf(" -u <steps>          Uniform remeshing of the whole mesh, steps > 0\n");
 printf("   --vertices <n>    Constrain number of vertices to n (only with -u)\n");
 printf(" --no-clean          Don't clean.\n");
 printf(" --smooth <n>        Apply n laplacian smoothing steps.\n");
 printf(" -s, --stl           Result is saved in STL     format instead of OFF.\n");
 printf(" -w, --wrl           Result is saved in VRML1.0 format instead of OFF.\n");
 printf(" --fsmesh            Result is saved in FreeSurfer format instead of OFF.\n");
 printf(" --xshift <d>        Shift x-coordinates of vertices by d when saving output.\n");
 printf("                     Only works with --fsmesh; used to deal with small FreeSurfer glitch\n");
 printf(" --msh               Result is saved in gmsh format for debugging (including vertex and triangle masks)\n");
 printf(" == Cutting, decoupling, dilation ==\n");
 printf(" --cut-outer <d>     Remove triangles of 1st that are outside of the 2nd shell.\n");
 printf(" --cut-inner <d>     Remove triangles of 1st that are inside  of the 2nd shell.\n");
 printf("                     Dilate 2nd by d; Fill holes and keep only 1st afterwards.\n");
 printf(" --decouple-inin <d> Treat 1st file as inner, 2nd file as outer component.\n");
 printf("                     Resolve overlaps by moving inners triangles inwards.\n");
 printf(" --decouple-outin <d> Treat 1st file as outer, 2nd file as inner component.\n");
 printf("                     Resolve overlaps by moving outers triangles inwards.\n");
 printf(" --decouple-outout <d> Treat 1st file as outer, 2nd file as inner component.\n");
 printf("                     Resolve overlaps by moving outers triangles outwards.\n");
 printf("                     Constrain the min distance between the components > d.\n");
 printf(" --fineTuneIn <d> <n> Used to fine-tune the minimal distance between surfaces \n");
 printf("                     A minimal distance d is ensured, and reached in n substeps \n");
 printf("                     When using the surfaces for subsequent volume meshing by gmsh\n");
 printf("                     this step prevent too flat tetrahedra\n");
 printf(" --fineTuneOut <d> <n> Similar to --fineTuneIn, but ensures minimal distance in the other direction\n");
 printf(" --dilate <d>        Dilate the surface by d. d < 0 means shrinking.\n");
 printf(" --intersect         If the mesh contains intersections, return value = 1.\n");
 printf(" --intersect -o fname.msh  If the mesh contains intersections, return value = 1.\n");
 printf("                     In addtion, save mesh with highlighted intersections in Gmsh format\n");
 printf("Accepted input formats are OFF, PLY and STL.\nOther formats are supported only partially.\n");
 printf("See http://jmeshlib.sourceforge.net for details on supported formats.\n");
 printf("\nIf MeshFix is used for research purposes, please cite the following paper:\n");
 printf("M. Attene - A lightweight approach to repairing digitized polygon meshes.\nThe Visual Computer, 2010. (c) Springer.\n");
 exit(0);
}

char *createFilename(const char *iname, const char *subext, const char *newextension, bool stripExt)
{
 static char tname[2048];
 char *oname = (char *)malloc(strlen(iname)+strlen(subext)+strlen(newextension)+1);
 strcpy(tname, iname);
 if(!stripExt)
 {
  int tl = strlen(tname), nl = strlen(newextension);
  stripExt = true;
  for (int n=0; n < nl; n++) stripExt &= tname[tl-nl+n] == newextension[n]; // strip if identical extension found
 }
 if(stripExt) for (int n=strlen(tname)-1; n>0; n--) if (tname[n]=='.') {tname[n] = '\0'; break;}
 sprintf(oname,"%s%s%s",tname,subext,newextension);
 return oname;
}

int main(int argc, char *argv[])
{
 JMesh::init();
 JMesh::app_name = "MeshFix";
 JMesh::app_version = "1.2-alpha";
 JMesh::app_year = "2011";
 JMesh::app_authors = "Marco Attene, Mirko Windhoff, Axel Thielscher";
 JMesh::app_maillist = "attene@ge.imati.cnr.it, mirko.windhoff@tuebingen.mpg.de, axel.thielscher@tuebingen.mpg.de";
 ExtTriMesh tin;

#ifdef DISCLAIMER
 printf("\n*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
 printf("This software can be used ONLY with an explicit authorization of the author.\n");
 printf("If you do not have such an authorization, you must delete this software.\n");
 printf("In no event this version of MeshFix can be redistributed.\n");
 printf("\n*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
#endif

 if (argc < 2) usage();

 float par = 0;
 unsigned numberComponentsToKeep = 1;
 bool joinOverlappingComponents = false;
// float minAllowedDistance = 0;
 bool haveJoinClosestComponents = false;
 int uniformRemeshSteps = 0, numberOfVertices = 0;
 int smoothingSteps = 0, nsteps = -1;
 double cutOuterMinDist = -1, cutInnerMinDist = -1;
 double decoupleOuterOutMinDist = -1, decoupleOuterInMinDist = -1, decoupleInnerInMinDist = -1;
 double dilateDist = 0;
 double fineTuneIn = -1, fineTuneOut = -1;
 bool clean = true;
 bool removeHandles = false;
 bool save_vrml = false;
 bool save_stl = false;
 bool save_msh = false;
 bool save_fsmesh = false;
 float xshift = 0.0; // used by saveFSMESH
 bool haveOutputFile = false;
 bool haveIntersectText = false;
 const char *outputFile;
 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) usage();
 for (int i=2; i<argc; i++)
 {
  if (!strcmp(argv[i], "-a"))
  {
   if (i<argc-1) par = (float)atof(argv[i+1]); else par = 0;
   if (par < 0) JMesh::error("Epsilon angle must be > 0.\n");
   if (par > 2) JMesh::error("Epsilon angle must be < 2 degrees.\n");
   tin.epsilon_angle = par;
   if (tin.epsilon_angle)
   {
    JMesh::acos_tolerance = asin((M_PI*tin.epsilon_angle)/180.0);
	printf("Fixing asin tolerance to %e\n",JMesh::acos_tolerance);
    i++;
   }
  }
  else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) usage();
  else if (!strcmp(argv[i], "--shells")) {
      if (i<argc-1) {
          numberComponentsToKeep = atoi(argv[i+1]);
          if (numberComponentsToKeep < 1)
              JMesh::error("# components to keep must be >= 1.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "-w") || !strcmp(argv[i], "--wrl")) save_vrml = true;
  else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stl")) save_stl = true;
  else if (!strcmp(argv[i], "--msh")) save_msh = true;
  else if (!strcmp(argv[i], "--fsmesh")) save_fsmesh = true;
  else if (!strcmp(argv[i], "-j")) joinOverlappingComponents = true;
  else if (!strcmp(argv[i], "-u")) {
      if (i>=argc-1 || (uniformRemeshSteps = atoi(argv[i+1]))<1)
          JMesh::error("# uniform remesh steps must be >= 1.\n");
      i++;
  }
  else if (!strcmp(argv[i], "--xshift")) {
      if (i>=argc-1) JMesh::error("error reading xshift\n");
      xshift = (float) atof(argv[i+1]);
      JMesh::info("xshift set to %f\n",xshift);
      i++;
  }
  else if (!strcmp(argv[i], "--vertices")) {
      if (i>=argc-1 || (numberOfVertices = atoi(argv[i+1]))<1)
          JMesh::error("# of vertices must be >= 0.\n");
      i++;
  }
  else if (!strcmp(argv[i], "--smooth")) {
      if (i>=argc-1 || (smoothingSteps = atoi(argv[i+1]))<1)
          JMesh::error("# smoothing steps must be >= 1.\n");
      i++;
  }
  else if (!strcmp(argv[i], "--cut-outer")) {
      if (i<argc-1) {
          cutOuterMinDist = atof(argv[i+1]);
          if (cutOuterMinDist < 0)
              JMesh::error("cutOuterMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--cut-inner")) {
      if (i<argc-1) {
          cutInnerMinDist = atof(argv[i+1]);
          if (cutInnerMinDist < 0)
              JMesh::error("cutInnerMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--decouple-outout")) {
      if (i<argc-1) {
          decoupleOuterOutMinDist = atof(argv[i+1]);
          if (decoupleOuterOutMinDist < 0)
              JMesh::error("decoupleOuterOutMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--decouple-outin")) {
      if (i<argc-1) {
          decoupleOuterInMinDist = atof(argv[i+1]);
          if (decoupleOuterInMinDist < 0)
              JMesh::error("decoupleOuterInMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--decouple-inin")) {
      if (i<argc-1) {
          decoupleInnerInMinDist = atof(argv[i+1]);
          if (decoupleInnerInMinDist < 0)
              JMesh::error("decoupleInnerInMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--decouple-inin")) {
      if (i<argc-1) {
          decoupleInnerInMinDist = atof(argv[i+1]);
          if (decoupleInnerInMinDist < 0)
              JMesh::error("decoupleInMinDist must be >= 0.\n");
          else
              i++;
      }
  }
  else if (!strcmp(argv[i], "--dilate")) {
      if (i<argc-1) {
          dilateDist = atof(argv[i+1]);
          i++;
      }
  }
  else if (!strcmp(argv[i], "--fineTuneIn")) {
      if (i<argc-1) { fineTuneIn = atof(argv[i+1]);  i++; }
      if (fineTuneIn <= 0) JMesh::error("fineTuneIn MinDist must be > 0.\n");

      if (i<argc-1) { nsteps = atoi(argv[i+1]);  i++; }
      if (nsteps <= 0) JMesh::error("number of substeps must be > 0.\n");
  }
  else if (!strcmp(argv[i], "--fineTuneOut")) {
      if (i<argc-1) { fineTuneOut = atof(argv[i+1]);  i++; }
      if (fineTuneOut <= 0) JMesh::error("fineTuneOut MinDist must be > 0.\n");

      if (i<argc-1) { nsteps = atoi(argv[i+1]);  i++; }
      if (nsteps <= 0) JMesh::error("number of substeps must be > 0.\n");
  }
  else if (!strcmp(argv[i], "--remove-handles")) removeHandles = true;
  else if (!strcmp(argv[i], "--intersect")) haveIntersectText = true;
  else if (!strcmp(argv[i], "--no-clean")) clean = false;
  else if (!strcmp(argv[i], "-jc")) haveJoinClosestComponents = true;
  else if (!strcmp(argv[i], "-o")) {
      if (i<argc-1) {
          haveOutputFile = true;
          outputFile = argv[i+1];
          i++;
      }
  }
  else if (!strcmp(argv[i], "-q")) JMesh::quiet = true;
  else if (argv[i][0] == '-') JMesh::warning("%s - Unknown operation.\n",argv[i]);
 }

 printf("meshfix %s\n", argv[1]);
 // The loader performs the conversion to a set of oriented manifolds
 if (tin.load(argv[1]) != 0) JMesh::error("Can't open file '%s'.\n", argv[1]);

 // Join the second input argument if existing
 if (tin.append(argv[2]) == 0)
     JMesh::info("%s was joined.\n", argv[2]);
 input_filename = argv[1];

 // Keep only the biggest components
 tin.removeSmallestComponents( numberComponentsToKeep );

 // Fill holes by taking into account both sampling density and normal field continuity
 tin.fillSmallBoundaries(tin.E.numels(), true, true);

 if (joinOverlappingComponents) {
     tin.removeSmallestComponents(2);
     if(!tin.joinOverlappingComponentPair2()) {
         if(!joinClosestComponents(&tin, false, true, false))
             JMesh::warning("Joining didn't succeed.\n");
     } else numberComponentsToKeep = 1; // for subsequent cleaning
 }
 if (haveJoinClosestComponents)
 {
  printf("\nJoining input components ...\n");
  JMesh::begin_progress();
  while (joinClosestComponents(&tin, false, true, true)) JMesh::report_progress("Num. components: %d       ",tin.shells());
  JMesh::end_progress();
  tin.deselectTriangles();
 }

 if (removeHandles) {
     printf("Removing all handles ...\n");
     if(tin.shells() > 1)
         JMesh::warning("Remove handles works only on single component meshes. Keeping only biggest shell.\n");
     if(!tin.removeHandles()) JMesh::warning("Remove handles didn't succeed.\n");
 }

 if (dilateDist != 0.0) {
     printf("Dilating by %g.\n", dilateDist);
     tin.dilate(dilateDist);
 }
 if (cutOuterMinDist >= 0) {
     printf("Cutting triangles of the first component away, that are outside of the second one; Fill holes.\n");
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't cut. Having %d and should have 2.\n", tin.shells());
     else tin.cutFirstWithSecondComponent(cutOuterMinDist, true);
 }
 if (cutInnerMinDist >= 0) {
     printf("Cutting triangles of the first component away, that are inside of the second one; Fill holes.\n");
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't cut. Having %d and should have 2.\n", tin.shells());
     else tin.cutFirstWithSecondComponent(cutInnerMinDist, false);
 }
 if (decoupleOuterOutMinDist >= 0) {
     if(numberComponentsToKeep == 1) JMesh::warning("Use --shells 2 for decoupling.\n");
     printf("Decoupling first (outer) component from second one (move outwards). Min. distance: %g.\n", decoupleOuterOutMinDist);
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't decouple. Having %d and should have 2.\n", tin.shells());
     else tin.decoupleFirstFromSecondComponent(decoupleOuterOutMinDist, 15, true, true);
     numberComponentsToKeep = 1; // for subsequent cleaning
 } else if(decoupleOuterInMinDist >= 0) {
     if(numberComponentsToKeep == 1) JMesh::warning("Use --shells 2 for decoupling.\n");
     printf("Decoupling first (outer) component from second one (move inwards). Min. distance: %g.\n", decoupleInnerInMinDist);
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't decouple. Having %d and should have 2.\n", tin.shells());
     else tin.decoupleFirstFromSecondComponent(decoupleOuterInMinDist, 15, true, false);
     numberComponentsToKeep = 1; // for subsequent cleaning
 } else if(decoupleInnerInMinDist >= 0) {
     if(numberComponentsToKeep == 1) JMesh::warning("Use --shells 2 for decoupling.\n");
     printf("Decoupling first (inner) component from second one (move inwards). Min. distance: %g.\n", decoupleInnerInMinDist);
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't decouple. Having %d and should have 2.\n", tin.shells());
     else tin.decoupleFirstFromSecondComponent(decoupleInnerInMinDist, 15, false, false);
     numberComponentsToKeep = 1; // for subsequent cleaning
 }

 if (fineTuneIn >=0) {
     printf("Fine-tuning for later volume meshing ...\n");
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't decouple. Having %d and should have 2.\n", tin.shells());
     else tin.fineTune(fineTuneIn, nsteps, true);
 } else if (fineTuneOut >=0) {
     printf("Fine-tuning for later volume meshing ...\n");
     if(tin.shells() != 2) JMesh::warning("Incorrect number of components, won't decouple. Having %d and should have 2.\n", tin.shells());
     else tin.fineTune(fineTuneOut, nsteps, false);
 }


 if (uniformRemeshSteps) {
     printf("Uniform remeshing ...\n");
     tin.uniformRemesh(uniformRemeshSteps, numberOfVertices, tin.E.numels());
 } else if(numberOfVertices) { JMesh::warning("--vertices works only together with -u."); }

 if(smoothingSteps) {
     printf("Smoothing %d steps.\n", smoothingSteps);
     tin.laplacianSmooth(smoothingSteps, 1);
 }
 // Run geometry correction
 if (clean) {
     printf("Cleaning intersections, degeneracies ...\n");
     if (!tin.clean(20, 3, numberComponentsToKeep)) {
      fprintf(stderr,"MeshFix failed!\n");
      fprintf(stderr,"Please try manually using ReMESH: http://remesh.sourceforge.net\n");
      FILE *fp = fopen("meshfix_log.txt","a");
      fprintf(fp,"MeshFix failed on %s\n", input_filename);
      fclose(fp);
     }
 }

 if (haveIntersectText) {
     printf("Testing for intersections ...\n");
     tin.deselectTriangles();

     int its = tin.selectIntersectingTriangles();

     if(haveOutputFile) tin.saveMSH(outputFile);

     if(its) return 0;
     return 1;
 }

 char *fname = createFilename( haveOutputFile ? outputFile : argv[1], haveOutputFile ? "": "_fixed", (save_vrml? ".wrl" : (save_stl? ".stl": (save_msh? ".msh" : (save_fsmesh? ".fsmesh" : ".off")))), !haveOutputFile);
 printf("Saving output mesh to '%s'\n",fname);
 if (save_vrml)
     tin.saveVRML1(fname);
 else if (save_stl)
     tin.saveSTL(fname);
 else if (save_msh)
     tin.saveMSH(fname);
 else if (save_fsmesh)
     tin.saveFSMESH(fname,xshift);
 else
     tin.saveOFF(fname);
 return 0;
}