Chaste  Release::2017.1
tetgen.cpp
Go to the documentation of this file.
1 
7 #ifndef UNUSED_OPT
8 #ifdef NDEBUG
9 #define UNUSED_OPT(var) var=var
10 #else //NDEBUG
11 #define UNUSED_OPT(var)
12 #endif //NDEBUG
13 #endif //UNUSED_OPT
14 
15 // This include is here so that the chaste_libs=0 build correctly links predicates.o.
16 #include "predicates.hpp"
17 
19 // //
20 // TetGen //
21 // //
22 // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator //
23 // //
24 // Version 1.4 //
25 // April 16, 2007 //
26 // //
27 // Copyright (C) 2002--2007 //
28 // Hang Si //
29 // Research Group Numerical Mathematics and Scientific Computing //
30 // Weierstrass Institute for Applied Analysis and Stochastics //
31 // Mohrenstr. 39, 10117 Berlin, Germany //
32 // si@wias-berlin.de //
33 // //
34 // TetGen is freely available through the website: http://tetgen.berlios.de. //
35 // It may be copied, modified, and redistributed for non-commercial use. //
36 // Please consult the file LICENSE for the detailed copyright notices. //
37 // //
39 
41 // //
42 // tetgen.cxx //
43 // //
44 // The TetGen library and program. //
45 // //
47 
48 #include "tetgen.h"
49 namespace tetgen
50 { //Added namespace to avoid clash with triangle
51 
53 // //
54 // terminatetetgen() Terminate TetGen with a given exit code. //
55 // //
57 
58 void terminatetetgen(int x)
59 {
60 #ifdef TETLIBRARY
61  throw x;
62 #else
63  exit(x);
64 #endif // #ifdef TETLIBRARY
65 }
66 
67 //
68 // Begin of class 'tetgenio' implementation
69 //
70 
72 // //
73 // initialize() Initialize all variables of 'tetgenio'. //
74 // //
75 // It is called by the only class constructor 'tetgenio()' implicitly. Thus, //
76 // all variables are guaranteed to be initialized. Each array is initialized //
77 // to be a 'NULL' pointer, and its length is equal zero. Some variables have //
78 // their default value, 'firstnumber' equals zero, 'mesh_dim' equals 3, and //
79 // 'numberofcorners' equals 4. Another possible use of this routine is to //
80 // call it before to re-use an object. //
81 // //
83 
84 void tetgenio::initialize()
85 {
86  firstnumber = 0; // Default item index is numbered from Zero.
87  mesh_dim = 3; // Default mesh dimension is 3.
88  useindex = true;
89 
90  pointlist = (REAL *) NULL;
91  pointattributelist = (REAL *) NULL;
92  pointmtrlist = (REAL *) NULL;
93  pointmarkerlist = (int *) NULL;
94  numberofpoints = 0;
95  numberofpointattributes = 0;
96  numberofpointmtrs = 0;
97 
98  tetrahedronlist = (int *) NULL;
99  tetrahedronattributelist = (REAL *) NULL;
100  tetrahedronvolumelist = (REAL *) NULL;
101  neighborlist = (int *) NULL;
102  numberoftetrahedra = 0;
103  numberofcorners = 4; // Default is 4 nodes per element.
104  numberoftetrahedronattributes = 0;
105 
106  trifacelist = (int *) NULL;
107  adjtetlist = (int *) NULL;
108  trifacemarkerlist = (int *) NULL;
109  numberoftrifaces = 0;
110 
111  facetlist = (facet *) NULL;
112  facetmarkerlist = (int *) NULL;
113  numberoffacets = 0;
114 
115  edgelist = (int *) NULL;
116  edgemarkerlist = (int *) NULL;
117  numberofedges = 0;
118 
119  holelist = (REAL *) NULL;
120  numberofholes = 0;
121 
122  regionlist = (REAL *) NULL;
123  numberofregions = 0;
124 
125  facetconstraintlist = (REAL *) NULL;
126  numberoffacetconstraints = 0;
127  segmentconstraintlist = (REAL *) NULL;
128  numberofsegmentconstraints = 0;
129 
130  pbcgrouplist = (pbcgroup *) NULL;
131  numberofpbcgroups = 0;
132 
133  vpointlist = (REAL *) NULL;
134  vedgelist = (voroedge *) NULL;
135  vfacetlist = (vorofacet *) NULL;
136  vcelllist = (int **) NULL;
137  numberofvpoints = 0;
138  numberofvedges = 0;
139  numberofvfacets = 0;
140  numberofvcells = 0;
141 }
142 
144 // //
145 // deinitialize() Free the memory allocated in 'tetgenio'. //
146 // //
147 // It is called by the class destructor '~tetgenio()' implicitly. Hence, the //
148 // occupied memory by arrays of an object will be automatically released on //
149 // the deletion of the object. However, this routine assumes that the memory //
150 // is allocated by C++ memory allocation operator 'new', thus it is freed by //
151 // the C++ array deletor 'delete []'. If one uses the C/C++ library function //
152 // 'malloc()' to allocate memory for arrays, one has to free them with the //
153 // 'free()' function, and call routine 'initialize()' once to disable this //
154 // routine on deletion of the object. //
155 // //
157 
158 void tetgenio::deinitialize()
159 {
160  facet *f;
161  polygon *p;
162  pbcgroup *pg;
163  int i, j;
164 
165  if (pointlist != (REAL *) NULL) {
166  delete [] pointlist;
167  }
168  if (pointattributelist != (REAL *) NULL) {
169  delete [] pointattributelist;
170  }
171  if (pointmtrlist != (REAL *) NULL) {
172  delete [] pointmtrlist;
173  }
174  if (pointmarkerlist != (int *) NULL) {
175  delete [] pointmarkerlist;
176  }
177 
178  if (tetrahedronlist != (int *) NULL) {
179  delete [] tetrahedronlist;
180  }
181  if (tetrahedronattributelist != (REAL *) NULL) {
182  delete [] tetrahedronattributelist;
183  }
184  if (tetrahedronvolumelist != (REAL *) NULL) {
185  delete [] tetrahedronvolumelist;
186  }
187  if (neighborlist != (int *) NULL) {
188  delete [] neighborlist;
189  }
190 
191  if (trifacelist != (int *) NULL) {
192  delete [] trifacelist;
193  }
194  if (adjtetlist != (int *) NULL) {
195  delete [] adjtetlist;
196  }
197  if (trifacemarkerlist != (int *) NULL) {
198  delete [] trifacemarkerlist;
199  }
200 
201  if (edgelist != (int *) NULL) {
202  delete [] edgelist;
203  }
204  if (edgemarkerlist != (int *) NULL) {
205  delete [] edgemarkerlist;
206  }
207 
208  if (facetlist != (facet *) NULL) {
209  for (i = 0; i < numberoffacets; i++) {
210  f = &facetlist[i];
211  for (j = 0; j < f->numberofpolygons; j++) {
212  p = &f->polygonlist[j];
213  delete [] p->vertexlist;
214  }
215  delete [] f->polygonlist;
216  if (f->holelist != (REAL *) NULL) {
217  delete [] f->holelist;
218  }
219  }
220  delete [] facetlist;
221  }
222  if (facetmarkerlist != (int *) NULL) {
223  delete [] facetmarkerlist;
224  }
225 
226  if (holelist != (REAL *) NULL) {
227  delete [] holelist;
228  }
229  if (regionlist != (REAL *) NULL) {
230  delete [] regionlist;
231  }
232  if (facetconstraintlist != (REAL *) NULL) {
233  delete [] facetconstraintlist;
234  }
235  if (segmentconstraintlist != (REAL *) NULL) {
236  delete [] segmentconstraintlist;
237  }
238  if (pbcgrouplist != (pbcgroup *) NULL) {
239  for (i = 0; i < numberofpbcgroups; i++) {
240  pg = &(pbcgrouplist[i]);
241  if (pg->pointpairlist != (int *) NULL) {
242  delete [] pg->pointpairlist;
243  }
244  }
245  delete [] pbcgrouplist;
246  }
247  if (vpointlist != (REAL *) NULL) {
248  delete [] vpointlist;
249  }
250  if (vedgelist != (voroedge *) NULL) {
251  delete [] vedgelist;
252  }
253  if (vfacetlist != (vorofacet *) NULL) {
254  for (i = 0; i < numberofvfacets; i++) {
255  delete [] vfacetlist[i].elist;
256  }
257  delete [] vfacetlist;
258  }
259  if (vcelllist != (int **) NULL) {
260  for (i = 0; i < numberofvcells; i++) {
261  delete [] vcelllist[i];
262  }
263  delete [] vcelllist;
264  }
265 }
266 
268 // //
269 // load_node_call() Load a list of nodes. //
270 // //
271 // It is a support routine for routines: 'load_nodes()', 'load_poly()', and //
272 // 'load_tetmesh()'. 'infile' is the file handle contains the node list. It //
273 // may point to a .node, or .poly or .smesh file. 'markers' indicates each //
274 // node contains an additional marker (integer) or not. 'infilename' is the //
275 // name of the file being read, it is only appeared in error message. //
276 // //
277 // The 'firstnumber' (0 or 1) is automatically determined by the number of //
278 // the first index of the first point. //
279 // //
281 
282 bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename)
283 {
284  char inputline[INPUTLINESIZE];
285  char *stringptr;
286  REAL x, y, z, attrib;
287  int firstnode, currentmarker;
288  int index, attribindex;
289  int i, j;
290 
291  // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
292  pointlist = new REAL[numberofpoints * 3];
293  if (pointlist == (REAL *) NULL) {
294  printf("Error: Out of memory.\n");
295  terminatetetgen(1);
296  }
297  if (numberofpointattributes > 0) {
298  pointattributelist = new REAL[numberofpoints * numberofpointattributes];
299  if (pointattributelist == (REAL *) NULL) {
300  printf("Error: Out of memory.\n");
301  terminatetetgen(1);
302  }
303  }
304  if (markers) {
305  pointmarkerlist = new int[numberofpoints];
306  if (pointmarkerlist == (int *) NULL) {
307  printf("Error: Out of memory.\n");
308  terminatetetgen(1);
309  }
310  }
311 
312  // Read the point section.
313  index = 0;
314  attribindex = 0;
315  for (i = 0; i < numberofpoints; i++) {
316  stringptr = readnumberline(inputline, infile, infilename);
317  if (useindex) {
318  if (i == 0) {
319  firstnode = (int) strtol (stringptr, &stringptr, 0);
320  if ((firstnode == 0) || (firstnode == 1)) {
321  firstnumber = firstnode;
322  }
323  }
324  stringptr = findnextnumber(stringptr);
325  } // if (useindex)
326  if (*stringptr == '\0') {
327  printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
328  break;
329  }
330  x = (REAL) strtod(stringptr, &stringptr);
331  stringptr = findnextnumber(stringptr);
332  if (*stringptr == '\0') {
333  printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
334  break;
335  }
336  y = (REAL) strtod(stringptr, &stringptr);
337  if (mesh_dim == 3) {
338  stringptr = findnextnumber(stringptr);
339  if (*stringptr == '\0') {
340  printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
341  break;
342  }
343  z = (REAL) strtod(stringptr, &stringptr);
344  } else {
345  z = 0.0; // mesh_dim == 2;
346  }
347  pointlist[index++] = x;
348  pointlist[index++] = y;
349  pointlist[index++] = z;
350  // Read the point attributes.
351  for (j = 0; j < numberofpointattributes; j++) {
352  stringptr = findnextnumber(stringptr);
353  if (*stringptr == '\0') {
354  attrib = 0.0;
355  } else {
356  attrib = (REAL) strtod(stringptr, &stringptr);
357  }
358  pointattributelist[attribindex++] = attrib;
359  }
360  if (markers) {
361  // Read a point marker.
362  stringptr = findnextnumber(stringptr);
363  if (*stringptr == '\0') {
364  currentmarker = 0;
365  } else {
366  currentmarker = (int) strtol (stringptr, &stringptr, 0);
367  }
368  pointmarkerlist[i] = currentmarker;
369  }
370  }
371  if (i < numberofpoints) {
372  // Failed to read points due to some error.
373  delete [] pointlist;
374  pointlist = (REAL *) NULL;
375  if (markers) {
376  delete [] pointmarkerlist;
377  pointmarkerlist = (int *) NULL;
378  }
379  if (numberofpointattributes > 0) {
380  delete [] pointattributelist;
381  pointattributelist = (REAL *) NULL;
382  }
383  numberofpoints = 0;
384  return false;
385  }
386  return true;
387 }
388 
390 // //
391 // load_node() Load a list of nodes from a .node file. //
392 // //
393 // 'filename' is the inputfile without suffix. The node list is in 'filename.//
394 // node'. On completion, the node list is returned in 'pointlist'. //
395 // //
397 
398 bool tetgenio::load_node(char* filename)
399 {
400  FILE *infile;
401  char innodefilename[FILENAMESIZE];
402  char inputline[INPUTLINESIZE];
403  char *stringptr;
404  int markers;
405 
406  markers = 0;
407  // Assembling the actual file names we want to open.
408  strcpy(innodefilename, filename);
409  strcat(innodefilename, ".node");
410 
411  // Try to open a .node file.
412  infile = fopen(innodefilename, "r");
413  if (infile == (FILE *) NULL) {
414  printf("File I/O Error: Cannot access file %s.\n", innodefilename);
415  return false;
416  }
417  printf("Opening %s.\n", innodefilename);
418  // Read the first line of the file.
419  stringptr = readnumberline(inputline, infile, innodefilename);
420  // Is this list of points generated from rbox?
421  stringptr = strstr(inputline, "rbox");
422  if (stringptr == NULL) {
423  // Read number of points, number of dimensions, number of point
424  // attributes, and number of boundary markers.
425  stringptr = inputline;
426  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
427  stringptr = findnextnumber(stringptr);
428  if (*stringptr == '\0') {
429  mesh_dim = 3;
430  } else {
431  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
432  }
433  stringptr = findnextnumber(stringptr);
434  if (*stringptr == '\0') {
435  numberofpointattributes = 0;
436  } else {
437  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
438  }
439  stringptr = findnextnumber(stringptr);
440  if (*stringptr == '\0') {
441  markers = 0;
442  } else {
443  markers = (int) strtol (stringptr, &stringptr, 0);
444  }
445  } else {
446  // It is a rbox (qhull) input file.
447  stringptr = inputline;
448  // Get the dimension.
449  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
450  // Get the number of points.
451  stringptr = readnumberline(inputline, infile, innodefilename);
452  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
453  // There is no index column.
454  useindex = 0;
455  }
456 
457  // if ((mesh_dim != 3) && (mesh_dim != 2)) {
458  // printf("Input error: TetGen only works for 2D & 3D point sets.\n");
459  // fclose(infile);
460  // return false;
461  // }
462  if (numberofpoints < (mesh_dim + 1)) {
463  printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
464  fclose(infile);
465  return false;
466  }
467 
468  // Load the list of nodes.
469  if (!load_node_call(infile, markers, innodefilename)) {
470  fclose(infile);
471  return false;
472  }
473  fclose(infile);
474  return true;
475 }
476 
478 // //
479 // load_pbc() Load a list of pbc groups into 'pbcgrouplist'. //
480 // //
481 // 'filename' is the filename of the original inputfile without suffix. The //
482 // pbc groups are found in file 'filename.pbc'. //
483 // //
484 // This routine will be called both in load_poly() and load_tetmesh(). //
485 // //
487 
488 bool tetgenio::load_pbc(char* filename)
489 {
490  FILE *infile;
491  char pbcfilename[FILENAMESIZE];
492  char inputline[INPUTLINESIZE];
493  char *stringptr;
494  pbcgroup *pg;
495  int index, p1, p2;
496  int i, j, k;
497 
498  // Pbc groups are saved in file "filename.pbc".
499  strcpy(pbcfilename, filename);
500  strcat(pbcfilename, ".pbc");
501  infile = fopen(pbcfilename, "r");
502  if (infile != (FILE *) NULL) {
503  printf("Opening %s.\n", pbcfilename);
504  } else {
505  // No such file. Return.
506  return false;
507  }
508 
509  // Read the number of pbc groups.
510  stringptr = readnumberline(inputline, infile, pbcfilename);
511  numberofpbcgroups = (int) strtol (stringptr, &stringptr, 0);
512  if (numberofpbcgroups == 0) {
513  // It looks this file contains no point.
514  fclose(infile);
515  return false;
516  }
517  // Initialize 'pbcgrouplist';
518  pbcgrouplist = new pbcgroup[numberofpbcgroups];
519 
520  // Read the list of pbc groups.
521  for (i = 0; i < numberofpbcgroups; i++) {
522  pg = &(pbcgrouplist[i]);
523  // Initialize pbcgroup i;
524  pg->numberofpointpairs = 0;
525  pg->pointpairlist = (int *) NULL;
526  // Read 'fmark1', 'fmark2'.
527  stringptr = readnumberline(inputline, infile, pbcfilename);
528  if (*stringptr == '\0') break;
529  pg->fmark1 = (int) strtol(stringptr, &stringptr, 0);
530  stringptr = findnextnumber(stringptr);
531  if (*stringptr == '\0') break;
532  pg->fmark2 = (int) strtol(stringptr, &stringptr, 0);
533  // Read 'transmat'.
534  do {
535  stringptr = readline(inputline, infile, NULL);
536  } while ((*stringptr != '[') && (*stringptr != '\0'));
537  if (*stringptr == '\0') break;
538  for (j = 0; j < 4; j++) {
539  for (k = 0; k < 4; k++) {
540  // Read the entry of [j, k].
541  stringptr = findnextnumber(stringptr);
542  if (*stringptr == '\0') {
543  // Try to read another line.
544  stringptr = readnumberline(inputline, infile, pbcfilename);
545  if (*stringptr == '\0') break;
546  }
547  pg->transmat[j][k] = (REAL) strtod(stringptr, &stringptr);
548  }
549  if (k < 4) break; // Not complete!
550  }
551  if (j < 4) break; // Not complete!
552  // Read 'numberofpointpairs'.
553  stringptr = readnumberline(inputline, infile, pbcfilename);
554  if (*stringptr == '\0') break;
555  pg->numberofpointpairs = (int) strtol(stringptr, &stringptr, 0);
556  if (pg->numberofpointpairs > 0) {
557  pg->pointpairlist = new int[pg->numberofpointpairs * 2];
558  // Read the point pairs.
559  index = 0;
560  for (j = 0; j < pg->numberofpointpairs; j++) {
561  stringptr = readnumberline(inputline, infile, pbcfilename);
562  p1 = (int) strtol(stringptr, &stringptr, 0);
563  stringptr = findnextnumber(stringptr);
564  p2 = (int) strtol(stringptr, &stringptr, 0);
565  pg->pointpairlist[index++] = p1;
566  pg->pointpairlist[index++] = p2;
567  }
568  }
569  }
570  fclose(infile);
571 
572  if (i < numberofpbcgroups) {
573  // Failed to read to additional points due to some error.
574  delete [] pbcgrouplist;
575  pbcgrouplist = (pbcgroup *) NULL;
576  numberofpbcgroups = 0;
577  return false;
578  }
579  return true;
580 }
581 
583 // //
584 // load_var() Load variant constraints applied on facets, segments, nodes.//
585 // //
586 // 'filename' is the filename of the original inputfile without suffix. The //
587 // constraints are found in file 'filename.var'. //
588 // //
590 
591 bool tetgenio::load_var(char* filename)
592 {
593  FILE *infile;
594  char varfilename[FILENAMESIZE];
595  char inputline[INPUTLINESIZE];
596  char *stringptr;
597  int index;
598  int i;
599 
600  // Variant constraints are saved in file "filename.var".
601  strcpy(varfilename, filename);
602  strcat(varfilename, ".var");
603  infile = fopen(varfilename, "r");
604  if (infile != (FILE *) NULL) {
605  printf("Opening %s.\n", varfilename);
606  } else {
607  // No such file. Return.
608  return false;
609  }
610 
611  // Read the facet constraint section.
612  stringptr = readnumberline(inputline, infile, varfilename);
613  if (*stringptr != '\0') {
614  numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
615  } else {
616  numberoffacetconstraints = 0;
617  }
618  if (numberoffacetconstraints > 0) {
619  // Initialize 'facetconstraintlist'.
620  facetconstraintlist = new REAL[numberoffacetconstraints * 2];
621  index = 0;
622  for (i = 0; i < numberoffacetconstraints; i++) {
623  stringptr = readnumberline(inputline, infile, varfilename);
624  stringptr = findnextnumber(stringptr);
625  if (*stringptr == '\0') {
626  printf("Error: facet constraint %d has no facet marker.\n",
627  firstnumber + i);
628  break;
629  } else {
630  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
631  }
632  stringptr = findnextnumber(stringptr);
633  if (*stringptr == '\0') {
634  printf("Error: facet constraint %d has no maximum area bound.\n",
635  firstnumber + i);
636  break;
637  } else {
638  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
639  }
640  }
641  if (i < numberoffacetconstraints) {
642  // This must be caused by an error.
643  fclose(infile);
644  return false;
645  }
646  }
647 
648  // Read the segment constraint section.
649  stringptr = readnumberline(inputline, infile, varfilename);
650  if (*stringptr != '\0') {
651  numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
652  } else {
653  numberofsegmentconstraints = 0;
654  }
655  if (numberofsegmentconstraints > 0) {
656  // Initialize 'segmentconstraintlist'.
657  segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
658  index = 0;
659  for (i = 0; i < numberofsegmentconstraints; i++) {
660  stringptr = readnumberline(inputline, infile, varfilename);
661  stringptr = findnextnumber(stringptr);
662  if (*stringptr == '\0') {
663  printf("Error: segment constraint %d has no frist endpoint.\n",
664  firstnumber + i);
665  break;
666  } else {
667  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
668  }
669  stringptr = findnextnumber(stringptr);
670  if (*stringptr == '\0') {
671  printf("Error: segment constraint %d has no second endpoint.\n",
672  firstnumber + i);
673  break;
674  } else {
675  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
676  }
677  stringptr = findnextnumber(stringptr);
678  if (*stringptr == '\0') {
679  printf("Error: segment constraint %d has no maximum length bound.\n",
680  firstnumber + i);
681  break;
682  } else {
683  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
684  }
685  }
686  if (i < numberofsegmentconstraints) {
687  // This must be caused by an error.
688  fclose(infile);
689  return false;
690  }
691  }
692 
693  fclose(infile);
694  return true;
695 }
696 
698 // //
699 // load_mtr() Load a size specification map from file. //
700 // //
701 // 'filename' is the filename of the original inputfile without suffix. The //
702 // size map is found in file 'filename.mtr'. //
703 // //
705 
706 bool tetgenio::load_mtr(char* filename)
707 {
708  FILE *infile;
709  char mtrfilename[FILENAMESIZE];
710  char inputline[INPUTLINESIZE];
711  char *stringptr;
712  REAL mtr;
713  int mtrindex;
714  int i, j;
715 
716  strcpy(mtrfilename, filename);
717  strcat(mtrfilename, ".mtr");
718  infile = fopen(mtrfilename, "r");
719  if (infile != (FILE *) NULL) {
720  printf("Opening %s.\n", mtrfilename);
721  } else {
722  // No such file. Return.
723  return false;
724  }
725 
726  // Read number of points, number of columns (1, 3, or 6).
727  stringptr = readnumberline(inputline, infile, mtrfilename);
728  stringptr = findnextnumber(stringptr); // Skip number of points.
729  if (*stringptr != '\0') {
730  numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
731  }
732  if (numberofpointmtrs == 0) {
733  // Column number doesn't match. Set a default number (1).
734  numberofpointmtrs = 1;
735  }
736 
737  // Allocate space for pointmtrlist.
738  pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
739  if (pointmtrlist == (REAL *) NULL) {
740  printf("Error: Out of memory.\n");
741  terminatetetgen(1);
742  }
743  mtrindex = 0;
744  for (i = 0; i < numberofpoints; i++) {
745  // Read metrics.
746  stringptr = readnumberline(inputline, infile, mtrfilename);
747  for (j = 0; j < numberofpointmtrs; j++) {
748  if (*stringptr == '\0') {
749  printf("Error: Metric %d is missing value #%d in %s.\n",
750  i + firstnumber, j + 1, mtrfilename);
751  terminatetetgen(1);
752  }
753  mtr = (REAL) strtod(stringptr, &stringptr);
754  pointmtrlist[mtrindex++] = mtr;
755  stringptr = findnextnumber(stringptr);
756  }
757  }
758 
759  fclose(infile);
760  return true;
761 }
762 
764 // //
765 // load_poly() Load a piecewise linear complex from a .poly or .smesh. //
766 // //
767 // 'filename' is the inputfile without suffix. The PLC is in 'filename.poly' //
768 // or 'filename.smesh', and possibly plus 'filename.node' (when the first //
769 // line of the file starts with a zero). //
770 // //
772 
773 bool tetgenio::load_poly(char* filename)
774 {
775  FILE *infile, *polyfile;
776  char innodefilename[FILENAMESIZE];
777  char inpolyfilename[FILENAMESIZE];
778  char insmeshfilename[FILENAMESIZE];
779  char inputline[INPUTLINESIZE];
780  char *stringptr, *infilename;
781  int smesh, markers, currentmarker;
782  int readnodefile, index;
783  int i, j, k;
784 
785  // Assembling the actual file names we want to open.
786  strcpy(innodefilename, filename);
787  strcpy(inpolyfilename, filename);
788  strcpy(insmeshfilename, filename);
789  strcat(innodefilename, ".node");
790  strcat(inpolyfilename, ".poly");
791  strcat(insmeshfilename, ".smesh");
792 
793  // First assume it is a .poly file.
794  smesh = 0;
795  // Try to open a .poly file.
796  polyfile = fopen(inpolyfilename, "r");
797  if (polyfile == (FILE *) NULL) {
798  // .poly doesn't exist! Try to open a .smesh file.
799  polyfile = fopen(insmeshfilename, "r");
800  if (polyfile == (FILE *) NULL) {
801  printf("File I/O Error: Cannot access file %s and %s.\n",
802  inpolyfilename, insmeshfilename);
803  return false;
804  } else {
805  printf("Opening %s.\n", insmeshfilename);
806  }
807  smesh = 1;
808  } else {
809  printf("Opening %s.\n", inpolyfilename);
810  }
811  // Initialize the default values.
812  mesh_dim = 3; // Three-dimemsional accoordinates.
813  numberofpointattributes = 0; // no point attribute.
814  markers = 0; // no boundary marker.
815  // Read number of points, number of dimensions, number of point
816  // attributes, and number of boundary markers.
817  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
818  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
819  stringptr = findnextnumber(stringptr);
820  if (*stringptr != '\0') {
821  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
822  }
823  stringptr = findnextnumber(stringptr);
824  if (*stringptr != '\0') {
825  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
826  }
827  stringptr = findnextnumber(stringptr);
828  if (*stringptr != '\0') {
829  markers = (int) strtol (stringptr, &stringptr, 0);
830  }
831  if (numberofpoints > 0) {
832  readnodefile = 0;
833  if (smesh) {
834  infilename = insmeshfilename;
835  } else {
836  infilename = inpolyfilename;
837  }
838  infile = polyfile;
839  } else {
840  // If the .poly or .smesh file claims there are zero points, that
841  // means the points should be read from a separate .node file.
842  readnodefile = 1;
843  infilename = innodefilename;
844  }
845 
846  if (readnodefile) {
847  // Read the points from the .node file.
848  printf("Opening %s.\n", innodefilename);
849  infile = fopen(innodefilename, "r");
850  if (infile == (FILE *) NULL) {
851  printf("File I/O Error: Cannot access file %s.\n", innodefilename);
852  return false;
853  }
854  // Initialize the default values.
855  mesh_dim = 3; // Three-dimemsional accoordinates.
856  numberofpointattributes = 0; // no point attribute.
857  markers = 0; // no boundary marker.
858  // Read number of points, number of dimensions, number of point
859  // attributes, and number of boundary markers.
860  stringptr = readnumberline(inputline, infile, innodefilename);
861  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
862  stringptr = findnextnumber(stringptr);
863  if (*stringptr != '\0') {
864  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
865  }
866  stringptr = findnextnumber(stringptr);
867  if (*stringptr != '\0') {
868  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
869  }
870  stringptr = findnextnumber(stringptr);
871  if (*stringptr != '\0') {
872  markers = (int) strtol (stringptr, &stringptr, 0);
873  }
874  }
875 
876  if ((mesh_dim != 3) && (mesh_dim != 2)) {
877  printf("Input error: TetGen only works for 2D & 3D point sets.\n");
878  fclose(infile);
879  return false;
880  }
881  if (numberofpoints < (mesh_dim + 1)) {
882  printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
883  fclose(infile);
884  return false;
885  }
886 
887  // Load the list of nodes.
888  if (!load_node_call(infile, markers, infilename)) {
889  fclose(infile);
890  return false;
891  }
892 
893  if (readnodefile) {
894  fclose(infile);
895  }
896 
897  facet *f;
898  polygon *p;
899 
900  if (mesh_dim == 3) {
901 
902  // Read number of facets and number of boundary markers.
903  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
904  numberoffacets = (int) strtol (stringptr, &stringptr, 0);
905  if (numberoffacets <= 0) {
906  // No facet list, return.
907  fclose(polyfile);
908  return true;
909  }
910  stringptr = findnextnumber(stringptr);
911  if (*stringptr == '\0') {
912  markers = 0; // no boundary marker.
913  } else {
914  markers = (int) strtol (stringptr, &stringptr, 0);
915  }
916 
917  // Initialize the 'facetlist', 'facetmarkerlist'.
918  facetlist = new facet[numberoffacets];
919  if (markers == 1) {
920  facetmarkerlist = new int[numberoffacets];
921  }
922 
923  // Read data into 'facetlist', 'facetmarkerlist'.
924  if (smesh == 0) {
925  // Facets are in .poly file format.
926  for (i = 1; i <= numberoffacets; i++) {
927  f = &(facetlist[i - 1]);
928  init(f);
929  f->numberofholes = 0;
930  currentmarker = 0;
931  // Read number of polygons, number of holes, and a boundary marker.
932  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
933  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
934  stringptr = findnextnumber(stringptr);
935  if (*stringptr != '\0') {
936  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
937  if (markers == 1) {
938  stringptr = findnextnumber(stringptr);
939  if (*stringptr != '\0') {
940  currentmarker = (int) strtol(stringptr, &stringptr, 0);
941  }
942  }
943  }
944  // Initialize facetmarker if it needs.
945  if (markers == 1) {
946  facetmarkerlist[i - 1] = currentmarker;
947  }
948  // Each facet should has at least one polygon.
949  if (f->numberofpolygons <= 0) {
950  printf("Error: Wrong number of polygon in %d facet.\n", i);
951  break;
952  }
953  // Initialize the 'f->polygonlist'.
954  f->polygonlist = new polygon[f->numberofpolygons];
955  // Go through all polygons, read in their vertices.
956  for (j = 1; j <= f->numberofpolygons; j++) {
957  p = &(f->polygonlist[j - 1]);
958  init(p);
959  // Read number of vertices of this polygon.
960  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
961  p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
962  if (p->numberofvertices < 1) {
963  printf("Error: Wrong polygon %d in facet %d\n", j, i);
964  break;
965  }
966  // Initialize 'p->vertexlist'.
967  p->vertexlist = new int[p->numberofvertices];
968  // Read all vertices of this polygon.
969  for (k = 1; k <= p->numberofvertices; k++) {
970  stringptr = findnextnumber(stringptr);
971  if (*stringptr == '\0') {
972  // Try to load another non-empty line and continue to read the
973  // rest of vertices.
974  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
975  if (*stringptr == '\0') {
976  printf("Error: Missing %d endpoints of polygon %d in facet %d",
977  p->numberofvertices - k, j, i);
978  break;
979  }
980  }
981  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
982  }
983  }
984  if (j <= f->numberofpolygons) {
985  // This must be caused by an error. However, there're j - 1
986  // polygons have been read. Reset the 'f->numberofpolygon'.
987  if (j == 1) {
988  // This is the first polygon.
989  delete [] f->polygonlist;
990  }
991  f->numberofpolygons = j - 1;
992  // No hole will be read even it exists.
993  f->numberofholes = 0;
994  break;
995  }
996  // If this facet has hole pints defined, read them.
997  if (f->numberofholes > 0) {
998  // Initialize 'f->holelist'.
999  f->holelist = new REAL[f->numberofholes * 3];
1000  // Read the holes' coordinates.
1001  index = 0;
1002  for (j = 1; j <= f->numberofholes; j++) {
1003  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1004  for (k = 1; k <= 3; k++) {
1005  stringptr = findnextnumber(stringptr);
1006  if (*stringptr == '\0') {
1007  printf("Error: Hole %d in facet %d has no coordinates", j, i);
1008  break;
1009  }
1010  f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1011  }
1012  if (k <= 3) {
1013  // This must be caused by an error.
1014  break;
1015  }
1016  }
1017  if (j <= f->numberofholes) {
1018  // This must be caused by an error.
1019  break;
1020  }
1021  }
1022  }
1023  if (i <= numberoffacets) {
1024  // This must be caused by an error.
1025  numberoffacets = i - 1;
1026  fclose(polyfile);
1027  return false;
1028  }
1029  } else { // poly == 0
1030  // Read the facets from a .smesh file.
1031  for (i = 1; i <= numberoffacets; i++) {
1032  f = &(facetlist[i - 1]);
1033  init(f);
1034  // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1035  // contains exactly one polygon, no hole.
1036  f->numberofpolygons = 1;
1037  f->polygonlist = new polygon[f->numberofpolygons];
1038  p = &(f->polygonlist[0]);
1039  init(p);
1040  // Read number of vertices of this polygon.
1041  stringptr = readnumberline(inputline, polyfile, insmeshfilename);
1042  p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1043  if (p->numberofvertices < 1) {
1044  printf("Error: Wrong number of vertex in facet %d\n", i);
1045  break;
1046  }
1047  // Initialize 'p->vertexlist'.
1048  p->vertexlist = new int[p->numberofvertices];
1049  for (k = 1; k <= p->numberofvertices; k++) {
1050  stringptr = findnextnumber(stringptr);
1051  if (*stringptr == '\0') {
1052  // Try to load another non-empty line and continue to read the
1053  // rest of vertices.
1054  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1055  if (*stringptr == '\0') {
1056  printf("Error: Missing %d endpoints in facet %d",
1057  p->numberofvertices - k, i);
1058  break;
1059  }
1060  }
1061  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1062  }
1063  if (k <= p->numberofvertices) {
1064  // This must be caused by an error.
1065  break;
1066  }
1067  // Read facet's boundary marker at last.
1068  if (markers == 1) {
1069  stringptr = findnextnumber(stringptr);
1070  if (*stringptr == '\0') {
1071  currentmarker = 0;
1072  } else {
1073  currentmarker = (int) strtol(stringptr, &stringptr, 0);
1074  }
1075  facetmarkerlist[i - 1] = currentmarker;
1076  }
1077  }
1078  if (i <= numberoffacets) {
1079  // This must be caused by an error.
1080  numberoffacets = i - 1;
1081  fclose(polyfile);
1082  return false;
1083  }
1084  }
1085 
1086  // Read the hole section.
1087  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1088  if (*stringptr != '\0') {
1089  numberofholes = (int) strtol (stringptr, &stringptr, 0);
1090  } else {
1091  numberofholes = 0;
1092  }
1093  if (numberofholes > 0) {
1094  // Initialize 'holelist'.
1095  holelist = new REAL[numberofholes * 3];
1096  for (i = 0; i < 3 * numberofholes; i += 3) {
1097  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1098  stringptr = findnextnumber(stringptr);
1099  if (*stringptr == '\0') {
1100  printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1101  break;
1102  } else {
1103  holelist[i] = (REAL) strtod(stringptr, &stringptr);
1104  }
1105  stringptr = findnextnumber(stringptr);
1106  if (*stringptr == '\0') {
1107  printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1108  break;
1109  } else {
1110  holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1111  }
1112  stringptr = findnextnumber(stringptr);
1113  if (*stringptr == '\0') {
1114  printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1115  break;
1116  } else {
1117  holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1118  }
1119  }
1120  if (i < 3 * numberofholes) {
1121  // This must be caused by an error.
1122  fclose(polyfile);
1123  return false;
1124  }
1125  }
1126 
1127  // Read the region section. The 'region' section is optional, if we
1128  // don't reach the end-of-file, try read it in.
1129  stringptr = readnumberline(inputline, polyfile, NULL);
1130  if (stringptr != (char *) NULL && *stringptr != '\0') {
1131  numberofregions = (int) strtol (stringptr, &stringptr, 0);
1132  } else {
1133  numberofregions = 0;
1134  }
1135  if (numberofregions > 0) {
1136  // Initialize 'regionlist'.
1137  regionlist = new REAL[numberofregions * 5];
1138  index = 0;
1139  for (i = 0; i < numberofregions; i++) {
1140  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1141  stringptr = findnextnumber(stringptr);
1142  if (*stringptr == '\0') {
1143  printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1144  break;
1145  } else {
1146  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1147  }
1148  stringptr = findnextnumber(stringptr);
1149  if (*stringptr == '\0') {
1150  printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1151  break;
1152  } else {
1153  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1154  }
1155  stringptr = findnextnumber(stringptr);
1156  if (*stringptr == '\0') {
1157  printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1158  break;
1159  } else {
1160  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1161  }
1162  stringptr = findnextnumber(stringptr);
1163  if (*stringptr == '\0') {
1164  printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1165  break;
1166  } else {
1167  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1168  }
1169  stringptr = findnextnumber(stringptr);
1170  if (*stringptr == '\0') {
1171  regionlist[index] = regionlist[index - 1];
1172  } else {
1173  regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1174  }
1175  index++;
1176  }
1177  if (i < numberofregions) {
1178  // This must be caused by an error.
1179  fclose(polyfile);
1180  return false;
1181  }
1182  }
1183 
1184  } else {
1185 
1186  // Read a PSLG from Triangle's poly file.
1187  assert(mesh_dim == 2);
1188  // A PSLG is a facet of a PLC.
1189  numberoffacets = 1;
1190  // Initialize the 'facetlist'.
1191  facetlist = new facet[numberoffacets];
1192  facetmarkerlist = (int *) NULL; // No facet markers.
1193  f = &(facetlist[0]);
1194  init(f);
1195  // Read number of segments.
1196  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1197  // Segments are degenerate polygons.
1198  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
1199  if (f->numberofpolygons > 0) {
1200  f->polygonlist = new polygon[f->numberofpolygons];
1201  }
1202  // Go through all segments, read in their vertices.
1203  for (j = 0; j < f->numberofpolygons; j++) {
1204  p = &(f->polygonlist[j]);
1205  init(p);
1206  // Read in a segment.
1207  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1208  stringptr = findnextnumber(stringptr); // Skip its index.
1209  p->numberofvertices = 2; // A segment always has two vertices.
1210  p->vertexlist = new int[p->numberofvertices];
1211  p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
1212  stringptr = findnextnumber(stringptr);
1213  p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
1214  }
1215  // Read number of holes.
1216  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1217  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
1218  if (f->numberofholes > 0) {
1219  // Initialize 'f->holelist'.
1220  f->holelist = new REAL[f->numberofholes * 3];
1221  // Read the holes' coordinates.
1222  for (j = 0; j < f->numberofholes; j++) {
1223  // Read a 2D hole point.
1224  stringptr = readnumberline(inputline, polyfile, inpolyfilename);
1225  stringptr = findnextnumber(stringptr); // Skip its index.
1226  f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
1227  stringptr = findnextnumber(stringptr);
1228  f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
1229  f->holelist[j * 3 + 2] = 0.0; // The z-coord.
1230  }
1231  }
1232  // The regions are skipped.
1233 
1234  }
1235 
1236  // End of reading poly/smesh file.
1237  fclose(polyfile);
1238 
1239  // Try to load a .var file if it exists.
1240  load_var(filename);
1241  // Try to load a .mtr file if it exists.
1242  load_mtr(filename);
1243  // Try to read a .pbc file if it exists.
1244  load_pbc(filename);
1245 
1246  return true;
1247 }
1248 
1250 // //
1251 // load_off() Load a polyhedron described in a .off file. //
1252 // //
1253 // The .off format is one of file formats of the Geomview, an interactive //
1254 // program for viewing and manipulating geometric objects. More information //
1255 // is available form: http://www.geomview.org. //
1256 // //
1257 // 'filename' is a input filename with extension .off or without extension ( //
1258 // the .off will be added in this case). On completion, the polyhedron is //
1259 // returned in 'pointlist' and 'facetlist'. //
1260 // //
1262 
1263 bool tetgenio::load_off(char* filename)
1264 {
1265  FILE *fp;
1266  tetgenio::facet *f;
1267  tetgenio::polygon *p;
1268  char infilename[FILENAMESIZE];
1269  char buffer[INPUTLINESIZE];
1270  char *bufferp;
1271  double *coord;
1272  int nverts = 0, iverts = 0;
1273  int nfaces = 0, ifaces = 0;
1274  int nedges = 0;
1275  int line_count = 0, i;
1276 
1277  strncpy(infilename, filename, 1024 - 1);
1278  infilename[FILENAMESIZE - 1] = '\0';
1279  if (infilename[0] == '\0') {
1280  printf("Error: No filename.\n");
1281  return false;
1282  }
1283  if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1284  strcat(infilename, ".off");
1285  }
1286 
1287  if (!(fp = fopen(infilename, "r"))) {
1288  printf("File I/O Error: Unable to open file %s\n", infilename);
1289  return false;
1290  }
1291  printf("Opening %s.\n", infilename);
1292 
1293  // OFF requires the index starts from '0'.
1294  firstnumber = 0;
1295 
1296  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1297  // Check section
1298  if (nverts == 0) {
1299  // Read header
1300  bufferp = strstr(bufferp, "OFF");
1301  if (bufferp != NULL) {
1302  // Read mesh counts
1303  bufferp = findnextnumber(bufferp); // Skip field "OFF".
1304  if (*bufferp == '\0') {
1305  // Read a non-empty line.
1306  bufferp = readline(buffer, fp, &line_count);
1307  }
1308  if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1309  || (nverts == 0)) {
1310  printf("Syntax error reading header on line %d in file %s\n",
1311  line_count, infilename);
1312  fclose(fp);
1313  return false;
1314  }
1315  // Allocate memory for 'tetgenio'
1316  if (nverts > 0) {
1317  numberofpoints = nverts;
1318  pointlist = new REAL[nverts * 3];
1319  }
1320  if (nfaces > 0) {
1321  numberoffacets = nfaces;
1322  facetlist = new tetgenio::facet[nfaces];
1323  }
1324  }
1325  } else if (iverts < nverts) {
1326  // Read vertex coordinates
1327  coord = &pointlist[iverts * 3];
1328  for (i = 0; i < 3; i++) {
1329  if (*bufferp == '\0') {
1330  printf("Syntax error reading vertex coords on line %d in file %s\n",
1331  line_count, infilename);
1332  fclose(fp);
1333  return false;
1334  }
1335  coord[i] = (REAL) strtod(bufferp, &bufferp);
1336  bufferp = findnextnumber(bufferp);
1337  }
1338  iverts++;
1339  } else if (ifaces < nfaces) {
1340  // Get next face
1341  f = &facetlist[ifaces];
1342  init(f);
1343  // In .off format, each facet has one polygon, no hole.
1344  f->numberofpolygons = 1;
1345  f->polygonlist = new tetgenio::polygon[1];
1346  p = &f->polygonlist[0];
1347  init(p);
1348  // Read the number of vertices, it should be greater than 0.
1349  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1350  if (p->numberofvertices == 0) {
1351  printf("Syntax error reading polygon on line %d in file %s\n",
1352  line_count, infilename);
1353  fclose(fp);
1354  return false;
1355  }
1356  // Allocate memory for face vertices
1357  p->vertexlist = new int[p->numberofvertices];
1358  for (i = 0; i < p->numberofvertices; i++) {
1359  bufferp = findnextnumber(bufferp);
1360  if (*bufferp == '\0') {
1361  printf("Syntax error reading polygon on line %d in file %s\n",
1362  line_count, infilename);
1363  fclose(fp);
1364  return false;
1365  }
1366  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1367  }
1368  ifaces++;
1369  } else {
1370  // Should never get here
1371  printf("Found extra text starting at line %d in file %s\n", line_count,
1372  infilename);
1373  break;
1374  }
1375  }
1376 
1377  // Close file
1378  fclose(fp);
1379 
1380  // Check whether read all points
1381  if (iverts != nverts) {
1382  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1383  nverts, iverts, infilename);
1384  return false;
1385  }
1386 
1387  // Check whether read all faces
1388  if (ifaces != nfaces) {
1389  printf("Expected %d faces, but read only %d faces in file %s\n",
1390  nfaces, ifaces, infilename);
1391  return false;
1392  }
1393 
1394  return true;
1395 }
1396 
1398 // //
1399 // load_ply() Load a polyhedron described in a .ply file. //
1400 // //
1401 // 'filename' is the file name with extension .ply or without extension (the //
1402 // .ply will be added in this case). //
1403 // //
1404 // This is a simplified version of reading .ply files, which only reads the //
1405 // set of vertices and the set of faces. Other informations (such as color, //
1406 // material, texture, etc) in .ply file are ignored. Complete routines for //
1407 // reading and writing ,ply files are available from: http://www.cc.gatech. //
1408 // edu/projects/large_models/ply.html. Except the header section, ply file //
1409 // format has exactly the same format for listing vertices and polygons as //
1410 // off file format. //
1411 // //
1412 // On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
1413 // //
1415 
1416 bool tetgenio::load_ply(char* filename)
1417 {
1418  FILE *fp;
1419  tetgenio::facet *f;
1420  tetgenio::polygon *p;
1421  char infilename[FILENAMESIZE];
1422  char buffer[INPUTLINESIZE];
1423  char *bufferp, *str;
1424  double *coord;
1425  int endheader = 0, format = 0;
1426  int nverts = 0, iverts = 0;
1427  int nfaces = 0, ifaces = 0;
1428  int line_count = 0, i;
1429 
1430  strncpy(infilename, filename, FILENAMESIZE - 1);
1431  infilename[FILENAMESIZE - 1] = '\0';
1432  if (infilename[0] == '\0') {
1433  printf("Error: No filename.\n");
1434  return false;
1435  }
1436  if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1437  strcat(infilename, ".ply");
1438  }
1439 
1440  if (!(fp = fopen(infilename, "r"))) {
1441  printf("Error: Unable to open file %s\n", infilename);
1442  return false;
1443  }
1444  printf("Opening %s.\n", infilename);
1445 
1446  // PLY requires the index starts from '0'.
1447  firstnumber = 0;
1448 
1449  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1450  if (!endheader) {
1451  // Find if it is the keyword "end_header".
1452  str = strstr(bufferp, "end_header");
1453  // strstr() is case sensitive.
1454  if (!str) str = strstr(bufferp, "End_header");
1455  if (!str) str = strstr(bufferp, "End_Header");
1456  if (str) {
1457  // This is the end of the header section.
1458  endheader = 1;
1459  continue;
1460  }
1461  // Parse the number of vertices and the number of faces.
1462  if (nverts == 0 || nfaces == 0) {
1463  // Find if it si the keyword "element".
1464  str = strstr(bufferp, "element");
1465  if (!str) str = strstr(bufferp, "Element");
1466  if (str) {
1467  bufferp = findnextfield(str);
1468  if (*bufferp == '\0') {
1469  printf("Syntax error reading element type on line%d in file %s\n",
1470  line_count, infilename);
1471  fclose(fp);
1472  return false;
1473  }
1474  if (nverts == 0) {
1475  // Find if it is the keyword "vertex".
1476  str = strstr(bufferp, "vertex");
1477  if (!str) str = strstr(bufferp, "Vertex");
1478  if (str) {
1479  bufferp = findnextnumber(str);
1480  if (*bufferp == '\0') {
1481  printf("Syntax error reading vertex number on line");
1482  printf(" %d in file %s\n", line_count, infilename);
1483  fclose(fp);
1484  return false;
1485  }
1486  nverts = (int) strtol(bufferp, &bufferp, 0);
1487  // Allocate memory for 'tetgenio'
1488  if (nverts > 0) {
1489  numberofpoints = nverts;
1490  pointlist = new REAL[nverts * 3];
1491  }
1492  }
1493  }
1494  if (nfaces == 0) {
1495  // Find if it is the keyword "face".
1496  str = strstr(bufferp, "face");
1497  if (!str) str = strstr(bufferp, "Face");
1498  if (str) {
1499  bufferp = findnextnumber(str);
1500  if (*bufferp == '\0') {
1501  printf("Syntax error reading face number on line");
1502  printf(" %d in file %s\n", line_count, infilename);
1503  fclose(fp);
1504  return false;
1505  }
1506  nfaces = (int) strtol(bufferp, &bufferp, 0);
1507  // Allocate memory for 'tetgenio'
1508  if (nfaces > 0) {
1509  numberoffacets = nfaces;
1510  facetlist = new tetgenio::facet[nfaces];
1511  }
1512  }
1513  }
1514  } // It is not the string "element".
1515  }
1516  if (format == 0) {
1517  // Find the keyword "format".
1518  str = strstr(bufferp, "format");
1519  if (!str) str = strstr(bufferp, "Format");
1520  if (str) {
1521  format = 1;
1522  bufferp = findnextfield(str);
1523  // Find if it is the string "ascii".
1524  str = strstr(bufferp, "ascii");
1525  if (!str) str = strstr(bufferp, "ASCII");
1526  if (!str) {
1527  printf("This routine only reads ascii format of ply files.\n");
1528  printf("Hint: You can convert the binary to ascii format by\n");
1529  printf(" using the provided ply tools:\n");
1530  printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1531  fclose(fp);
1532  return false;
1533  }
1534  }
1535  }
1536  } else if (iverts < nverts) {
1537  // Read vertex coordinates
1538  coord = &pointlist[iverts * 3];
1539  for (i = 0; i < 3; i++) {
1540  if (*bufferp == '\0') {
1541  printf("Syntax error reading vertex coords on line %d in file %s\n",
1542  line_count, infilename);
1543  fclose(fp);
1544  return false;
1545  }
1546  coord[i] = (REAL) strtod(bufferp, &bufferp);
1547  bufferp = findnextnumber(bufferp);
1548  }
1549  iverts++;
1550  } else if (ifaces < nfaces) {
1551  // Get next face
1552  f = &facetlist[ifaces];
1553  init(f);
1554  // In .off format, each facet has one polygon, no hole.
1555  f->numberofpolygons = 1;
1556  f->polygonlist = new tetgenio::polygon[1];
1557  p = &f->polygonlist[0];
1558  init(p);
1559  // Read the number of vertices, it should be greater than 0.
1560  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1561  if (p->numberofvertices == 0) {
1562  printf("Syntax error reading polygon on line %d in file %s\n",
1563  line_count, infilename);
1564  fclose(fp);
1565  return false;
1566  }
1567  // Allocate memory for face vertices
1568  p->vertexlist = new int[p->numberofvertices];
1569  for (i = 0; i < p->numberofvertices; i++) {
1570  bufferp = findnextnumber(bufferp);
1571  if (*bufferp == '\0') {
1572  printf("Syntax error reading polygon on line %d in file %s\n",
1573  line_count, infilename);
1574  fclose(fp);
1575  return false;
1576  }
1577  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1578  }
1579  ifaces++;
1580  } else {
1581  // Should never get here
1582  printf("Found extra text starting at line %d in file %s\n", line_count,
1583  infilename);
1584  break;
1585  }
1586  }
1587 
1588  // Close file
1589  fclose(fp);
1590 
1591  // Check whether read all points
1592  if (iverts != nverts) {
1593  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1594  nverts, iverts, infilename);
1595  return false;
1596  }
1597 
1598  // Check whether read all faces
1599  if (ifaces != nfaces) {
1600  printf("Expected %d faces, but read only %d faces in file %s\n",
1601  nfaces, ifaces, infilename);
1602  return false;
1603  }
1604 
1605  return true;
1606 }
1607 
1609 // //
1610 // load_stl() Load a surface mesh described in a .stl file. //
1611 // //
1612 // 'filename' is the file name with extension .stl or without extension (the //
1613 // .stl will be added in this case). //
1614 // //
1615 // The .stl or stereolithography format is an ASCII or binary file used in //
1616 // manufacturing. It is a list of the triangular surfaces that describe a //
1617 // computer generated solid model. This is the standard input for most rapid //
1618 // prototyping machines. //
1619 // //
1620 // On completion, 'pointlist' and 'facetlist' together return the polyhedron.//
1621 // Note: After load_stl(), there exist many duplicated points in 'pointlist'.//
1622 // They will be unified during the Delaunay tetrahedralization process. //
1623 // //
1625 
1626 bool tetgenio::load_stl(char* filename)
1627 {
1628  FILE *fp;
1629  tetgenmesh::list *plist;
1630  tetgenio::facet *f;
1631  tetgenio::polygon *p;
1632  char infilename[FILENAMESIZE];
1633  char buffer[INPUTLINESIZE];
1634  char *bufferp, *str;
1635  double *coord;
1636  int solid = 0;
1637  int nverts = 0, iverts = 0;
1638  int nfaces = 0;
1639  int line_count = 0, i;
1640 
1641  strncpy(infilename, filename, FILENAMESIZE - 1);
1642  infilename[FILENAMESIZE - 1] = '\0';
1643  if (infilename[0] == '\0') {
1644  printf("Error: No filename.\n");
1645  return false;
1646  }
1647  if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1648  strcat(infilename, ".stl");
1649  }
1650 
1651  if (!(fp = fopen(infilename, "r"))) {
1652  printf("Error: Unable to open file %s\n", infilename);
1653  return false;
1654  }
1655  printf("Opening %s.\n", infilename);
1656 
1657  // STL file has no number of points available. Use a list to read points.
1658  plist = new tetgenmesh::list(sizeof(double) * 3, NULL, 1024);
1659 
1660  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1661  // The ASCII .stl file must start with the lower case keyword solid and
1662  // end with endsolid.
1663  if (solid == 0) {
1664  // Read header
1665  bufferp = strstr(bufferp, "solid");
1666  if (bufferp != NULL) {
1667  solid = 1;
1668  }
1669  } else {
1670  // We're inside the block of the solid.
1671  str = bufferp;
1672  // Is this the end of the solid.
1673  bufferp = strstr(bufferp, "endsolid");
1674  if (bufferp != NULL) {
1675  solid = 0;
1676  } else {
1677  // Read the XYZ coordinates if it is a vertex.
1678  bufferp = str;
1679  bufferp = strstr(bufferp, "vertex");
1680  if (bufferp != NULL) {
1681  coord = (double *) plist->append(NULL);
1682  for (i = 0; i < 3; i++) {
1683  bufferp = findnextnumber(bufferp);
1684  if (*bufferp == '\0') {
1685  printf("Syntax error reading vertex coords on line %d\n",
1686  line_count);
1687  delete plist;
1688  fclose(fp);
1689  return false;
1690  }
1691  coord[i] = (REAL) strtod(bufferp, &bufferp);
1692  }
1693  }
1694  }
1695  }
1696  }
1697  fclose(fp);
1698 
1699  nverts = plist->len();
1700  // nverts should be an integer times 3 (every 3 vertices denote a face).
1701  if (nverts == 0 || (nverts % 3 != 0)) {
1702  printf("Error: Wrong number of vertices in file %s.\n", infilename);
1703  delete plist;
1704  return false;
1705  }
1706  numberofpoints = nverts;
1707  pointlist = new REAL[nverts * 3];
1708  for (i = 0; i < nverts; i++) {
1709  coord = (double *) (* plist)[i];
1710  iverts = i * 3;
1711  pointlist[iverts] = (REAL) coord[0];
1712  pointlist[iverts + 1] = (REAL) coord[1];
1713  pointlist[iverts + 2] = (REAL) coord[2];
1714  }
1715 
1716  nfaces = (int) (nverts / 3);
1717  numberoffacets = nfaces;
1718  facetlist = new tetgenio::facet[nfaces];
1719 
1720  // Default use '1' as the array starting index.
1721  firstnumber = 1;
1722  iverts = firstnumber;
1723  for (i = 0; i < nfaces; i++) {
1724  f = &facetlist[i];
1725  init(f);
1726  // In .stl format, each facet has one polygon, no hole.
1727  f->numberofpolygons = 1;
1728  f->polygonlist = new tetgenio::polygon[1];
1729  p = &f->polygonlist[0];
1730  init(p);
1731  // Each polygon has three vertices.
1732  p->numberofvertices = 3;
1733  p->vertexlist = new int[p->numberofvertices];
1734  p->vertexlist[0] = iverts;
1735  p->vertexlist[1] = iverts + 1;
1736  p->vertexlist[2] = iverts + 2;
1737  iverts += 3;
1738  }
1739 
1740  delete plist;
1741  return true;
1742 }
1743 
1745 // //
1746 // load_medit() Load a surface mesh described in .mesh file. //
1747 // //
1748 // 'filename' is the file name with extension .mesh or without entension ( //
1749 // the .mesh will be added in this case). .mesh is the file format of Medit, //
1750 // a user-friendly interactive mesh viewing program. //
1751 // //
1752 // This routine ONLY reads the sections containing vertices, triangles, and //
1753 // quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.//
1754 // //
1756 
1757 bool tetgenio::load_medit(char* filename)
1758 {
1759  FILE *fp;
1760  tetgenio::facet *tmpflist, *f;
1761  tetgenio::polygon *p;
1762  char infilename[FILENAMESIZE];
1763  char buffer[INPUTLINESIZE];
1764  char *bufferp, *str;
1765  double *coord;
1766  int *tmpfmlist;
1767  int dimension = 0;
1768  int nverts = 0;
1769  int nfaces = 0;
1770  int line_count = 0;
1771  int corners = 0; // 3 (triangle) or 4 (quad).
1772  int i, j;
1773 
1774  strncpy(infilename, filename, FILENAMESIZE - 1);
1775  infilename[FILENAMESIZE - 1] = '\0';
1776  if (infilename[0] == '\0') {
1777  printf("Error: No filename.\n");
1778  return false;
1779  }
1780  if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1781  strcat(infilename, ".mesh");
1782  }
1783 
1784  if (!(fp = fopen(infilename, "r"))) {
1785  printf("Error: Unable to open file %s\n", infilename);
1786  return false;
1787  }
1788  printf("Opening %s.\n", infilename);
1789 
1790  // Default uses the index starts from '1'.
1791  firstnumber = 1;
1792 
1793  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1794  if (*bufferp == '#') continue; // A comment line is skipped.
1795  if (dimension == 0) {
1796  // Find if it is the keyword "Dimension".
1797  str = strstr(bufferp, "Dimension");
1798  if (!str) str = strstr(bufferp, "dimension");
1799  if (!str) str = strstr(bufferp, "DIMENSION");
1800  if (str) {
1801  // Read the dimensions
1802  bufferp = findnextnumber(str); // Skip field "Dimension".
1803  if (*bufferp == '\0') {
1804  // Read a non-empty line.
1805  bufferp = readline(buffer, fp, &line_count);
1806  }
1807  dimension = (int) strtol(bufferp, &bufferp, 0);
1808  if (dimension != 2 && dimension != 3) {
1809  printf("Unknown dimension in file on line %d in file %s\n",
1810  line_count, infilename);
1811  fclose(fp);
1812  return false;
1813  }
1814  mesh_dim = dimension;
1815  }
1816  }
1817  if (nverts == 0) {
1818  // Find if it is the keyword "Vertices".
1819  str = strstr(bufferp, "Vertices");
1820  if (!str) str = strstr(bufferp, "vertices");
1821  if (!str) str = strstr(bufferp, "VERTICES");
1822  if (str) {
1823  // Read the number of vertices.
1824  bufferp = findnextnumber(str); // Skip field "Vertices".
1825  if (*bufferp == '\0') {
1826  // Read a non-empty line.
1827  bufferp = readline(buffer, fp, &line_count);
1828  }
1829  nverts = (int) strtol(bufferp, &bufferp, 0);
1830  // Allocate memory for 'tetgenio'
1831  if (nverts > 0) {
1832  numberofpoints = nverts;
1833  pointlist = new REAL[nverts * 3];
1834  }
1835  // Read the follwoing node list.
1836  for (i = 0; i < nverts; i++) {
1837  bufferp = readline(buffer, fp, &line_count);
1838  if (bufferp == NULL) {
1839  printf("Unexpected end of file on line %d in file %s\n",
1840  line_count, infilename);
1841  fclose(fp);
1842  return false;
1843  }
1844  // Read vertex coordinates
1845  coord = &pointlist[i * 3];
1846  for (j = 0; j < 3; j++) {
1847  if (*bufferp == '\0') {
1848  printf("Syntax error reading vertex coords on line");
1849  printf(" %d in file %s\n", line_count, infilename);
1850  fclose(fp);
1851  return false;
1852  }
1853  if ((j < 2) || (dimension == 3)) {
1854  coord[j] = (REAL) strtod(bufferp, &bufferp);
1855  } else {
1856  assert((j == 2) && (dimension == 2));
1857  coord[j] = 0.0;
1858  }
1859  bufferp = findnextnumber(bufferp);
1860  }
1861  }
1862  continue;
1863  }
1864  }
1865  if (nfaces == 0) {
1866  // Find if it is the keyword "Triangles" or "Quadrilaterals".
1867  corners = 0;
1868  str = strstr(bufferp, "Triangles");
1869  if (!str) str = strstr(bufferp, "triangles");
1870  if (!str) str = strstr(bufferp, "TRIANGLES");
1871  if (str) {
1872  corners = 3;
1873  } else {
1874  str = strstr(bufferp, "Quadrilaterals");
1875  if (!str) str = strstr(bufferp, "quadrilaterals");
1876  if (!str) str = strstr(bufferp, "QUADRILATERALS");
1877  if (str) {
1878  corners = 4;
1879  }
1880  }
1881  if (corners == 3 || corners == 4) {
1882  // Read the number of triangles (or quadrilaterals).
1883  bufferp = findnextnumber(str); // Skip field "Triangles".
1884  if (*bufferp == '\0') {
1885  // Read a non-empty line.
1886  bufferp = readline(buffer, fp, &line_count);
1887  }
1888  nfaces = strtol(bufferp, &bufferp, 0);
1889  // Allocate memory for 'tetgenio'
1890  if (nfaces > 0) {
1891  if (numberoffacets > 0) {
1892  // facetlist has already been allocated. Enlarge arrays.
1893  tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1894  tmpfmlist = new int[numberoffacets + nfaces];
1895  // Copy the data of old arrays into new arrays.
1896  for (i = 0; i < numberoffacets; i++) {
1897  f = &(tmpflist[i]);
1898  tetgenio::init(f);
1899  *f = facetlist[i];
1900  tmpfmlist[i] = facetmarkerlist[i];
1901  }
1902  // Release old arrays.
1903  delete [] facetlist;
1904  delete [] facetmarkerlist;
1905  // Remember the new arrays.
1906  facetlist = tmpflist;
1907  facetmarkerlist = tmpfmlist;
1908  } else {
1909  // This is the first time to allocate facetlist.
1910  facetlist = new tetgenio::facet[nfaces];
1911  facetmarkerlist = new int[nfaces];
1912  }
1913  }
1914  // Read the following list of faces.
1915  for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
1916  bufferp = readline(buffer, fp, &line_count);
1917  if (bufferp == NULL) {
1918  printf("Unexpected end of file on line %d in file %s\n",
1919  line_count, infilename);
1920  fclose(fp);
1921  return false;
1922  }
1923  f = &facetlist[i];
1924  tetgenio::init(f);
1925  // In .mesh format, each facet has one polygon, no hole.
1926  f->numberofpolygons = 1;
1927  f->polygonlist = new tetgenio::polygon[1];
1928  p = &f->polygonlist[0];
1929  tetgenio::init(p);
1930  p->numberofvertices = corners;
1931  // Allocate memory for face vertices
1932  p->vertexlist = new int[p->numberofvertices];
1933  // Read the vertices of the face.
1934  for (j = 0; j < corners; j++) {
1935  if (*bufferp == '\0') {
1936  printf("Syntax error reading face on line %d in file %s\n",
1937  line_count, infilename);
1938  fclose(fp);
1939  return false;
1940  }
1941  p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
1942  if (firstnumber == 1) {
1943  // Check if a '0' index appears.
1944  if (p->vertexlist[j] == 0) {
1945  // The first index is set to be 0.
1946  firstnumber = 0;
1947  }
1948  }
1949  bufferp = findnextnumber(bufferp);
1950  }
1951  // Read the marker of the face if it exists.
1952  facetmarkerlist[i] = 0;
1953  if (*bufferp != '\0') {
1954  facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
1955  }
1956  }
1957  // Have read in a list of triangles/quads.
1958  numberoffacets += nfaces;
1959  nfaces = 0;
1960  }
1961  }
1962  // if (nverts > 0 && nfaces > 0) break; // Ignore other data.
1963  }
1964 
1965  // Close file
1966  fclose(fp);
1967 
1968  return true;
1969 }
1970 
1972 // //
1973 // load_plc() Load a piecewise linear complex from file. //
1974 // //
1975 // This is main entrance for loading plcs from different file formats into //
1976 // tetgenio. 'filename' is the input file name without extention. 'object' //
1977 // indicates which file format is used to describ the plc. //
1978 // //
1980 
1981 bool tetgenio::load_plc(char* filename, int object)
1982 {
1983  enum tetgenbehavior::objecttype type;
1984 
1985  type = (enum tetgenbehavior::objecttype) object;
1986  switch (type) {
1987  case tetgenbehavior::NODES:
1988  return load_node(filename);
1989  case tetgenbehavior::POLY:
1990  return load_poly(filename);
1991  case tetgenbehavior::OFF:
1992  return load_off(filename);
1993  case tetgenbehavior::PLY:
1994  return load_ply(filename);
1995  case tetgenbehavior::STL:
1996  return load_stl(filename);
1997  case tetgenbehavior::MEDIT:
1998  return load_medit(filename);
1999  default:
2000  return load_poly(filename);
2001  }
2002 }
2003 
2005 // //
2006 // load_tetmesh() Load a tetrahedral mesh from files. //
2007 // //
2008 // 'filename' is the inputfile without suffix. The nodes of the tetrahedral //
2009 // mesh is in "filename.node", the elements is in "filename.ele", if the //
2010 // "filename.face" and "filename.vol" exists, they will also be read. //
2011 // //
2013 
2014 bool tetgenio::load_tetmesh(char* filename)
2015 {
2016  FILE *infile;
2017  char innodefilename[FILENAMESIZE];
2018  char inelefilename[FILENAMESIZE];
2019  char infacefilename[FILENAMESIZE];
2020  char inedgefilename[FILENAMESIZE];
2021  char involfilename[FILENAMESIZE];
2022  char inputline[INPUTLINESIZE];
2023  char *stringptr, *infilename;
2024  REAL attrib, volume;
2025  int volelements;
2026  int markers, corner;
2027  int index, attribindex;
2028  int i, j;
2029 
2030  markers = 0;
2031 
2032  // Assembling the actual file names we want to open.
2033  strcpy(innodefilename, filename);
2034  strcpy(inelefilename, filename);
2035  strcpy(infacefilename, filename);
2036  strcpy(inedgefilename, filename);
2037  strcpy(involfilename, filename);
2038  strcat(innodefilename, ".node");
2039  strcat(inelefilename, ".ele");
2040  strcat(infacefilename, ".face");
2041  strcat(inedgefilename, ".edge");
2042  strcat(involfilename, ".vol");
2043 
2044  // Read the points from a .node file.
2045  infilename = innodefilename;
2046  printf("Opening %s.\n", infilename);
2047  infile = fopen(infilename, "r");
2048  if (infile == (FILE *) NULL) {
2049  printf("File I/O Error: Cannot access file %s.\n", infilename);
2050  return false;
2051  }
2052  // Read the first line of the file.
2053  stringptr = readnumberline(inputline, infile, infilename);
2054  // Is this list of points generated from rbox?
2055  stringptr = strstr(inputline, "rbox");
2056  if (stringptr == NULL) {
2057  // Read number of points, number of dimensions, number of point
2058  // attributes, and number of boundary markers.
2059  stringptr = inputline;
2060  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
2061  stringptr = findnextnumber(stringptr);
2062  if (*stringptr == '\0') {
2063  mesh_dim = 3;
2064  } else {
2065  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2066  }
2067  stringptr = findnextnumber(stringptr);
2068  if (*stringptr == '\0') {
2069  numberofpointattributes = 0;
2070  } else {
2071  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
2072  }
2073  stringptr = findnextnumber(stringptr);
2074  if (*stringptr == '\0') {
2075  markers = 0; // Default value.
2076  } else {
2077  markers = (int) strtol (stringptr, &stringptr, 0);
2078  }
2079  } else {
2080  // It is a rbox (qhull) input file.
2081  stringptr = inputline;
2082  // Get the dimension.
2083  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2084  // Get the number of points.
2085  stringptr = readnumberline(inputline, infile, infilename);
2086  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
2087  // There is no index column.
2088  useindex = 0;
2089  }
2090 
2091  // Load the list of nodes.
2092  if (!load_node_call(infile, markers, infilename)) {
2093  fclose(infile);
2094  return false;
2095  }
2096  fclose(infile);
2097 
2098  // Read the elements from an .ele file.
2099  if (mesh_dim == 3) {
2100  infilename = inelefilename;
2101  infile = fopen(infilename, "r");
2102  if (infile != (FILE *) NULL) {
2103  printf("Opening %s.\n", infilename);
2104  // Read number of elements, number of corners (4 or 10), number of
2105  // element attributes.
2106  stringptr = readnumberline(inputline, infile, infilename);
2107  numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
2108  stringptr = findnextnumber(stringptr);
2109  if (*stringptr == '\0') {
2110  numberofcorners = 4; // Default read 4 nodes per element.
2111  } else {
2112  numberofcorners = (int) strtol(stringptr, &stringptr, 0);
2113  }
2114  stringptr = findnextnumber(stringptr);
2115  if (*stringptr == '\0') {
2116  numberoftetrahedronattributes = 0; // Default no attribute.
2117  } else {
2118  numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
2119  }
2120  if (numberofcorners != 4 && numberofcorners != 10) {
2121  printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
2122  numberofcorners);
2123  fclose(infile);
2124  return false;
2125  }
2126  // Allocate memory for tetrahedra.
2127  if (numberoftetrahedra > 0) {
2128  tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
2129  if (tetrahedronlist == (int *) NULL) {
2130  printf("Error: Out of memory.\n");
2131  terminatetetgen(1);
2132  }
2133  // Allocate memory for output tetrahedron attributes if necessary.
2134  if (numberoftetrahedronattributes > 0) {
2135  tetrahedronattributelist = new REAL[numberoftetrahedra *
2136  numberoftetrahedronattributes];
2137  if (tetrahedronattributelist == (REAL *) NULL) {
2138  printf("Error: Out of memory.\n");
2139  terminatetetgen(1);
2140  }
2141  }
2142  }
2143  // Read the list of tetrahedra.
2144  index = 0;
2145  attribindex = 0;
2146  for (i = 0; i < numberoftetrahedra; i++) {
2147  // Read tetrahedron index and the tetrahedron's corners.
2148  stringptr = readnumberline(inputline, infile, infilename);
2149  for (j = 0; j < numberofcorners; j++) {
2150  stringptr = findnextnumber(stringptr);
2151  if (*stringptr == '\0') {
2152  printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
2153  i + firstnumber, j + 1, infilename);
2154  terminatetetgen(1);
2155  }
2156  corner = (int) strtol(stringptr, &stringptr, 0);
2157  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2158  printf("Error: Tetrahedron %d has an invalid vertex index.\n",
2159  i + firstnumber);
2160  terminatetetgen(1);
2161  }
2162  tetrahedronlist[index++] = corner;
2163  }
2164  // Read the tetrahedron's attributes.
2165  for (j = 0; j < numberoftetrahedronattributes; j++) {
2166  stringptr = findnextnumber(stringptr);
2167  if (*stringptr == '\0') {
2168  attrib = 0.0;
2169  } else {
2170  attrib = (REAL) strtod(stringptr, &stringptr);
2171  }
2172  tetrahedronattributelist[attribindex++] = attrib;
2173  }
2174  }
2175  fclose(infile);
2176  }
2177  } // if (meshdim == 3)
2178 
2179  // Read the hullfaces or subfaces from a .face file if it exists.
2180  if (mesh_dim == 3) {
2181  infilename = infacefilename;
2182  } else {
2183  infilename = inelefilename;
2184  }
2185  infile = fopen(infilename, "r");
2186  if (infile != (FILE *) NULL) {
2187  printf("Opening %s.\n", infilename);
2188  // Read number of faces, boundary markers.
2189  stringptr = readnumberline(inputline, infile, infilename);
2190  numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
2191  stringptr = findnextnumber(stringptr);
2192  if (mesh_dim == 2) {
2193  // Skip a number.
2194  stringptr = findnextnumber(stringptr);
2195  }
2196  if (*stringptr == '\0') {
2197  markers = 0; // Default there is no marker per face.
2198  } else {
2199  markers = (int) strtol (stringptr, &stringptr, 0);
2200  }
2201  if (numberoftrifaces > 0) {
2202  trifacelist = new int[numberoftrifaces * 3];
2203  if (trifacelist == (int *) NULL) {
2204  printf("Error: Out of memory.\n");
2205  terminatetetgen(1);
2206  }
2207  if (markers) {
2208  trifacemarkerlist = new int[numberoftrifaces * 3];
2209  if (trifacemarkerlist == (int *) NULL) {
2210  printf("Error: Out of memory.\n");
2211  terminatetetgen(1);
2212  }
2213  }
2214  }
2215  // Read the list of faces.
2216  index = 0;
2217  for (i = 0; i < numberoftrifaces; i++) {
2218  // Read face index and the face's three corners.
2219  stringptr = readnumberline(inputline, infile, infilename);
2220  for (j = 0; j < 3; j++) {
2221  stringptr = findnextnumber(stringptr);
2222  if (*stringptr == '\0') {
2223  printf("Error: Face %d is missing vertex %d in %s.\n",
2224  i + firstnumber, j + 1, infilename);
2225  terminatetetgen(1);
2226  }
2227  corner = (int) strtol(stringptr, &stringptr, 0);
2228  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2229  printf("Error: Face %d has an invalid vertex index.\n",
2230  i + firstnumber);
2231  terminatetetgen(1);
2232  }
2233  trifacelist[index++] = corner;
2234  }
2235  // Read the boundary marker if it exists.
2236  if (markers) {
2237  stringptr = findnextnumber(stringptr);
2238  if (*stringptr == '\0') {
2239  attrib = 0.0;
2240  } else {
2241  attrib = (REAL) strtod(stringptr, &stringptr);
2242  }
2243  trifacemarkerlist[i] = (int) attrib;
2244  }
2245  }
2246  fclose(infile);
2247  }
2248 
2249  // Read the boundary edges from a .edge file if it exists.
2250  infilename = inedgefilename;
2251  infile = fopen(infilename, "r");
2252  if (infile != (FILE *) NULL) {
2253  printf("Opening %s.\n", infilename);
2254  // Read number of boundary edges.
2255  stringptr = readnumberline(inputline, infile, infilename);
2256  numberofedges = (int) strtol (stringptr, &stringptr, 0);
2257  if (numberofedges > 0) {
2258  edgelist = new int[numberofedges * 2];
2259  if (edgelist == (int *) NULL) {
2260  printf("Error: Out of memory.\n");
2261  terminatetetgen(1);
2262  }
2263  }
2264  // Read the list of faces.
2265  index = 0;
2266  for (i = 0; i < numberofedges; i++) {
2267  // Read face index and the edge's two endpoints.
2268  stringptr = readnumberline(inputline, infile, infilename);
2269  for (j = 0; j < 2; j++) {
2270  stringptr = findnextnumber(stringptr);
2271  if (*stringptr == '\0') {
2272  printf("Error: Edge %d is missing vertex %d in %s.\n",
2273  i + firstnumber, j + 1, infilename);
2274  terminatetetgen(1);
2275  }
2276  corner = (int) strtol(stringptr, &stringptr, 0);
2277  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
2278  printf("Error: Edge %d has an invalid vertex index.\n",
2279  i + firstnumber);
2280  terminatetetgen(1);
2281  }
2282  edgelist[index++] = corner;
2283  }
2284  }
2285  fclose(infile);
2286  }
2287 
2288  // Read the volume constraints from a .vol file if it exists.
2289  infilename = involfilename;
2290  infile = fopen(infilename, "r");
2291  if (infile != (FILE *) NULL) {
2292  printf("Opening %s.\n", infilename);
2293  // Read number of tetrahedra.
2294  stringptr = readnumberline(inputline, infile, infilename);
2295  volelements = (int) strtol (stringptr, &stringptr, 0);
2296  if (volelements != numberoftetrahedra) {
2297  printf("Warning: %s and %s disagree on number of tetrahedra.\n",
2298  inelefilename, involfilename);
2299  volelements = 0;
2300  }
2301  if (volelements > 0) {
2302  tetrahedronvolumelist = new REAL[volelements];
2303  if (tetrahedronvolumelist == (REAL *) NULL) {
2304  printf("Error: Out of memory.\n");
2305  terminatetetgen(1);
2306  }
2307  }
2308  // Read the list of volume constraints.
2309  for (i = 0; i < volelements; i++) {
2310  stringptr = readnumberline(inputline, infile, infilename);
2311  stringptr = findnextnumber(stringptr);
2312  if (*stringptr == '\0') {
2313  volume = -1.0; // No constraint on this tetrahedron.
2314  } else {
2315  volume = (REAL) strtod(stringptr, &stringptr);
2316  }
2317  tetrahedronvolumelist[i] = volume;
2318  }
2319  fclose(infile);
2320  }
2321 
2322  // Try to load a .mtr file if it exists.
2323  load_mtr(filename);
2324  // Try to read a .pbc file if it exists.
2325  load_pbc(filename);
2326 
2327  return true;
2328 }
2329 
2331 // //
2332 // load_voronoi() Load a Voronoi diagram from files. //
2333 // //
2334 // 'filename' is the inputfile without suffix. The Voronoi diagram is read //
2335 // from files: filename.v.node, filename.v.edge, and filename.v.face. //
2336 // //
2338 
2339 bool tetgenio::load_voronoi(char* filename)
2340 {
2341  FILE *infile;
2342  char innodefilename[FILENAMESIZE];
2343  char inedgefilename[FILENAMESIZE];
2344  char inputline[INPUTLINESIZE];
2345  char *stringptr, *infilename;
2346  voroedge *vedge;
2347  REAL x, y, z;
2348  int firstnode, corner;
2349  int index;
2350  int i, j;
2351 
2352  // Assembling the actual file names we want to open.
2353  strcpy(innodefilename, filename);
2354  strcpy(inedgefilename, filename);
2355  strcat(innodefilename, ".v.node");
2356  strcat(inedgefilename, ".v.edge");
2357 
2358  // Read the points from a .v.node file.
2359  infilename = innodefilename;
2360  printf("Opening %s.\n", infilename);
2361  infile = fopen(infilename, "r");
2362  if (infile == (FILE *) NULL) {
2363  printf("File I/O Error: Cannot access file %s.\n", infilename);
2364  return false;
2365  }
2366  // Read the first line of the file.
2367  stringptr = readnumberline(inputline, infile, infilename);
2368  // Is this list of points generated from rbox?
2369  stringptr = strstr(inputline, "rbox");
2370  if (stringptr == NULL) {
2371  // Read number of points, number of dimensions, number of point
2372  // attributes, and number of boundary markers.
2373  stringptr = inputline;
2374  numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
2375  stringptr = findnextnumber(stringptr);
2376  if (*stringptr == '\0') {
2377  mesh_dim = 3; // Default.
2378  } else {
2379  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2380  }
2381  useindex = 1; // There is an index column.
2382  } else {
2383  // It is a rbox (qhull) input file.
2384  stringptr = inputline;
2385  // Get the dimension.
2386  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
2387  // Get the number of points.
2388  stringptr = readnumberline(inputline, infile, infilename);
2389  numberofvpoints = (int) strtol (stringptr, &stringptr, 0);
2390  useindex = 0; // No index column.
2391  }
2392  // Initialize 'vpointlist'.
2393  vpointlist = new REAL[numberofvpoints * 3];
2394  if (vpointlist == (REAL *) NULL) {
2395  printf("Error: Out of memory.\n");
2396  terminatetetgen(1);
2397  }
2398  // Read the point section.
2399  index = 0;
2400  for (i = 0; i < numberofvpoints; i++) {
2401  stringptr = readnumberline(inputline, infile, infilename);
2402  if (useindex) {
2403  if (i == 0) {
2404  firstnode = (int) strtol (stringptr, &stringptr, 0);
2405  if ((firstnode == 0) || (firstnode == 1)) {
2406  firstnumber = firstnode;
2407  }
2408  }
2409  stringptr = findnextnumber(stringptr);
2410  } // if (useindex)
2411  if (*stringptr == '\0') {
2412  printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
2413  terminatetetgen(1);
2414  }
2415  x = (REAL) strtod(stringptr, &stringptr);
2416  stringptr = findnextnumber(stringptr);
2417  if (*stringptr == '\0') {
2418  printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
2419  terminatetetgen(1);
2420  }
2421  y = (REAL) strtod(stringptr, &stringptr);
2422  if (mesh_dim == 3) {
2423  stringptr = findnextnumber(stringptr);
2424  if (*stringptr == '\0') {
2425  printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
2426  terminatetetgen(1);
2427  }
2428  z = (REAL) strtod(stringptr, &stringptr);
2429  } else {
2430  z = 0.0; // mesh_dim == 2;
2431  }
2432  vpointlist[index++] = x;
2433  vpointlist[index++] = y;
2434  vpointlist[index++] = z;
2435  }
2436  fclose(infile);
2437 
2438  // Read the Voronoi edges from a .v.edge file if it exists.
2439  infilename = inedgefilename;
2440  infile = fopen(infilename, "r");
2441  if (infile != (FILE *) NULL) {
2442  printf("Opening %s.\n", infilename);
2443  // Read number of boundary edges.
2444  stringptr = readnumberline(inputline, infile, infilename);
2445  numberofvedges = (int) strtol (stringptr, &stringptr, 0);
2446  if (numberofvedges > 0) {
2447  vedgelist = new voroedge[numberofvedges];
2448  }
2449  // Read the list of faces.
2450  index = 0;
2451  for (i = 0; i < numberofvedges; i++) {
2452  // Read edge index and the edge's two endpoints.
2453  stringptr = readnumberline(inputline, infile, infilename);
2454  vedge = &(vedgelist[i]);
2455  for (j = 0; j < 2; j++) {
2456  stringptr = findnextnumber(stringptr);
2457  if (*stringptr == '\0') {
2458  printf("Error: Edge %d is missing vertex %d in %s.\n",
2459  i + firstnumber, j + 1, infilename);
2460  terminatetetgen(1);
2461  }
2462  corner = (int) strtol(stringptr, &stringptr, 0);
2463  j == 0 ? vedge->v1 = corner : vedge->v2 = corner;
2464  }
2465  if (vedge->v2 < 0) {
2466  for (j = 0; j < mesh_dim; j++) {
2467  stringptr = findnextnumber(stringptr);
2468  if (*stringptr == '\0') {
2469  printf("Error: Edge %d is missing normal in %s.\n",
2470  i + firstnumber, infilename);
2471  terminatetetgen(1);
2472  }
2473  vedge->vnormal[j] = (REAL) strtod(stringptr, &stringptr);
2474  }
2475  if (mesh_dim == 2) {
2476  vedge->vnormal[2] = 0.0;
2477  }
2478  } else {
2479  vedge->vnormal[0] = 0.0;
2480  vedge->vnormal[1] = 0.0;
2481  vedge->vnormal[2] = 0.0;
2482  }
2483  }
2484  fclose(infile);
2485  }
2486 
2487  return true;
2488 }
2489 
2491 // //
2492 // save_nodes() Save points to a .node file. //
2493 // //
2494 // 'filename' is a string containing the file name without suffix. //
2495 // //
2497 
2498 void tetgenio::save_nodes(char* filename)
2499 {
2500  FILE *fout;
2501  char outnodefilename[FILENAMESIZE];
2502  char outmtrfilename[FILENAMESIZE];
2503  int i, j;
2504 
2505  sprintf(outnodefilename, "%s.node", filename);
2506  printf("Saving nodes to %s\n", outnodefilename);
2507  fout = fopen(outnodefilename, "w");
2508  fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2509  numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2510  for (i = 0; i < numberofpoints; i++) {
2511  if (mesh_dim == 2) {
2512  fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 2],
2513  pointlist[i * 2 + 1]);
2514  } else {
2515  fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2516  pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2517  }
2518  for (j = 0; j < numberofpointattributes; j++) {
2519  fprintf(fout, " %.16g",
2520  pointattributelist[i * numberofpointattributes + j]);
2521  }
2522  if (pointmarkerlist != NULL) {
2523  fprintf(fout, " %d", pointmarkerlist[i]);
2524  }
2525  fprintf(fout, "\n");
2526  }
2527  fclose(fout);
2528 
2529  // If the point metrics exist, output them to a .mtr file.
2530  if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2531  sprintf(outmtrfilename, "%s.mtr", filename);
2532  printf("Saving metrics to %s\n", outmtrfilename);
2533  fout = fopen(outmtrfilename, "w");
2534  fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2535  for (i = 0; i < numberofpoints; i++) {
2536  for (j = 0; j < numberofpointmtrs; j++) {
2537  fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2538  }
2539  fprintf(fout, "\n");
2540  }
2541  fclose(fout);
2542  }
2543 }
2544 
2546 // //
2547 // save_elements() Save elements to a .ele file. //
2548 // //
2549 // 'filename' is a string containing the file name without suffix. //
2550 // //
2552 
2553 void tetgenio::save_elements(char* filename)
2554 {
2555  FILE *fout;
2556  char outelefilename[FILENAMESIZE];
2557  int i, j;
2558 
2559  sprintf(outelefilename, "%s.ele", filename);
2560  printf("Saving elements to %s\n", outelefilename);
2561  fout = fopen(outelefilename, "w");
2562  fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2563  numberoftetrahedronattributes);
2564  for (i = 0; i < numberoftetrahedra; i++) {
2565  fprintf(fout, "%d", i + firstnumber);
2566  for (j = 0; j < numberofcorners; j++) {
2567  fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2568  }
2569  for (j = 0; j < numberoftetrahedronattributes; j++) {
2570  fprintf(fout, " %g",
2571  tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2572  }
2573  fprintf(fout, "\n");
2574  }
2575 
2576  fclose(fout);
2577 }
2578 
2580 // //
2581 // save_faces() Save faces to a .face file. //
2582 // //
2583 // 'filename' is a string containing the file name without suffix. //
2584 // //
2586 
2587 void tetgenio::save_faces(char* filename)
2588 {
2589  FILE *fout;
2590  char outfacefilename[FILENAMESIZE];
2591  int i;
2592 
2593  sprintf(outfacefilename, "%s.face", filename);
2594  printf("Saving faces to %s\n", outfacefilename);
2595  fout = fopen(outfacefilename, "w");
2596  fprintf(fout, "%d %d\n", numberoftrifaces,
2597  trifacemarkerlist != NULL ? 1 : 0);
2598  for (i = 0; i < numberoftrifaces; i++) {
2599  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2600  trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2601  if (trifacemarkerlist != NULL) {
2602  fprintf(fout, " %d", trifacemarkerlist[i]);
2603  }
2604  fprintf(fout, "\n");
2605  }
2606 
2607  fclose(fout);
2608 }
2609 
2611 // //
2612 // save_edges() Save egdes to a .edge file. //
2613 // //
2614 // 'filename' is a string containing the file name without suffix. //
2615 // //
2617 
2618 void tetgenio::save_edges(char* filename)
2619 {
2620  FILE *fout;
2621  char outedgefilename[FILENAMESIZE];
2622  int i;
2623 
2624  sprintf(outedgefilename, "%s.edge", filename);
2625  printf("Saving edges to %s\n", outedgefilename);
2626  fout = fopen(outedgefilename, "w");
2627  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2628  for (i = 0; i < numberofedges; i++) {
2629  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2630  edgelist[i * 2 + 1]);
2631  if (edgemarkerlist != NULL) {
2632  fprintf(fout, " %d", edgemarkerlist[i]);
2633  }
2634  fprintf(fout, "\n");
2635  }
2636 
2637  fclose(fout);
2638 }
2639 
2641 // //
2642 // save_neighbors() Save egdes to a .neigh file. //
2643 // //
2644 // 'filename' is a string containing the file name without suffix. //
2645 // //
2647 
2648 void tetgenio::save_neighbors(char* filename)
2649 {
2650  FILE *fout;
2651  char outneighborfilename[FILENAMESIZE];
2652  int i;
2653 
2654  sprintf(outneighborfilename, "%s.neigh", filename);
2655  printf("Saving neighbors to %s\n", outneighborfilename);
2656  fout = fopen(outneighborfilename, "w");
2657  fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2658  for (i = 0; i < numberoftetrahedra; i++) {
2659  if (mesh_dim == 2) {
2660  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2661  neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2662  } else {
2663  fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2664  neighborlist[i * 4], neighborlist[i * 4 + 1],
2665  neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2666  }
2667  fprintf(fout, "\n");
2668  }
2669 
2670  fclose(fout);
2671 }
2672 
2674 // //
2675 // save_poly() Save segments or facets to a .poly file. //
2676 // //
2677 // 'filename' is a string containing the file name without suffix. It only //
2678 // save the facets, holes and regions. The nodes are saved in a .node file //
2679 // by routine save_nodes(). //
2680 // //
2682 
2683 void tetgenio::save_poly(char* filename)
2684 {
2685  FILE *fout;
2686  facet *f;
2687  polygon *p;
2688  char outpolyfilename[FILENAMESIZE];
2689  int i, j, k;
2690 
2691  sprintf(outpolyfilename, "%s.poly", filename);
2692  printf("Saving poly to %s\n", outpolyfilename);
2693  fout = fopen(outpolyfilename, "w");
2694 
2695  // The zero indicates that the vertices are in a separate .node file.
2696  // Followed by number of dimensions, number of vertex attributes,
2697  // and number of boundary markers (zero or one).
2698  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2699  pointmarkerlist != NULL ? 1 : 0);
2700 
2701  // Save segments or facets.
2702  if (mesh_dim == 2) {
2703  // Number of segments, number of boundary markers (zero or one).
2704  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2705  for (i = 0; i < numberofedges; i++) {
2706  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2707  edgelist[i * 2 + 1]);
2708  if (edgemarkerlist != NULL) {
2709  fprintf(fout, " %d", edgemarkerlist[i]);
2710  }
2711  fprintf(fout, "\n");
2712  }
2713  } else {
2714  // Number of facets, number of boundary markers (zero or one).
2715  fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2716  for (i = 0; i < numberoffacets; i++) {
2717  f = &(facetlist[i]);
2718  fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2719  facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2720  // Output polygons of this facet.
2721  for (j = 0; j < f->numberofpolygons; j++) {
2722  p = &(f->polygonlist[j]);
2723  fprintf(fout, "%d ", p->numberofvertices);
2724  for (k = 0; k < p->numberofvertices; k++) {
2725  if (((k + 1) % 10) == 0) {
2726  fprintf(fout, "\n ");
2727  }
2728  fprintf(fout, " %d", p->vertexlist[k]);
2729  }
2730  fprintf(fout, "\n");
2731  }
2732  // Output holes of this facet.
2733  for (j = 0; j < f->numberofholes; j++) {
2734  fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2735  f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2736  }
2737  }
2738  }
2739 
2740  // Save holes.
2741  fprintf(fout, "%d\n", numberofholes);
2742  for (i = 0; i < numberofholes; i++) {
2743  // Output x, y coordinates.
2744  fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2745  holelist[i * mesh_dim + 1]);
2746  if (mesh_dim == 3) {
2747  // Output z coordinate.
2748  fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2749  }
2750  fprintf(fout, "\n");
2751  }
2752 
2753  // Save regions.
2754  fprintf(fout, "%d\n", numberofregions);
2755  for (i = 0; i < numberofregions; i++) {
2756  if (mesh_dim == 2) {
2757  // Output the index, x, y coordinates, attribute (region number)
2758  // and maximum area constraint (maybe -1).
2759  fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2760  regionlist[i * 4], regionlist[i * 4 + 1],
2761  regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2762  } else {
2763  // Output the index, x, y, z coordinates, attribute (region number)
2764  // and maximum volume constraint (maybe -1).
2765  fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2766  regionlist[i * 5], regionlist[i * 5 + 1],
2767  regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2768  regionlist[i * 5 + 4]);
2769  }
2770  }
2771 
2772  fclose(fout);
2773 }
2774 
2776 // //
2777 // readline() Read a nonempty line from a file. //
2778 // //
2779 // A line is considered "nonempty" if it contains something more than white //
2780 // spaces. If a line is considered empty, it will be dropped and the next //
2781 // line will be read, this process ends until reaching the end-of-file or a //
2782 // non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2783 // a pointer to the first non-whitespace character of the line. //
2784 // //
2786 
2787 char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2788 {
2789  char *result;
2790 
2791  // Search for a non-empty line.
2792  do {
2793  result = fgets(string, INPUTLINESIZE - 1, infile);
2794  if (linenumber) (*linenumber)++;
2795  if (result == (char *) NULL) {
2796  return (char *) NULL;
2797  }
2798  // Skip white spaces.
2799  while ((*result == ' ') || (*result == '\t')) result++;
2800  // If it's end of line, read another line and try again.
2801  } while (*result == '\0');
2802  return result;
2803 }
2804 
2806 // //
2807 // findnextfield() Find the next field of a string. //
2808 // //
2809 // Jumps past the current field by searching for whitespace or a comma, then //
2810 // jumps past the whitespace or the comma to find the next field. //
2811 // //
2813 
2814 char* tetgenio::findnextfield(char *string)
2815 {
2816  char *result;
2817 
2818  result = string;
2819  // Skip the current field. Stop upon reaching whitespace or a comma.
2820  while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2821  (*result != ',') && (*result != ';')) {
2822  result++;
2823  }
2824  // Now skip the whitespace or the comma, stop at anything else that looks
2825  // like a character, or the end of a line.
2826  while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2827  (*result == ';')) {
2828  result++;
2829  }
2830  return result;
2831 }
2832 
2834 // //
2835 // readnumberline() Read a nonempty number line from a file. //
2836 // //
2837 // A line is considered "nonempty" if it contains something that looks like //
2838 // a number. Comments (prefaced by `#') are ignored. //
2839 // //
2841 
2842 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2843 {
2844  char *result;
2845 
2846  // Search for something that looks like a number.
2847  do {
2848  result = fgets(string, INPUTLINESIZE, infile);
2849  if (result == (char *) NULL) {
2850  if (infilename != (char *) NULL) {
2851  printf(" Error: Unexpected end of file in %s.\n", infilename);
2852  terminatetetgen(1);
2853  }
2854  return result;
2855  }
2856  // Skip anything that doesn't look like a number, a comment,
2857  // or the end of a line.
2858  while ((*result != '\0') && (*result != '#')
2859  && (*result != '.') && (*result != '+') && (*result != '-')
2860  && ((*result < '0') || (*result > '9'))) {
2861  result++;
2862  }
2863  // If it's a comment or end of line, read another line and try again.
2864  } while ((*result == '#') || (*result == '\0'));
2865  return result;
2866 }
2867 
2869 // //
2870 // findnextnumber() Find the next field of a number string. //
2871 // //
2872 // Jumps past the current field by searching for whitespace or a comma, then //
2873 // jumps past the whitespace or the comma to find the next field that looks //
2874 // like a number. //
2875 // //
2877 
2878 char* tetgenio::findnextnumber(char *string)
2879 {
2880  char *result;
2881 
2882  result = string;
2883  // Skip the current field. Stop upon reaching whitespace or a comma.
2884  while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2885  (*result != '\t') && (*result != ',')) {
2886  result++;
2887  }
2888  // Now skip the whitespace and anything else that doesn't look like a
2889  // number, a comment, or the end of a line.
2890  while ((*result != '\0') && (*result != '#')
2891  && (*result != '.') && (*result != '+') && (*result != '-')
2892  && ((*result < '0') || (*result > '9'))) {
2893  result++;
2894  }
2895  // Check for a comment (prefixed with `#').
2896  if (*result == '#') {
2897  *result = '\0';
2898  }
2899  return result;
2900 }
2901 
2902 //
2903 // End of class 'tetgenio' implementation
2904 //
2905 
2906 static REAL PI = 3.14159265358979323846264338327950288419716939937510582;
2907 
2908 //
2909 // Begin of class 'tetgenbehavior' implementation
2910 //
2911 
2913 // //
2914 // tetgenbehavior() Initialize veriables of 'tetgenbehavior'. //
2915 // //
2917 
2918 tetgenbehavior::tetgenbehavior()
2919 {
2920  // Initialize command line switches.
2921  plc = 0;
2922  quality = 0;
2923  refine = 0;
2924  coarse = 0;
2925  metric = 0;
2926  minratio = 2.0;
2927  goodratio = 0.0;
2928  minangle = 20.0;
2929  goodangle = 0.0;
2930  maxdihedral = 165.0;
2931  mindihedral = 5.0;
2932  varvolume = 0;
2933  fixedvolume = 0;
2934  maxvolume = -1.0;
2935  regionattrib = 0;
2936  insertaddpoints = 0;
2937  diagnose = 0;
2938  offcenter = 0;
2939  conformdel = 0;
2940  alpha1 = sqrt(2.0);
2941  alpha2 = 1.0;
2942  alpha3 = 0.6;
2943  zeroindex = 0;
2944  facesout = 0;
2945  edgesout = 0;
2946  neighout = 0;
2947  voroout = 0;
2948  meditview = 0;
2949  gidview = 0;
2950  geomview = 0;
2951  optlevel = 3;
2952  optpasses = 3;
2953  order = 1;
2954  nojettison = 0;
2955  nobound = 0;
2956  nonodewritten = 0;
2957  noelewritten = 0;
2958  nofacewritten = 0;
2959  noiterationnum = 0;
2960  nobisect = 0;
2961  noflip = 0;
2962  steiner = -1;
2963  fliprepair = 1;
2964  nomerge = 0;
2965  docheck = 0;
2966  quiet = 0;
2967  verbose = 0;
2968  useshelles = 0;
2969  epsilon = 1.0e-8;
2970  epsilon2 = 1.0e-5;
2971  object = NONE;
2972  // Initialize strings
2973  commandline[0] = '\0';
2974  infilename[0] = '\0';
2975  outfilename[0] = '\0';
2976  addinfilename[0] = '\0';
2977  bgmeshfilename[0] = '\0';
2978 }
2979 
2981 // //
2982 // versioninfo() Print the version information of TetGen. //
2983 // //
2985 
2986 void tetgenbehavior::versioninfo()
2987 {
2988  printf("Version 1.4.2 (April 16, 2007).\n");
2989  printf("\n");
2990  printf("Copyright (C) 2002 - 2007\n");
2991  printf("Hang Si\n");
2992  printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
2993  printf("si@wias-berlin.de\n");
2994 }
2995 
2997 // //
2998 // syntax() Print list of command line switches and exit the program. //
2999 // //
3001 
3002 void tetgenbehavior::syntax()
3003 {
3004  printf(" tetgen [-prq_Ra_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n");
3005  printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
3006  printf(" -r Reconstructs a previously generated mesh.\n");
3007  printf(" -q Quality mesh generation (adding new mesh points to ");
3008  printf("improve mesh quality).\n");
3009  printf(" -R Mesh coarsening (deleting redundant mesh points).\n");
3010  printf(" -a Applies a maximum tetrahedron volume constraint.\n");
3011  printf(" -A Assigns attributes to identify tetrahedra in different ");
3012  printf("regions.\n");
3013  printf(" -i Inserts a list of additional points into mesh.\n");
3014  printf(" -M Does not merge coplanar facets.\n");
3015  printf(" -Y Suppresses boundary facets/segments splitting.\n");
3016  printf(" -S Specifies maximum number of added points.\n");
3017  printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
3018  printf(" -d Detects self-intersections of facets of the PLC.\n");
3019  printf(" -z Numbers all output items starting from zero.\n");
3020  printf(" -o2 Generates second-order subparametric elements.\n");
3021  printf(" -f Outputs all faces to .face file.");
3022  printf("file.\n");
3023  printf(" -e Outputs all edges to .edge file.\n");
3024  printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
3025  printf(" -v Outputs Voronoi diagram to files.\n");
3026  printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
3027  printf(" -G Outputs mesh to .msh file for viewing by Gid.\n");
3028  printf(" -O Outputs mesh to .off file for viewing by Geomview.\n");
3029  printf(" -J No jettison of unused vertices from output .node file.\n");
3030  printf(" -B Suppresses output of boundary information.\n");
3031  printf(" -N Suppresses output of .node file.\n");
3032  printf(" -E Suppresses output of .ele file.\n");
3033  printf(" -F Suppresses output of .face file.\n");
3034  printf(" -I Suppresses mesh iteration numbers.\n");
3035  printf(" -C Checks the consistency of the final mesh.\n");
3036  printf(" -Q Quiet: No terminal output except errors.\n");
3037  printf(" -V Verbose: Detailed information, more terminal output.\n");
3038  printf(" -h Help: A brief instruction for using TetGen.\n");
3039 }
3040 
3042 // //
3043 // usage() Print a brief instruction for using TetGen. //
3044 // //
3046 
3047 void tetgenbehavior::usage()
3048 {
3049  printf("TetGen\n");
3050  printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
3051  printf("Triangulator\n");
3052  versioninfo();
3053  printf("\n");
3054  printf("What Can TetGen Do?\n");
3055  printf("\n");
3056  printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n");
3057  printf(" constrained Delaunay tetrahedralizations, and quality ");
3058  printf("tetrahedral\n meshes. The latter are nicely graded and whose ");
3059  printf("tetrahedra have\n radius-edge ratio bounded, thus are suitable ");
3060  printf("for finite element and\n finite volume analysis.\n");
3061  printf("\n");
3062  printf("Command Line Syntax:\n");
3063  printf("\n");
3064  printf(" Below is the command line syntax of TetGen with a list of ");
3065  printf("short\n");
3066  printf(" descriptions. Underscores indicate that numbers may optionally\n");
3067  printf(" follow certain switches. Do not leave any space between a ");
3068  printf("switch\n");
3069  printf(" and its numeric parameter. \'input_file\' contains input data\n");
3070  printf(" depending on the switches you supplied which may be a ");
3071  printf(" piecewise\n");
3072  printf(" linear complex or a list of nodes. File formats and detailed\n");
3073  printf(" description of command line switches are found in user's ");
3074  printf("manual.\n");
3075  printf("\n");
3076  syntax();
3077  printf("\n");
3078  printf("Examples of How to Use TetGen:\n");
3079  printf("\n");
3080  printf(" \'tetgen object\' reads vertices from object.node, and writes ");
3081  printf("their\n Delaunay tetrahedralization to object.1.node and ");
3082  printf("object.1.ele.\n");
3083  printf("\n");
3084  printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
3085  printf("smesh (and\n possibly object.node) and writes its constrained ");
3086  printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele and ");
3087  printf("object.1.face.\n");
3088  printf("\n");
3089  printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
3090  printf(" object.smesh (and possibly object.node), generates a mesh ");
3091  printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
3092  printf("have volume\n of 0.1 or less, and writes the mesh to ");
3093  printf("object.1.node, object.1.ele\n and object.1.face.\n");
3094  printf("\n");
3095  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3096 }
3097 
3099 // //
3100 // parse_commandline() Read the command line, identify switches, and set //
3101 // up options and file names. //
3102 // //
3103 // 'argc' and 'argv' are the same parameters passed to the function main() //
3104 // of a C/C++ program. They together represent the command line user invoked //
3105 // from an environment in which TetGen is running. //
3106 // //
3107 // When TetGen is invoked from an environment. 'argc' is nonzero, switches //
3108 // and input filename should be supplied as zero-terminated strings in //
3109 // argv[0] through argv[argc - 1] and argv[0] shall be the name used to //
3110 // invoke TetGen, i.e. "tetgen". Switches are previously started with a //
3111 // dash '-' to identify them from the input filename. //
3112 // //
3113 // When TetGen is called from within another program. 'argc' is set to zero. //
3114 // switches are given in one zero-terminated string (no previous dash is //
3115 // required.), and 'argv' is a pointer points to this string. No input //
3116 // filename is required (usually the input data has been directly created by //
3117 // user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' //
3118 // will be created for debugging output purpose. //
3119 // //
3121 
3122 bool tetgenbehavior::parse_commandline(int argc, char **argv)
3123 {
3124  int startindex;
3125  int increment;
3126  int meshnumber;
3127  int scount;
3128  int i, j, k;
3129  char workstring[1024];
3130 
3131  // First determine the input style of the switches.
3132  if (argc == 0) {
3133  startindex = 0; // Switches are given without a dash.
3134  argc = 1; // For running the following for-loop once.
3135  commandline[0] = '\0';
3136  } else {
3137  startindex = 1;
3138  strcpy(commandline, argv[0]);
3139  strcat(commandline, " ");
3140  }
3141 
3142  // Rcount used to count the number of '-R' be used.
3143  scount = 0;
3144 
3145  for (i = startindex; i < argc; i++) {
3146  // Remember the command line switches.
3147  strcat(commandline, argv[i]);
3148  strcat(commandline, " ");
3149  if (startindex == 1) {
3150  // Is this string a filename?
3151  if (argv[i][0] != '-') {
3152  strncpy(infilename, argv[i], 1024 - 1);
3153  infilename[1024 - 1] = '\0';
3154  // Go to the next string directly.
3155  continue;
3156  }
3157  }
3158  // Parse the individual switch from the string.
3159  for (j = startindex; argv[i][j] != '\0'; j++) {
3160  if (argv[i][j] == 'p') {
3161  plc = 1;
3162  } else if (argv[i][j] == 'r') {
3163  refine = 1;
3164  } else if (argv[i][j] == 'R') {
3165  coarse = 1;
3166  } else if (argv[i][j] == 'q') {
3167  quality++;
3168  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3169  (argv[i][j + 1] == '.')) {
3170  k = 0;
3171  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3172  (argv[i][j + 1] == '.')) {
3173  j++;
3174  workstring[k] = argv[i][j];
3175  k++;
3176  }
3177  workstring[k] = '\0';
3178  if (quality == 1) {
3179  minratio = (REAL) strtod(workstring, (char **) NULL);
3180  } else if (quality == 2) {
3181  mindihedral = (REAL) strtod(workstring, (char **) NULL);
3182  } else if (quality == 3) {
3183  maxdihedral = (REAL) strtod(workstring, (char **) NULL);
3184  } else if (quality == 4) {
3185  alpha2 = (REAL) strtod(workstring, (char **) NULL);
3186  } else if (quality == 5) {
3187  alpha1 = (REAL) strtod(workstring, (char **) NULL);
3188  }
3189  }
3190  } else if (argv[i][j] == 'm') {
3191  metric++;
3192  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3193  (argv[i][j + 1] == '.')) {
3194  k = 0;
3195  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3196  (argv[i][j + 1] == '.')) {
3197  j++;
3198  workstring[k] = argv[i][j];
3199  k++;
3200  }
3201  workstring[k] = '\0';
3202  if (metric == 1) {
3203  alpha1 = (REAL) strtod(workstring, (char **) NULL);
3204  } else if (metric == 2) {
3205  alpha2 = (REAL) strtod(workstring, (char **) NULL);
3206  }
3207  }
3208  } else if (argv[i][j] == 'a') {
3209  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3210  (argv[i][j + 1] == '.')) {
3211  fixedvolume = 1;
3212  k = 0;
3213  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3214  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3215  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3216  j++;
3217  workstring[k] = argv[i][j];
3218  k++;
3219  }
3220  workstring[k] = '\0';
3221  maxvolume = (REAL) strtod(workstring, (char **) NULL);
3222  } else {
3223  varvolume = 1;
3224  }
3225  } else if (argv[i][j] == 'A') {
3226  regionattrib++;
3227  } else if (argv[i][j] == 'i') {
3228  insertaddpoints = 1;
3229  } else if (argv[i][j] == 'd') {
3230  diagnose = 1;
3231  } else if (argv[i][j] == 'z') {
3232  zeroindex = 1;
3233  } else if (argv[i][j] == 'f') {
3234  facesout = 1;
3235  } else if (argv[i][j] == 'e') {
3236  edgesout++;
3237  } else if (argv[i][j] == 'n') {
3238  neighout++;
3239  } else if (argv[i][j] == 'v') {
3240  voroout = 1;
3241  } else if (argv[i][j] == 'g') {
3242  meditview = 1;
3243  } else if (argv[i][j] == 'G') {
3244  gidview = 1;
3245  } else if (argv[i][j] == 'O') {
3246  geomview = 1;
3247  } else if (argv[i][j] == 'M') {
3248  nomerge = 1;
3249  } else if (argv[i][j] == 'Y') {
3250  nobisect++;
3251  } else if (argv[i][j] == 'J') {
3252  nojettison = 1;
3253  } else if (argv[i][j] == 'B') {
3254  nobound = 1;
3255  } else if (argv[i][j] == 'N') {
3256  nonodewritten = 1;
3257  } else if (argv[i][j] == 'E') {
3258  noelewritten = 1;
3259  } else if (argv[i][j] == 'F') {
3260  nofacewritten = 1;
3261  } else if (argv[i][j] == 'I') {
3262  noiterationnum = 1;
3263  } else if (argv[i][j] == 'o') {
3264  if (argv[i][j + 1] == '2') {
3265  j++;
3266  order = 2;
3267  }
3268  } else if (argv[i][j] == 'S') {
3269  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3270  (argv[i][j + 1] == '.')) {
3271  k = 0;
3272  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3273  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3274  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3275  j++;
3276  workstring[k] = argv[i][j];
3277  k++;
3278  }
3279  workstring[k] = '\0';
3280  steiner = (int) strtol(workstring, (char **) NULL, 0);
3281  }
3282  } else if (argv[i][j] == 's') {
3283  scount++;
3284  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3285  (argv[i][j + 1] == '.')) {
3286  k = 0;
3287  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3288  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3289  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3290  j++;
3291  workstring[k] = argv[i][j];
3292  k++;
3293  }
3294  workstring[k] = '\0';
3295  if (scount == 1) {
3296  optlevel = (int) strtol(workstring, (char **) NULL, 0);
3297  } else if (scount == 2) {
3298  optpasses = (int) strtol(workstring, (char **) NULL, 0);
3299  }
3300  }
3301  } else if (argv[i][j] == 'D') {
3302  conformdel++;
3303  } else if (argv[i][j] == 'T') {
3304  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3305  (argv[i][j + 1] == '.')) {
3306  k = 0;
3307  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3308  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3309  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3310  j++;
3311  workstring[k] = argv[i][j];
3312  k++;
3313  }
3314  workstring[k] = '\0';
3315  epsilon = (REAL) strtod(workstring, (char **) NULL);
3316  }
3317  } else if (argv[i][j] == 'C') {
3318  docheck++;
3319  } else if (argv[i][j] == 'X') {
3320  fliprepair = 0;
3321  } else if (argv[i][j] == 'Q') {
3322  quiet = 1;
3323  } else if (argv[i][j] == 'V') {
3324  verbose++;
3325  // } else if (argv[i][j] == 'v') {
3326  // versioninfo();
3327  // terminatetetgen(0);
3328  } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
3329  (argv[i][j] == '?')) {
3330  usage();
3331  terminatetetgen(0);
3332  } else {
3333  printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3334  }
3335  }
3336  }
3337 
3338  if (startindex == 0) {
3339  // Set a temporary filename for debugging output.
3340  strcpy(infilename, "tetgen-tmpfile");
3341  } else {
3342  if (infilename[0] == '\0') {
3343  // No input file name. Print the syntax and exit.
3344  syntax();
3345  terminatetetgen(0);
3346  }
3347  // Recognize the object from file extension if it is available.
3348  if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3349  infilename[strlen(infilename) - 5] = '\0';
3350  object = NODES;
3351  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3352  infilename[strlen(infilename) - 5] = '\0';
3353  object = POLY;
3354  plc = 1;
3355  } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3356  infilename[strlen(infilename) - 6] = '\0';
3357  object = POLY;
3358  plc = 1;
3359  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3360  infilename[strlen(infilename) - 4] = '\0';
3361  object = OFF;
3362  plc = 1;
3363  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3364  infilename[strlen(infilename) - 4] = '\0';
3365  object = PLY;
3366  plc = 1;
3367  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3368  infilename[strlen(infilename) - 4] = '\0';
3369  object = STL;
3370  plc = 1;
3371  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3372  infilename[strlen(infilename) - 5] = '\0';
3373  object = MEDIT;
3374  plc = 1;
3375  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3376  infilename[strlen(infilename) - 4] = '\0';
3377  object = MESH;
3378  refine = 1;
3379  }
3380  }
3381  plc = plc || diagnose;
3382  useshelles = plc || refine || coarse || quality;
3383  goodratio = minratio;
3384  goodratio *= goodratio;
3385 
3386  // Detect improper combinations of switches.
3387  if (plc && refine) {
3388  printf("Error: Switch -r cannot use together with -p.\n");
3389  return false;
3390  }
3391  if (refine && (plc || noiterationnum)) {
3392  printf("Error: Switches %s cannot use together with -r.\n",
3393  "-p, -d, and -I");
3394  return false;
3395  }
3396  if (diagnose && (quality || insertaddpoints || (order == 2) || neighout
3397  || docheck)) {
3398  printf("Error: Switches %s cannot use together with -d.\n",
3399  "-q, -i, -o2, -n, and -C");
3400  return false;
3401  }
3402 
3403  // Be careful not to allocate space for element area constraints that
3404  // will never be assigned any value (other than the default -1.0).
3405  if (!refine && !plc) {
3406  varvolume = 0;
3407  }
3408  // Be careful not to add an extra attribute to each element unless the
3409  // input supports it (PLC in, but not refining a preexisting mesh).
3410  if (refine || !plc) {
3411  regionattrib = 0;
3412  }
3413  // If '-a' or '-aa' is in use, enable '-q' option too.
3414  if (fixedvolume || varvolume) {
3415  if (quality == 0) {
3416  quality = 1;
3417  }
3418  }
3419  // Calculate the goodangle for testing bad subfaces.
3420  goodangle = cos(minangle * PI / 180.0);
3421  goodangle *= goodangle;
3422 
3423  increment = 0;
3424  strcpy(workstring, infilename);
3425  j = 1;
3426  while (workstring[j] != '\0') {
3427  if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3428  increment = j + 1;
3429  }
3430  j++;
3431  }
3432  meshnumber = 0;
3433  if (increment > 0) {
3434  j = increment;
3435  do {
3436  if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3437  meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3438  } else {
3439  increment = 0;
3440  }
3441  j++;
3442  } while (workstring[j] != '\0');
3443  }
3444  if (noiterationnum) {
3445  strcpy(outfilename, infilename);
3446  } else if (increment == 0) {
3447  strcpy(outfilename, infilename);
3448  strcat(outfilename, ".1");
3449  } else {
3450  workstring[increment] = '%';
3451  workstring[increment + 1] = 'd';
3452  workstring[increment + 2] = '\0';
3453  sprintf(outfilename, workstring, meshnumber + 1);
3454  }
3455  // Additional input file name has the end ".a".
3456  strcpy(addinfilename, infilename);
3457  strcat(addinfilename, ".a");
3458  // Background filename has the form "*.b.ele", "*.b.node", ...
3459  strcpy(bgmeshfilename, infilename);
3460  strcat(bgmeshfilename, ".b");
3461 
3462  return true;
3463 }
3464 
3465 //
3466 // End of class 'tetgenbehavior' implementation
3467 //
3468 
3469 //
3470 // Begin of class 'tetgenmesh' implementation
3471 //
3472 
3473 //
3474 // Begin of class 'list', 'memorypool' and 'link' implementation
3475 //
3476 
3477 // Following are predefined compare functions for primitive data types.
3478 // These functions take two pointers of the corresponding date type,
3479 // perform the comparation. Return -1, 0 or 1 indicating the default
3480 // linear order of two operators.
3481 
3482 // Compare two 'integers'.
3483 int tetgenmesh::compare_2_ints(const void* x, const void* y) {
3484  if (* (int *) x < * (int *) y) {
3485  return -1;
3486  } else if (* (int *) x > * (int *) y) {
3487  return 1;
3488  } else {
3489  return 0;
3490  }
3491 }
3492 
3493 // Compare two 'longs'. Note: in 64-bit machine the 'long' type is 64-bit
3494 // (8-byte) where the 'int' only 32-bit (4-byte).
3495 int tetgenmesh::compare_2_longs(const void* x, const void* y) {
3496  if (* (long *) x < * (long *) y) {
3497  return -1;
3498  } else if (* (long *) x > * (long *) y) {
3499  return 1;
3500  } else {
3501  return 0;
3502  }
3503 }
3504 
3505 // Compare two 'unsigned longs'.
3506 int tetgenmesh::compare_2_unsignedlongs(const void* x, const void* y) {
3507  if (* (unsigned long *) x < * (unsigned long *) y) {
3508  return -1;
3509  } else if (* (unsigned long *) x > * (unsigned long *) y) {
3510  return 1;
3511  } else {
3512  return 0;
3513  }
3514 }
3515 
3517 // //
3518 // set_compfunc() Determine the size of primitive data types and set the //
3519 // corresponding predefined linear order functions. //
3520 // //
3521 // 'str' is a zero-end string indicating a primitive data type, like 'int', //
3522 // 'long' or 'unsigned long'. Every string ending with a '*' is though as a //
3523 // type of pointer and the type 'unsign long' is used for it. //
3524 // //
3525 // When the type of 'str' is determined, the size of this type (in byte) is //
3526 // returned in 'itbytes', and the pointer of corresponding predefined linear //
3527 // order functions is returned in 'pcomp'. //
3528 // //
3530 
3531 void tetgenmesh::set_compfunc(char* str, int* itbytes, compfunc* pcomp)
3532 {
3533  // First figure out whether it is a pointer or not.
3534  if (str[strlen(str) - 1] == '*') {
3535  *itbytes = sizeof(unsigned long);
3536  *pcomp = &compare_2_unsignedlongs;
3537  return;
3538  }
3539  // Then determine other types.
3540  if (strcmp(str, "int") == 0) {
3541  *itbytes = sizeof(int);
3542  *pcomp = &compare_2_ints;
3543  } else if (strcmp(str, "long") == 0) {
3544  *itbytes = sizeof(long);
3545  *pcomp = &compare_2_longs;
3546  } else if (strcmp(str, "unsigned long") == 0) {
3547  *itbytes = sizeof(unsigned long);
3548  *pcomp = &compare_2_unsignedlongs;
3549  } else {
3550  // It is an unknown type.
3551  printf("Error in set_compfunc(): unknown type %s.\n", str);
3552  terminatetetgen(1);
3553  }
3554 }
3555 
3557 // //
3558 // listinit() Initialize a list for storing a data type. //
3559 // //
3560 // Determine the size of each item, set the maximum size allocated at onece, //
3561 // set the expand size in case the list is full, and set the linear order //
3562 // function if it is provided (default is NULL). //
3563 // //
3565 
3566 void tetgenmesh::list::
3567 listinit(int itbytes, compfunc pcomp, int mitems,int exsize)
3568 {
3569 #ifdef SELF_CHECK
3570  assert(itbytes > 0 && mitems > 0 && exsize > 0);
3571 #endif
3572  itembytes = itbytes;
3573  comp = pcomp;
3574  maxitems = mitems;
3575  expandsize = exsize;
3576  base = (char *) malloc(maxitems * itembytes);
3577  if (base == (char *) NULL) {
3578  printf("Error: Out of memory.\n");
3579  terminatetetgen(1);
3580  }
3581  items = 0;
3582 }
3583 
3585 // //
3586 // append() Add a new item at the end of the list. //
3587 // //
3588 // A new space at the end of this list will be allocated for storing the new //
3589 // item. If the memory is not sufficient, reallocation will be performed. If //
3590 // 'appitem' is not NULL, the contents of this pointer will be copied to the //
3591 // new allocated space. Returns the pointer to the new allocated space. //
3592 // //
3594 
3595 void* tetgenmesh::list::append(void *appitem)
3596 {
3597  // Do we have enough space?
3598  if (items == maxitems) {
3599  char* newbase = (char *) realloc(base, (maxitems + expandsize) *
3600  itembytes);
3601  if (newbase == (char *) NULL) {
3602  printf("Error: Out of memory.\n");
3603  terminatetetgen(1);
3604  }
3605  base = newbase;
3606  maxitems += expandsize;
3607  }
3608  if (appitem != (void *) NULL) {
3609  memcpy(base + items * itembytes, appitem, itembytes);
3610  }
3611  items++;
3612  return (void *) (base + (items - 1) * itembytes);
3613 }
3614 
3616 // //
3617 // insert() Insert an item before 'pos' (range from 0 to items - 1). //
3618 // //
3619 // A new space will be inserted at the position 'pos', that is, items lie //
3620 // after pos (including the item at pos) will be moved one space downwords. //
3621 // If 'insitem' is not NULL, its contents will be copied into the new //
3622 // inserted space. Return a pointer to the new inserted space. //
3623 // //
3625 
3626 void* tetgenmesh::list::insert(int pos, void* insitem)
3627 {
3628  if (pos >= items) {
3629  return append(insitem);
3630  }
3631  // Do we have enough space.
3632  if (items == maxitems) {
3633  char* newbase = (char *) realloc(base, (maxitems + expandsize) *
3634  itembytes);
3635  if (newbase == (char *) NULL) {
3636  printf("Error: Out of memory.\n");
3637  terminatetetgen(1);
3638  }
3639  base = newbase;
3640  maxitems += expandsize;
3641  }
3642  // Do block move.
3643  memmove(base + (pos + 1) * itembytes, // dest
3644  base + pos * itembytes, // src
3645  (items - pos) * itembytes); // size in bytes
3646  // Insert the item.
3647  if (insitem != (void *) NULL) {
3648  memcpy(base + pos * itembytes, insitem, itembytes);
3649  }
3650  items++;
3651  return (void *) (base + pos * itembytes);
3652 }
3653 
3655 // //
3656 // del() Delete an item at 'pos' (range from 0 to items - 1). //
3657 // //
3658 // The space at 'pos' will be overlapped by other item. If 'order' is 1, the //
3659 // remaining items of the list have the same order as usual, i.e., items lie //
3660 // after pos will be moved one space upwords. If 'order' is 0, the last item //
3661 // of the list will be moved up to pos. //
3662 // //
3664 
3665 void tetgenmesh::list::del(int pos, int order)
3666 {
3667  // If 'pos' is the last item of the list, nothing need to do.
3668  if (pos >= 0 && pos < items - 1) {
3669  if (order == 1) {
3670  // Do block move.
3671  memmove(base + pos * itembytes, // dest
3672  base + (pos + 1) * itembytes, // src
3673  (items - pos - 1) * itembytes);
3674  } else {
3675  // Use the last item to overlap the del item.
3676  memcpy(base + pos * itembytes, // item at pos
3677  base + (items - 1) * itembytes, // item at last
3678  itembytes);
3679  }
3680  }
3681  if (items > 0) {
3682  items--;
3683  }
3684 }
3685 
3687 // //
3688 // hasitem() Search in this list to find if 'checkitem' exists. //
3689 // //
3690 // This routine assumes that a linear order function has been set. It loops //
3691 // through the entire list, compares each item to 'checkitem'. If it exists, //
3692 // return its position (between 0 to items - 1), otherwise, return -1. //
3693 // //
3695 
3696 int tetgenmesh::list::hasitem(void* checkitem)
3697 {
3698  int i;
3699 
3700  for (i = 0; i < items; i++) {
3701  if (comp != (compfunc) NULL) {
3702  if ((* comp)((void *)(base + i * itembytes), checkitem) == 0) {
3703  return i;
3704  }
3705  }
3706  }
3707  return -1;
3708 }
3709 
3711 // //
3712 // sort() Sort the items with respect to a linear order function. //
3713 // //
3714 // Uses QuickSort routines (qsort) of the standard C/C++ library (stdlib.h). //
3715 // //
3717 
3718 void tetgenmesh::list::sort()
3719 {
3720  qsort((void *) base, (size_t) items, (size_t) itembytes, comp);
3721 }
3722 
3724 // //
3725 // memorypool() The constructors of memorypool. //
3726 // //
3728 
3729 tetgenmesh::memorypool::memorypool()
3730 {
3731  firstblock = nowblock = (void **) NULL;
3732  nextitem = (void *) NULL;
3733  deaditemstack = (void *) NULL;
3734  pathblock = (void **) NULL;
3735  pathitem = (void *) NULL;
3736  itemwordtype = POINTER;
3737  alignbytes = 0;
3738  itembytes = itemwords = 0;
3739  itemsperblock = 0;
3740  items = maxitems = 0l;
3741  unallocateditems = 0;
3742  pathitemsleft = 0;
3743 }
3744 
3745 tetgenmesh::memorypool::
3746 memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment)
3747 {
3748  poolinit(bytecount, itemcount, wtype, alignment);
3749 }
3750 
3752 // //
3753 // ~memorypool() Free to the operating system all memory taken by a pool. //
3754 // //
3756 
3757 tetgenmesh::memorypool::~memorypool()
3758 {
3759  while (firstblock != (void **) NULL) {
3760  nowblock = (void **) *(firstblock);
3761  free(firstblock);
3762  firstblock = nowblock;
3763  }
3764 }
3765 
3767 // //
3768 // poolinit() Initialize a pool of memory for allocation of items. //
3769 // //
3770 // A `pool' is created whose records have size at least `bytecount'. Items //
3771 // will be allocated in `itemcount'-item blocks. Each item is assumed to be //
3772 // a collection of words, and either pointers or floating-point values are //
3773 // assumed to be the "primary" word type. (The "primary" word type is used //
3774 // to determine alignment of items.) If `alignment' isn't zero, all items //
3775 // will be `alignment'-byte aligned in memory. `alignment' must be either a //
3776 // multiple or a factor of the primary word size; powers of two are safe. //
3777 // `alignment' is normally used to create a few unused bits at the bottom of //
3778 // each item's pointer, in which information may be stored. //
3779 // //
3781 
3782 void tetgenmesh::memorypool::
3783 poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment)
3784 {
3785  int wordsize;
3786 
3787  // Initialize values in the pool.
3788  itemwordtype = wtype;
3789  wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL);
3790  // Find the proper alignment, which must be at least as large as:
3791  // - The parameter `alignment'.
3792  // - The primary word type, to avoid unaligned accesses.
3793  // - sizeof(void *), so the stack of dead items can be maintained
3794  // without unaligned accesses.
3795  if (alignment > wordsize) {
3796  alignbytes = alignment;
3797  } else {
3798  alignbytes = wordsize;
3799  }
3800  if ((int) sizeof(void *) > alignbytes) {
3801  alignbytes = (int) sizeof(void *);
3802  }
3803  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
3804  * (alignbytes / wordsize);
3805  itembytes = itemwords * wordsize;
3806  itemsperblock = itemcount;
3807 
3808  // Allocate a block of items. Space for `itemsperblock' items and one
3809  // pointer (to point to the next block) are allocated, as well as space
3810  // to ensure alignment of the items.
3811  firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3812  + alignbytes);
3813  if (firstblock == (void **) NULL) {
3814  printf("Error: Out of memory.\n");
3815  terminatetetgen(1);
3816  }
3817  // Set the next block pointer to NULL.
3818  *(firstblock) = (void *) NULL;
3819  restart();
3820 }
3821 
3823 // //
3824 // restart() Deallocate all items in this pool. //
3825 // //
3826 // The pool is returned to its starting state, except that no memory is //
3827 // freed to the operating system. Rather, the previously allocated blocks //
3828 // are ready to be reused. //
3829 // //
3831 
3832 void tetgenmesh::memorypool::restart()
3833 {
3834  unsigned long alignptr;
3835 
3836  items = 0;
3837  maxitems = 0;
3838 
3839  // Set the currently active block.
3840  nowblock = firstblock;
3841  // Find the first item in the pool. Increment by the size of (void *).
3842  alignptr = (unsigned long) (nowblock + 1);
3843  // Align the item on an `alignbytes'-byte boundary.
3844  nextitem = (void *)
3845  (alignptr + (unsigned long) alignbytes -
3846  (alignptr % (unsigned long) alignbytes));
3847  // There are lots of unallocated items left in this block.
3848  unallocateditems = itemsperblock;
3849  // The stack of deallocated items is empty.
3850  deaditemstack = (void *) NULL;
3851 }
3852 
3854 // //
3855 // alloc() Allocate space for an item. //
3856 // //
3858 
3859 void* tetgenmesh::memorypool::alloc()
3860 {
3861  void *newitem;
3862  void **newblock;
3863  unsigned long alignptr;
3864 
3865  // First check the linked list of dead items. If the list is not
3866  // empty, allocate an item from the list rather than a fresh one.
3867  if (deaditemstack != (void *) NULL) {
3868  newitem = deaditemstack; // Take first item in list.
3869  deaditemstack = * (void **) deaditemstack;
3870  } else {
3871  // Check if there are any free items left in the current block.
3872  if (unallocateditems == 0) {
3873  // Check if another block must be allocated.
3874  if (*nowblock == (void *) NULL) {
3875  // Allocate a new block of items, pointed to by the previous block.
3876  newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3877  + alignbytes);
3878  if (newblock == (void **) NULL) {
3879  printf("Error: Out of memory.\n");
3880  terminatetetgen(1);
3881  }
3882  *nowblock = (void *) newblock;
3883  // The next block pointer is NULL.
3884  *newblock = (void *) NULL;
3885  }
3886  // Move to the new block.
3887  nowblock = (void **) *nowblock;
3888  // Find the first item in the block.
3889  // Increment by the size of (void *).
3890  alignptr = (unsigned long) (nowblock + 1);
3891  // Align the item on an `alignbytes'-byte boundary.
3892  nextitem = (void *)
3893  (alignptr + (unsigned long) alignbytes -
3894  (alignptr % (unsigned long) alignbytes));
3895  // There are lots of unallocated items left in this block.
3896  unallocateditems = itemsperblock;
3897  }
3898  // Allocate a new item.
3899  newitem = nextitem;
3900  // Advance `nextitem' pointer to next free item in block.
3901  if (itemwordtype == POINTER) {
3902  nextitem = (void *) ((void **) nextitem + itemwords);
3903  } else {
3904  nextitem = (void *) ((REAL *) nextitem + itemwords);
3905  }
3906  unallocateditems--;
3907  maxitems++;
3908  }
3909  items++;
3910  return newitem;
3911 }
3912 
3914 // //
3915 // dealloc() Deallocate space for an item. //
3916 // //
3917 // The deallocated space is stored in a queue for later reuse. //
3918 // //
3920 
3921 void tetgenmesh::memorypool::dealloc(void *dyingitem)
3922 {
3923  // Push freshly killed item onto stack.
3924  *((void **) dyingitem) = deaditemstack;
3925  deaditemstack = dyingitem;
3926  items--;
3927 }
3928 
3930 // //
3931 // traversalinit() Prepare to traverse the entire list of items. //
3932 // //
3933 // This routine is used in conjunction with traverse(). //
3934 // //
3936 
3937 void tetgenmesh::memorypool::traversalinit()
3938 {
3939  unsigned long alignptr;
3940 
3941  // Begin the traversal in the first block.
3942  pathblock = firstblock;
3943  // Find the first item in the block. Increment by the size of (void *).
3944  alignptr = (unsigned long) (pathblock + 1);
3945  // Align with item on an `alignbytes'-byte boundary.
3946  pathitem = (void *)
3947  (alignptr + (unsigned long) alignbytes -
3948  (alignptr % (unsigned long) alignbytes));
3949  // Set the number of items left in the current block.
3950  pathitemsleft = itemsperblock;
3951 }
3952 
3954 // //
3955 // traverse() Find the next item in the list. //
3956 // //
3957 // This routine is used in conjunction with traversalinit(). Be forewarned //
3958 // that this routine successively returns all items in the list, including //
3959 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
3960 // ones are actually dead. It can usually be done more space-efficiently by //
3961 // a routine that knows something about the structure of the item. //
3962 // //
3964 
3965 void* tetgenmesh::memorypool::traverse()
3966 {
3967  void *newitem;
3968  unsigned long alignptr;
3969 
3970  // Stop upon exhausting the list of items.
3971  if (pathitem == nextitem) {
3972  return (void *) NULL;
3973  }
3974  // Check whether any untraversed items remain in the current block.
3975  if (pathitemsleft == 0) {
3976  // Find the next block.
3977  pathblock = (void **) *pathblock;
3978  // Find the first item in the block. Increment by the size of (void *).
3979  alignptr = (unsigned long) (pathblock + 1);
3980  // Align with item on an `alignbytes'-byte boundary.
3981  pathitem = (void *)
3982  (alignptr + (unsigned long) alignbytes -
3983  (alignptr % (unsigned long) alignbytes));
3984  // Set the number of items left in the current block.
3985  pathitemsleft = itemsperblock;
3986  }
3987  newitem = pathitem;
3988  // Find the next item in the block.
3989  if (itemwordtype == POINTER) {
3990  pathitem = (void *) ((void **) pathitem + itemwords);
3991  } else {
3992  pathitem = (void *) ((REAL *) pathitem + itemwords);
3993  }
3994  pathitemsleft--;
3995  return newitem;
3996 }
3997 
3999 // //
4000 // linkinit() Initialize a link for storing items. //
4001 // //
4002 // The input parameters are the size of each item, a pointer of a linear //
4003 // order function and the number of items allocating in one memory bulk. //
4004 // //
4006 
4007 void tetgenmesh::link::linkinit(int bytecount, compfunc pcomp, int itemcount)
4008 {
4009 #ifdef SELF_CHECK
4010  assert(bytecount > 0 && itemcount > 0);
4011 #endif
4012  // Remember the real size of each item.
4013  linkitembytes = bytecount;
4014  // Set the linear order function for this link.
4015  comp = pcomp;
4016 
4017  // Call the constructor of 'memorypool' to initialize its variables.
4018  // like: itembytes, itemwords, items, ... Each node has size
4019  // bytecount + 2 * sizeof(void **), and total 'itemcount + 2' (because
4020  // link has additional two nodes 'head' and 'tail').
4021  poolinit(bytecount + 2 * sizeof(void **), itemcount + 2, POINTER, 0);
4022 
4023  // Initial state of this link.
4024  head = (void **) alloc();
4025  tail = (void **) alloc();
4026  *head = (void *) tail;
4027  *(head + 1) = NULL;
4028  *tail = NULL;
4029  *(tail + 1) = (void *) head;
4030  nextlinkitem = *head;
4031  curpos = 1;
4032  linkitems = 0;
4033 }
4034 
4036 // //
4037 // clear() Deallocate all nodes in this link. //
4038 // //
4039 // The link is returned to its starting state, except that no memory is //
4040 // freed to the operating system. Rather, the previously allocated blocks //
4041 // are ready to be reused. //
4042 // //
4044 
4045 void tetgenmesh::link::clear()
4046 {
4047  // Reset the pool.
4048  restart();
4049 
4050  // Initial state of this link.
4051  head = (void **) alloc();
4052  tail = (void **) alloc();
4053  *head = (void *) tail;
4054  *(head + 1) = NULL;
4055  *tail = NULL;
4056  *(tail + 1) = (void *) head;
4057  nextlinkitem = *head;
4058  curpos = 1;
4059  linkitems = 0;
4060 }
4061 
4063 // //
4064 // move() Causes 'nextlinkitem' to traverse the specified number of nodes,//
4065 // updates 'curpos' to be the node to which 'nextlinkitem' points. //
4066 // //
4067 // 'numberofnodes' is a number indicating how many nodes need be traversed //
4068 // (not counter the current node) need be traversed. It may be positive(move //
4069 // forward) or negative (move backward). Return TRUE if it is successful. //
4070 // //
4072 
4073 bool tetgenmesh::link::move(int numberofnodes)
4074 {
4075  void **nownode;
4076  int i;
4077 
4078  nownode = (void **) nextlinkitem;
4079  if (numberofnodes > 0) {
4080  // Move forward.
4081  i = 0;
4082  while ((i < numberofnodes) && *nownode) {
4083  nownode = (void **) *nownode;
4084  i++;
4085  }
4086  if (*nownode == NULL) return false;
4087  nextlinkitem = (void *) nownode;
4088  curpos += numberofnodes;
4089  } else if (numberofnodes < 0) {
4090  // Move backward.
4091  i = 0;
4092  numberofnodes = -numberofnodes;
4093  while ((i < numberofnodes) && *(nownode + 1)) {
4094  nownode = (void **) *(nownode + 1);
4095  i++;
4096  }
4097  if (*(nownode + 1) == NULL) return false;
4098  nextlinkitem = (void *) nownode;
4099  curpos -= numberofnodes;
4100  }
4101  return true;
4102 }
4103 
4105 // //
4106 // locate() Locates the node at the specified position. //
4107 // //
4108 // The number 'pos' (between 1 and 'linkitems') indicates the location. This //
4109 // routine first decides the shortest path traversing from 'curpos' to 'pos',//
4110 // i.e., from head, tail or 'curpos'. Routine 'move()' is called to really //
4111 // traverse the link. If success, 'nextlinkitem' points to the node, 'curpos'//
4112 // and 'pos' are equal. Otherwise, return FALSE. //
4113 // //
4115 
4116 bool tetgenmesh::link::locate(int pos)
4117 {
4118  int headdist, taildist, curdist;
4119  int abscurdist, mindist;
4120 
4121  if (pos < 1 || pos > linkitems) return false;
4122 
4123  headdist = pos - 1;
4124  taildist = linkitems - pos;
4125  curdist = pos - curpos;
4126  abscurdist = curdist >= 0 ? curdist : -curdist;
4127 
4128  if (headdist > taildist) {
4129  if (taildist > abscurdist) {
4130  mindist = curdist;
4131  } else {
4132  // taildist <= abs(curdist)
4133  mindist = -taildist;
4134  goend();
4135  }
4136  } else {
4137  // headdist <= taildist
4138  if (headdist > abscurdist) {
4139  mindist = curdist;
4140  } else {
4141  // headdist <= abs(curdist)
4142  mindist = headdist;
4143  rewind();
4144  }
4145  }
4146 
4147  return move(mindist);
4148 }
4149 
4151 // //
4152 // add() Add a node at the end of this link. //
4153 // //
4154 // A new node is appended to the end of the link. If 'newitem' is not NULL, //
4155 // its conents will be copied to the data slot of the new node. Returns the //
4156 // pointer to the newest added node. //
4157 // //
4159 
4160 void* tetgenmesh::link::add(void* newitem)
4161 {
4162  void **newnode = tail;
4163  if (newitem != (void *) NULL) {
4164  memcpy((void *)(newnode + 2), newitem, linkitembytes);
4165  }
4166  tail = (void **) alloc();
4167  *tail = NULL;
4168  *newnode = (void*) tail;
4169  *(tail + 1) = (void*) newnode;
4170  linkitems++;
4171  return (void *)(newnode + 2);
4172 }
4173 
4175 // //
4176 // insert() Inserts a node before the specified position. //
4177 // //
4178 // 'pos' (between 1 and 'linkitems') indicates the inserting position. This //
4179 // routine inserts a new node before the node of 'pos'. If 'newitem' is not //
4180 // NULL, its conents will be copied into the data slot of the new node. If //
4181 // 'pos' is larger than 'linkitems', it is equal as 'add()'. A pointer to //
4182 // the newest inserted item is returned. //
4183 // //
4185 
4186 void* tetgenmesh::link::insert(int pos, void* insitem)
4187 {
4188  if (!locate(pos)) {
4189  return add(insitem);
4190  }
4191 
4192  void **nownode = (void **) nextlinkitem;
4193 
4194  // Insert a node before 'nownode'.
4195  void **newnode = (void **) alloc();
4196  if (insitem != (void *) NULL) {
4197  memcpy((void *)(newnode + 2), insitem, linkitembytes);
4198  }
4199 
4200  *(void **)(*(nownode + 1)) = (void *) newnode;
4201  *newnode = (void *) nownode;
4202  *(newnode + 1) = *(nownode + 1);
4203  *(nownode + 1) = (void *) newnode;
4204 
4205  linkitems++;
4206 
4207  nextlinkitem = (void *) newnode;
4208  return (void *)(newnode + 2);
4209 }
4210 
4212 // //
4213 // del() Delete a node. //
4214 // //
4215 // Returns a pointer of the deleted data. If you try to delete a non-existed //
4216 // node (e.g. link is empty or a wrong index is given) return NULL. //
4217 // //
4219 
4220 void* tetgenmesh::link::deletenode(void** deadnode)
4221 {
4222  void **nextnode = (void **) *deadnode;
4223  void **prevnode = (void **) *(deadnode + 1);
4224  *prevnode = (void *) nextnode;
4225  *(nextnode + 1) = (void *) prevnode;
4226 
4227  dealloc((void *) deadnode);
4228  linkitems--;
4229 
4230  nextlinkitem = (void *) nextnode;
4231  return (void *)(deadnode + 2);
4232 }
4233 
4235 // //
4236 // del() Delete a node at the specified position. //
4237 // //
4238 // 'pos' between 1 and 'linkitems'. Returns a pointer of the deleted data. //
4239 // If you try to delete a non-existed node (e.g. link is empty or a wrong //
4240 // index is given) return NULL. //
4241 // //
4243 
4244 void* tetgenmesh::link::del(int pos)
4245 {
4246  if (!locate(pos) || (linkitems == 0)) {
4247  return (void *) NULL;
4248  }
4249  return deletenode((void **) nextlinkitem);
4250 }
4251 
4253 // //
4254 // getitem() The link traversal routine. //
4255 // //
4256 // Returns the node to which 'nextlinkitem' points. Returns a 'NULL' if the //
4257 // end of the link is reaching. Both 'nextlinkitem' and 'curpos' will be //
4258 // updated after this operation. //
4259 // //
4261 
4262 void* tetgenmesh::link::getitem()
4263 {
4264  if (nextlinkitem == (void *) tail) return NULL;
4265  void **nownode = (void **) nextlinkitem;
4266  nextlinkitem = *nownode;
4267  curpos += 1;
4268  return (void *)(nownode + 2);
4269 }
4270 
4272 // //
4273 // getnitem() Returns the node at a specified position. //
4274 // //
4275 // 'pos' between 1 and 'linkitems'. After this operation, 'nextlinkitem' and //
4276 // 'curpos' will be updated to indicate this node. //
4277 // //
4279 
4280 void* tetgenmesh::link::getnitem(int pos)
4281 {
4282  if (!locate(pos)) return NULL;
4283  return (void *)((void **) nextlinkitem + 2);
4284 }
4285 
4287 // //
4288 // hasitem() Search in this link to find if 'checkitem' exists. //
4289 // //
4290 // If 'checkitem' exists, return its position (between 1 to 'linkitems'), //
4291 // otherwise, return -1. This routine requires the linear order function has //
4292 // been set. //
4293 // //
4295 
4296 int tetgenmesh::link::hasitem(void* checkitem)
4297 {
4298  void *pathitem;
4299  int count;
4300 
4301  rewind();
4302  pathitem = getitem();
4303  count = 0;
4304  while (pathitem) {
4305  count ++;
4306  if (comp) {
4307  if ((* comp)(pathitem, checkitem) == 0) {
4308  return count;
4309  }
4310  }
4311  pathitem = getitem();
4312  }
4313  return -1;
4314 }
4315 
4316 //
4317 // End of class 'list', 'memorypool' and 'link' implementation
4318 //
4319 
4320 //
4321 // Begin of mesh manipulation primitives
4322 //
4323 
4324 //
4325 // Begin of tables initialization.
4326 //
4327 
4328 // For enumerating three edges of a triangle.
4329 
4330 int tetgenmesh::plus1mod3[3] = {1, 2, 0};
4331 int tetgenmesh::minus1mod3[3] = {2, 0, 1};
4332 
4333 // Table 've' takes an edge version as input, returns the next edge version
4334 // in the same edge ring.
4335 
4336 int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 };
4337 
4338 // Tables 'vo', 'vd' and 'va' take an edge version, return the positions of
4339 // the origin, destination and apex in the triangle.
4340 
4341 int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 };
4342 int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 };
4343 int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 };
4344 
4345 // The following tables are for tetrahedron primitives (operate on trifaces).
4346 
4347 // For 'org()', 'dest()' and 'apex()'. Use 'loc' as the first index and
4348 // 'ver' as the second index.
4349 
4350 int tetgenmesh::locver2org[4][6] = {
4351  {0, 1, 1, 2, 2, 0},
4352  {0, 3, 3, 1, 1, 0},
4353  {1, 3, 3, 2, 2, 1},
4354  {2, 3, 3, 0, 0, 2}
4355 };
4356 int tetgenmesh::locver2dest[4][6] = {
4357  {1, 0, 2, 1, 0, 2},
4358  {3, 0, 1, 3, 0, 1},
4359  {3, 1, 2, 3, 1, 2},
4360  {3, 2, 0, 3, 2, 0}
4361 };
4362 int tetgenmesh::locver2apex[4][6] = {
4363  {2, 2, 0, 0, 1, 1},
4364  {1, 1, 0, 0, 3, 3},
4365  {2, 2, 1, 1, 3, 3},
4366  {0, 0, 2, 2, 3, 3}
4367 };
4368 
4369 // For oppo() primitives, use 'loc' as the index.
4370 
4371 int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 };
4372 
4373 // For fnext() primitive. Use 'loc' as the first index and 'ver' as the
4374 // second index. Returns a new 'loc' and new 'ver' in an array. (It is
4375 // only valid for edge version equals one of {0, 2, 4}.)
4376 
4377 int tetgenmesh::locver2nextf[4][6][2] = {
4378  { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} },
4379  { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} },
4380  { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} },
4381  { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} }
4382 };
4383 
4384 // The edge number (from 0 to 5) of a tet is defined as follows:
4385 // 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0)
4386 // 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2).
4387 
4388 int tetgenmesh::locver2edge[4][6] = {
4389  {0, 0, 1, 1, 2, 2},
4390  {3, 3, 4, 4, 0, 0},
4391  {4, 4, 5, 5, 1, 1},
4392  {5, 5, 3, 3, 2, 2}
4393 };
4394 
4395 int tetgenmesh::edge2locver[6][2] = {
4396  {0, 0}, // 0 v0 -> v1
4397  {0, 2}, // 1 v1 -> v2
4398  {0, 4}, // 2 v2 -> v1
4399  {1, 0}, // 3 v0 -> v3
4400  {1, 2}, // 4 v1 -> v3
4401  {2, 2} // 5 v2 -> v3
4402 };
4403 
4404 //
4405 // End of tables initialization.
4406 //
4407 
4408 // Some macros for convenience
4409 
4410 #define Div2 >> 1
4411 #define Mod2 & 01
4412 
4413 // NOTE: These bit operators should only be used in macros below.
4414 
4415 // Get orient(Range from 0 to 2) from face version(Range from 0 to 5).
4416 
4417 #define Orient(V) ((V) Div2)
4418 
4419 // Determine edge ring(0 or 1) from face version(Range from 0 to 5).
4420 
4421 #define EdgeRing(V) ((V) Mod2)
4422 
4423 //
4424 // Begin of primitives for tetrahedra
4425 //
4426 
4427 // Each tetrahedron contains four pointers to its neighboring tetrahedra,
4428 // with face indices. To save memory, both information are kept in a
4429 // single pointer. To make this possible, all tetrahedra are aligned to
4430 // eight-byte boundaries, so that the last three bits of each pointer are
4431 // zeros. A face index (in the range 0 to 3) is compressed into the last
4432 // two bits of each pointer by the function 'encode()'. The function
4433 // 'decode()' decodes a pointer, extracting a face index and a pointer to
4434 // the beginning of a tetrahedron.
4435 
4436 inline void tetgenmesh::decode(tetrahedron ptr, triface& t) {
4437  t.loc = (int) ((unsigned long) (ptr) & (unsigned long) 3l);
4438  t.tet = (tetrahedron *) ((unsigned long) (ptr) & ~(unsigned long) 7l);
4439 }
4440 
4441 inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) {
4442  return (tetrahedron) ((unsigned long) t.tet | (unsigned long) t.loc);
4443 }
4444 
4445 // sym() finds the abutting tetrahedron on the same face.
4446 
4447 inline void tetgenmesh::sym(triface& t1, triface& t2) {
4448  tetrahedron ptr = t1.tet[t1.loc];
4449  decode(ptr, t2);
4450 }
4451 
4452 inline void tetgenmesh::symself(triface& t) {
4453  tetrahedron ptr = t.tet[t.loc];
4454  decode(ptr, t);
4455 }
4456 
4457 // Bond two tetrahedra together at their faces.
4458 
4459 inline void tetgenmesh::bond(triface& t1, triface& t2) {
4460  t1.tet[t1.loc] = encode(t2);
4461  t2.tet[t2.loc] = encode(t1);
4462 }
4463 
4464 // Dissolve a bond (from one side). Note that the other tetrahedron will
4465 // still think it is connected to this tetrahedron. Usually, however,
4466 // the other tetrahedron is being deleted entirely, or bonded to another
4467 // tetrahedron, so it doesn't matter.
4468 
4469 inline void tetgenmesh::dissolve(triface& t) {
4470  t.tet[t.loc] = (tetrahedron) dummytet;
4471 }
4472 
4473 // These primitives determine or set the origin, destination, apex or
4474 // opposition of a tetrahedron with respect to 'loc' and 'ver'.
4475 
4476 inline tetgenmesh::point tetgenmesh::org(triface& t) {
4477  return (point) t.tet[locver2org[t.loc][t.ver] + 4];
4478 }
4479 
4480 inline tetgenmesh::point tetgenmesh::dest(triface& t) {
4481  return (point) t.tet[locver2dest[t.loc][t.ver] + 4];
4482 }
4483 
4484 inline tetgenmesh::point tetgenmesh::apex(triface& t) {
4485  return (point) t.tet[locver2apex[t.loc][t.ver] + 4];
4486 }
4487 
4488 inline tetgenmesh::point tetgenmesh::oppo(triface& t) {
4489  return (point) t.tet[loc2oppo[t.loc] + 4];
4490 }
4491 
4492 inline void tetgenmesh::setorg(triface& t, point pointptr) {
4493  t.tet[locver2org[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4494 }
4495 
4496 inline void tetgenmesh::setdest(triface& t, point pointptr) {
4497  t.tet[locver2dest[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4498 }
4499 
4500 inline void tetgenmesh::setapex(triface& t, point pointptr) {
4501  t.tet[locver2apex[t.loc][t.ver] + 4] = (tetrahedron) pointptr;
4502 }
4503 
4504 inline void tetgenmesh::setoppo(triface& t, point pointptr) {
4505  t.tet[loc2oppo[t.loc] + 4] = (tetrahedron) pointptr;
4506 }
4507 
4508 // These primitives were drived from Mucke's triangle-edge data structure
4509 // to change face-edge relation in a tetrahedron (esym, enext and enext2)
4510 // or between two tetrahedra (fnext).
4511 
4512 // If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two directions
4513 // of the same undirected edge of a face. e0.sym() = e1 and vice versa.
4514 
4515 inline void tetgenmesh::esym(triface& t1, triface& t2) {
4516  t2.tet = t1.tet;
4517  t2.loc = t1.loc;
4518  t2.ver = t1.ver + (EdgeRing(t1.ver) ? -1 : 1);
4519 }
4520 
4521 inline void tetgenmesh::esymself(triface& t) {
4522  t.ver += (EdgeRing(t.ver) ? -1 : 1);
4523 }
4524 
4525 // If e0 and e1 are both in the same edge ring of a face, e1 = e0.enext().
4526 
4527 inline void tetgenmesh::enext(triface& t1, triface& t2) {
4528  t2.tet = t1.tet;
4529  t2.loc = t1.loc;
4530  t2.ver = ve[t1.ver];
4531 }
4532 
4533 inline void tetgenmesh::enextself(triface& t) {
4534  t.ver = ve[t.ver];
4535 }
4536 
4537 // enext2() is equal to e2 = e0.enext().enext()
4538 
4539 inline void tetgenmesh::enext2(triface& t1, triface& t2) {
4540  t2.tet = t1.tet;
4541  t2.loc = t1.loc;
4542  t2.ver = ve[ve[t1.ver]];
4543 }
4544 
4545 inline void tetgenmesh::enext2self(triface& t) {
4546  t.ver = ve[ve[t.ver]];
4547 }
4548 
4549 // If f0 and f1 are both in the same face ring of a face, f1 = f0.fnext().
4550 // If f1 exists, return true. Otherwise, return false, i.e., f0 is a
4551 // boundary or hull face.
4552 
4553 inline bool tetgenmesh::fnext(triface& t1, triface& t2)
4554 {
4555  // Get the next face.
4556  t2.loc = locver2nextf[t1.loc][t1.ver][0];
4557  // Is the next face in the same tet?
4558  if (t2.loc != -1) {
4559  // It's in the same tet. Get the edge version.
4560  t2.ver = locver2nextf[t1.loc][t1.ver][1];
4561  t2.tet = t1.tet;
4562  } else {
4563  // The next face is in the neigbhour of 't1'.
4564  sym(t1, t2);
4565  if (t2.tet != dummytet) {
4566  // Find the corresponding edge in t2.
4567  point torg;
4568  int tloc, tver, i;
4569  t2.ver = 0;
4570  torg = org(t1);
4571  for (i = 0; (i < 3) && (org(t2) != torg); i++) {
4572  enextself(t2);
4573  }
4574  // Go to the next face in t2.
4575  tloc = t2.loc;
4576  tver = t2.ver;
4577  t2.loc = locver2nextf[tloc][tver][0];
4578  t2.ver = locver2nextf[tloc][tver][1];
4579  }
4580  }
4581  return t2.tet != dummytet;
4582 }
4583 
4584 inline bool tetgenmesh::fnextself(triface& t1)
4585 {
4586  triface t2;
4587 
4588  // Get the next face.
4589  t2.loc = locver2nextf[t1.loc][t1.ver][0];
4590  // Is the next face in the same tet?
4591  if (t2.loc != -1) {
4592  // It's in the same tet. Get the edge version.
4593  t2.ver = locver2nextf[t1.loc][t1.ver][1];
4594  t1.loc = t2.loc;
4595  t1.ver = t2.ver;
4596  } else {
4597  // The next face is in the neigbhour of 't1'.
4598  sym(t1, t2);
4599  if (t2.tet != dummytet) {
4600  // Find the corresponding edge in t2.
4601  point torg;
4602  int i;
4603  t2.ver = 0;
4604  torg = org(t1);
4605  for (i = 0; (i < 3) && (org(t2) != torg); i++) {
4606  enextself(t2);
4607  }
4608  t1.loc = locver2nextf[t2.loc][t2.ver][0];
4609  t1.ver = locver2nextf[t2.loc][t2.ver][1];
4610  t1.tet = t2.tet;
4611  }
4612  }
4613  return t2.tet != dummytet;
4614 }
4615 
4616 // enextfnext() and enext2fnext() are combination primitives of enext(),
4617 // enext2() and fnext().
4618 
4619 inline void tetgenmesh::enextfnext(triface& t1, triface& t2) {
4620  enext(t1, t2);
4621  fnextself(t2);
4622 }
4623 
4624 inline void tetgenmesh::enextfnextself(triface& t) {
4625  enextself(t);
4626  fnextself(t);
4627 }
4628 
4629 inline void tetgenmesh::enext2fnext(triface& t1, triface& t2) {
4630  enext2(t1, t2);
4631  fnextself(t2);
4632 }
4633 
4634 inline void tetgenmesh::enext2fnextself(triface& t) {
4635  enext2self(t);
4636  fnextself(t);
4637 }
4638 
4639 // Primitives to infect or cure a tetrahedron with the virus. The last
4640 // third bit of the pointer is marked for infection. These rely on the
4641 // assumption that all tetrahedron are aligned to eight-byte boundaries.
4642 
4643 inline void tetgenmesh::infect(triface& t) {
4644  t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] | (unsigned long) 4l);
4645 }
4646 
4647 inline void tetgenmesh::uninfect(triface& t) {
4648  t.tet[0] = (tetrahedron) ((unsigned long) t.tet[0] & ~ (unsigned long) 4l);
4649 }
4650 
4651 // Test a tetrahedron for viral infection.
4652 
4653 inline bool tetgenmesh::infected(triface& t) {
4654  return (((unsigned long) t.tet[0] & (unsigned long) 4l) != 0);
4655 }
4656 
4657 // Check or set a tetrahedron's attributes.
4658 
4659 inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) {
4660  return ((REAL *) (ptr))[elemattribindex + attnum];
4661 }
4662 
4663 inline void tetgenmesh::
4664 setelemattribute(tetrahedron* ptr, int attnum, REAL value){
4665  ((REAL *) (ptr))[elemattribindex + attnum] = value;
4666 }
4667 
4668 // Check or set a tetrahedron's maximum volume bound.
4669 
4670 inline REAL tetgenmesh::volumebound(tetrahedron* ptr) {
4671  return ((REAL *) (ptr))[volumeboundindex];
4672 }
4673 
4674 inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) {
4675  ((REAL *) (ptr))[volumeboundindex] = value;
4676 }
4677 
4678 //
4679 // End of primitives for tetrahedra
4680 //
4681 
4682 //
4683 // Begin of primitives for subfaces/subsegments
4684 //
4685 
4686 // Each subface contains three pointers to its neighboring subfaces, with
4687 // edge versions. To save memory, both information are kept in a single
4688 // pointer. To make this possible, all subfaces are aligned to eight-byte
4689 // boundaries, so that the last three bits of each pointer are zeros. An
4690 // edge version (in the range 0 to 5) is compressed into the last three
4691 // bits of each pointer by 'sencode()'. 'sdecode()' decodes a pointer,
4692 // extracting an edge version and a pointer to the beginning of a subface.
4693 
4694 inline void tetgenmesh::sdecode(shellface sptr, face& s) {
4695  s.shver = (int) ((unsigned long) (sptr) & (unsigned long) 7l);
4696  s.sh = (shellface *) ((unsigned long) (sptr) & ~ (unsigned long) 7l);
4697 }
4698 
4699 inline tetgenmesh::shellface tetgenmesh::sencode(face& s) {
4700  return (shellface) ((unsigned long) s.sh | (unsigned long) s.shver);
4701 }
4702 
4703 // spivot() finds the other subface (from this subface) that shares the
4704 // same edge.
4705 
4706 inline void tetgenmesh::spivot(face& s1, face& s2) {
4707  shellface sptr = s1.sh[Orient(s1.shver)];
4708  sdecode(sptr, s2);
4709 }
4710 
4711 inline void tetgenmesh::spivotself(face& s) {
4712  shellface sptr = s.sh[Orient(s.shver)];
4713  sdecode(sptr, s);
4714 }
4715 
4716 // sbond() bonds two subfaces together, i.e., after bonding, both faces
4717 // are pointing to each other.
4718 
4719 inline void tetgenmesh::sbond(face& s1, face& s2) {
4720  s1.sh[Orient(s1.shver)] = sencode(s2);
4721  s2.sh[Orient(s2.shver)] = sencode(s1);
4722 }
4723 
4724 // sbond1() only bonds s2 to s1, i.e., after bonding, s1 is pointing to s2,
4725 // but s2 is not pointing to s1.
4726 
4727 inline void tetgenmesh::sbond1(face& s1, face& s2) {
4728  s1.sh[Orient(s1.shver)] = sencode(s2);
4729 }
4730 
4731 // Dissolve a subface bond (from one side). Note that the other subface
4732 // will still think it's connected to this subface.
4733 
4734 inline void tetgenmesh::sdissolve(face& s) {
4735  s.sh[Orient(s.shver)] = (shellface) dummysh;
4736 }
4737 
4738 // These primitives determine or set the origin, destination, or apex
4739 // of a subface with respect to the edge version.
4740 
4741 inline tetgenmesh::point tetgenmesh::sorg(face& s) {
4742  return (point) s.sh[3 + vo[s.shver]];
4743 }
4744 
4745 inline tetgenmesh::point tetgenmesh::sdest(face& s) {
4746  return (point) s.sh[3 + vd[s.shver]];
4747 }
4748 
4749 inline tetgenmesh::point tetgenmesh::sapex(face& s) {
4750  return (point) s.sh[3 + va[s.shver]];
4751 }
4752 
4753 inline void tetgenmesh::setsorg(face& s, point pointptr) {
4754  s.sh[3 + vo[s.shver]] = (shellface) pointptr;
4755 }
4756 
4757 inline void tetgenmesh::setsdest(face& s, point pointptr) {
4758  s.sh[3 + vd[s.shver]] = (shellface) pointptr;
4759 }
4760 
4761 inline void tetgenmesh::setsapex(face& s, point pointptr) {
4762  s.sh[3 + va[s.shver]] = (shellface) pointptr;
4763 }
4764 
4765 // These primitives were drived from Mucke[2]'s triangle-edge data structure
4766 // to change face-edge relation in a subface (sesym, senext and senext2).
4767 
4768 inline void tetgenmesh::sesym(face& s1, face& s2) {
4769  s2.sh = s1.sh;
4770  s2.shver = s1.shver + (EdgeRing(s1.shver) ? -1 : 1);
4771 }
4772 
4773 inline void tetgenmesh::sesymself(face& s) {
4774  s.shver += (EdgeRing(s.shver) ? -1 : 1);
4775 }
4776 
4777 inline void tetgenmesh::senext(face& s1, face& s2) {
4778  s2.sh = s1.sh;
4779  s2.shver = ve[s1.shver];
4780 }
4781 
4782 inline void tetgenmesh::senextself(face& s) {
4783  s.shver = ve[s.shver];
4784 }
4785 
4786 inline void tetgenmesh::senext2(face& s1, face& s2) {
4787  s2.sh = s1.sh;
4788  s2.shver = ve[ve[s1.shver]];
4789 }
4790 
4791 inline void tetgenmesh::senext2self(face& s) {
4792  s.shver = ve[ve[s.shver]];
4793 }
4794 
4795 // If f0 and f1 are both in the same face ring, then f1 = f0.fnext(),
4796 
4797 inline void tetgenmesh::sfnext(face& s1, face& s2) {
4798  getnextsface(&s1, &s2);
4799 }
4800 
4801 inline void tetgenmesh::sfnextself(face& s) {
4802  getnextsface(&s, NULL);
4803 }
4804 
4805 // These primitives read or set a pointer of the badface structure. The
4806 // pointer is stored sh[11].
4807 
4808 inline tetgenmesh::badface* tetgenmesh::shell2badface(face& s) {
4809  return (badface*) s.sh[11];
4810 }
4811 
4812 inline void tetgenmesh::setshell2badface(face& s, badface* value) {
4813  s.sh[11] = (shellface) value;
4814 }
4815 
4816 // Check or set a subface's maximum area bound.
4817 
4818 inline REAL tetgenmesh::areabound(face& s) {
4819  return ((REAL *) (s.sh))[areaboundindex];
4820 }
4821 
4822 inline void tetgenmesh::setareabound(face& s, REAL value) {
4823  ((REAL *) (s.sh))[areaboundindex] = value;
4824 }
4825 
4826 // These two primitives read or set a shell marker. Shell markers are used
4827 // to hold user boundary information.
4828 
4829 inline int tetgenmesh::shellmark(face& s) {
4830  return ((int *) (s.sh))[shmarkindex];
4831 }
4832 
4833 inline void tetgenmesh::setshellmark(face& s, int value) {
4834  ((int *) (s.sh))[shmarkindex] = value;
4835 }
4836 
4837 // These two primitives set or read the type of the subface or subsegment.
4838 
4839 inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) {
4840  return (enum shestype) ((int *) (s.sh))[shmarkindex + 1];
4841 }
4842 
4843 inline void tetgenmesh::setshelltype(face& s, enum shestype value) {
4844  ((int *) (s.sh))[shmarkindex + 1] = (int) value;
4845 }
4846 
4847 // These two primitives set or read the pbc group of the subface.
4848 
4849 inline int tetgenmesh::shellpbcgroup(face& s) {
4850  return ((int *) (s.sh))[shmarkindex + 2];
4851 }
4852 
4853 inline void tetgenmesh::setshellpbcgroup(face& s, int value) {
4854  ((int *) (s.sh))[shmarkindex + 2] = value;
4855 }
4856 
4857 // Primitives to infect or cure a subface with the virus. These rely on the
4858 // assumption that all tetrahedra are aligned to eight-byte boundaries.
4859 
4860 inline void tetgenmesh::sinfect(face& s) {
4861  s.sh[6] = (shellface) ((unsigned long) s.sh[6] | (unsigned long) 4l);
4862 }
4863 
4864 inline void tetgenmesh::suninfect(face& s) {
4865  s.sh[6] = (shellface)((unsigned long) s.sh[6] & ~(unsigned long) 4l);
4866 }
4867 
4868 // Test a subface for viral infection.
4869 
4870 inline bool tetgenmesh::sinfected(face& s) {
4871  return (((unsigned long) s.sh[6] & (unsigned long) 4l) != 0);
4872 }
4873 
4874 //
4875 // End of primitives for subfaces/subsegments
4876 //
4877 
4878 //
4879 // Begin of primitives for interacting between tetrahedra and subfaces
4880 //
4881 
4882 // tspivot() finds a subface abutting on this tetrahdera.
4883 
4884 inline void tetgenmesh::tspivot(triface& t, face& s) {
4885  shellface sptr = (shellface) t.tet[8 + t.loc];
4886  sdecode(sptr, s);
4887 }
4888 
4889 // stpivot() finds a tetrahedron abutting a subface.
4890 
4891 inline void tetgenmesh::stpivot(face& s, triface& t) {
4892  tetrahedron ptr = (tetrahedron) s.sh[6 + EdgeRing(s.shver)];
4893  decode(ptr, t);
4894 }
4895 
4896 // tsbond() bond a tetrahedron to a subface.
4897 
4898 inline void tetgenmesh::tsbond(triface& t, face& s) {
4899  t.tet[8 + t.loc] = (tetrahedron) sencode(s);
4900  s.sh[6 + EdgeRing(s.shver)] = (shellface) encode(t);
4901 }
4902 
4903 // tsdissolve() dissolve a bond (from the tetrahedron side).
4904 
4905 inline void tetgenmesh::tsdissolve(triface& t) {
4906  t.tet[8 + t.loc] = (tetrahedron) dummysh;
4907 }
4908 
4909 // stdissolve() dissolve a bond (from the subface side).
4910 
4911 inline void tetgenmesh::stdissolve(face& s) {
4912  s.sh[6 + EdgeRing(s.shver)] = (shellface) dummytet;
4913 }
4914 
4915 //
4916 // End of primitives for interacting between tetrahedra and subfaces
4917 //
4918 
4919 //
4920 // Begin of primitives for interacting between subfaces and subsegs
4921 //
4922 
4923 // sspivot() finds a subsegment abutting a subface.
4924 
4925 inline void tetgenmesh::sspivot(face& s, face& edge) {
4926  shellface sptr = (shellface) s.sh[8 + Orient(s.shver)];
4927  sdecode(sptr, edge);
4928 }
4929 
4930 // ssbond() bond a subface to a subsegment.
4931 
4932 inline void tetgenmesh::ssbond(face& s, face& edge) {
4933  s.sh[8 + Orient(s.shver)] = sencode(edge);
4934  edge.sh[0] = sencode(s);
4935 }
4936 
4937 // ssdisolve() dissolve a bond (from the subface side)
4938 
4939 inline void tetgenmesh::ssdissolve(face& s) {
4940  s.sh[8 + Orient(s.shver)] = (shellface) dummysh;
4941 }
4942 
4943 //
4944 // End of primitives for interacting between subfaces and subsegs
4945 //
4946 
4947 //
4948 // Begin of primitives for interacting between tet and subsegs.
4949 //
4950 
4951 inline void tetgenmesh::tsspivot1(triface& t, face& seg)
4952 {
4953  shellface sptr = (shellface) t.tet[8 + locver2edge[t.loc][t.ver]];
4954  sdecode(sptr, seg);
4955 }
4956 
4957 // Only bond/dissolve at tet's side, but not vice versa.
4958 
4959 inline void tetgenmesh::tssbond1(triface& t, face& seg)
4960 {
4961  t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) sencode(seg);
4962 }
4963 
4964 inline void tetgenmesh::tssdissolve1(triface& t)
4965 {
4966  t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) dummysh;
4967 }
4968 
4969 //
4970 // End of primitives for interacting between tet and subsegs.
4971 //
4972 
4973 //
4974 // Begin of primitives for points
4975 //
4976 
4977 inline int tetgenmesh::pointmark(point pt) {
4978  return ((int *) (pt))[pointmarkindex];
4979 }
4980 
4981 inline void tetgenmesh::setpointmark(point pt, int value) {
4982  ((int *) (pt))[pointmarkindex] = value;
4983 }
4984 
4985 // These two primitives set and read the type of the point.
4986 
4987 inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) {
4988  return (enum verttype) ((int *) (pt))[pointmarkindex + 1];
4989 }
4990 
4991 inline void tetgenmesh::setpointtype(point pt, enum verttype value) {
4992  ((int *) (pt))[pointmarkindex + 1] = (int) value;
4993 }
4994 
4995 // These following primitives set and read a pointer to a tetrahedron
4996 // a subface/subsegment, a point, or a tet of background mesh.
4997 
4998 inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) {
4999  return ((tetrahedron *) (pt))[point2simindex];
5000 }
5001 
5002 inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) {
5003  ((tetrahedron *) (pt))[point2simindex] = value;
5004 }
5005 
5006 inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) {
5007  return (shellface) ((tetrahedron *) (pt))[point2simindex + 1];
5008 }
5009 
5010 inline void tetgenmesh::setpoint2sh(point pt, shellface value) {
5011  ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value;
5012 }
5013 
5014 inline tetgenmesh::point tetgenmesh::point2ppt(point pt) {
5015  return (point) ((tetrahedron *) (pt))[point2simindex + 2];
5016 }
5017 
5018 inline void tetgenmesh::setpoint2ppt(point pt, point value) {
5019  ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value;
5020 }
5021 
5022 inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) {
5023  return ((tetrahedron *) (pt))[point2simindex + 3];
5024 }
5025 
5026 inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) {
5027  ((tetrahedron *) (pt))[point2simindex + 3] = value;
5028 }
5029 
5030 // These primitives set and read a pointer to its pbc point.
5031 
5032 inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) {
5033  return (point) ((tetrahedron *) (pt))[point2pbcptindex];
5034 }
5035 
5036 inline void tetgenmesh::setpoint2pbcpt(point pt, point value) {
5037  ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value;
5038 }
5039 
5040 //
5041 // End of primitives for points
5042 //
5043 
5044 //
5045 // Begin of advanced primitives
5046 //
5047 
5048 // adjustedgering() adjusts the edge version so that it belongs to the
5049 // indicated edge ring. The 'direction' only can be 0(CCW) or 1(CW).
5050 // If the edge is not in the wanted edge ring, reverse it.
5051 
5052 inline void tetgenmesh::adjustedgering(triface& t, int direction) {
5053  if (EdgeRing(t.ver) != direction) {
5054  esymself(t);
5055  }
5056 }
5057 
5058 inline void tetgenmesh::adjustedgering(face& s, int direction) {
5059  if (EdgeRing(s.shver) != direction) {
5060  sesymself(s);
5061  }
5062 }
5063 
5064 // isdead() returns TRUE if the tetrahedron or subface has been dealloced.
5065 
5066 inline bool tetgenmesh::isdead(triface* t) {
5067  if (t->tet == (tetrahedron *) NULL) return true;
5068  else return t->tet[4] == (tetrahedron) NULL;
5069 }
5070 
5071 inline bool tetgenmesh::isdead(face* s) {
5072  if (s->sh == (shellface *) NULL) return true;
5073  else return s->sh[3] == (shellface) NULL;
5074 }
5075 
5076 // isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices
5077 // of the tetface 't' subface 's'.
5078 
5079 inline bool tetgenmesh::isfacehaspoint(triface* t, point testpoint) {
5080  return ((org(*t) == testpoint) || (dest(*t) == testpoint) ||
5081  (apex(*t) == testpoint));
5082 }
5083 
5084 inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) {
5085  return (s->sh[3] == (shellface) testpoint) ||
5086  (s->sh[4] == (shellface) testpoint) ||
5087  (s->sh[5] == (shellface) testpoint);
5088 }
5089 
5090 // isfacehasedge() returns TRUE if the edge (given by its two endpoints) is
5091 // one of the three edges of the subface 's'.
5092 
5093 inline bool tetgenmesh::isfacehasedge(face* s, point tend1, point tend2) {
5094  return (isfacehaspoint(s, tend1) && isfacehaspoint(s, tend2));
5095 }
5096 
5097 // issymexist() returns TRUE if the adjoining tetrahedron is not 'duumytet'.
5098 
5099 inline bool tetgenmesh::issymexist(triface* t) {
5100  tetrahedron *ptr = (tetrahedron *)
5101  ((unsigned long)(t->tet[t->loc]) & ~(unsigned long)7l);
5102  return ptr != dummytet;
5103 }
5104 
5106 // //
5107 // getnextsface() Finds the next subface in the face ring. //
5108 // //
5109 // For saving space in the data structure of subface, there only exists one //
5110 // face ring around a segment (see programming manual). This routine imple- //
5111 // ments the double face ring as desired in Muecke's data structure. //
5112 // //
5114 
5115 void tetgenmesh::getnextsface(face* s1, face* s2)
5116 {
5117  face neighsh, spinsh;
5118  face testseg;
5119 
5120  sspivot(*s1, testseg);
5121  if (testseg.sh != dummysh) {
5122  testseg.shver = 0;
5123  if (sorg(testseg) == sorg(*s1)) {
5124  spivot(*s1, neighsh);
5125  } else {
5126  spinsh = *s1;
5127  do {
5128  neighsh = spinsh;
5129  spivotself(spinsh);
5130  } while (spinsh.sh != s1->sh);
5131  }
5132  } else {
5133  spivot(*s1, neighsh);
5134  }
5135  if (sorg(neighsh) != sorg(*s1)) {
5136  sesymself(neighsh);
5137  }
5138  if (s2 != (face *) NULL) {
5139  *s2 = neighsh;
5140  } else {
5141  *s1 = neighsh;
5142  }
5143 }
5144 
5146 // //
5147 // tsspivot() Finds a subsegment abutting on a tetrahderon's edge. //
5148 // //
5149 // The edge is represented in the primary edge of 'checkedge'. If there is a //
5150 // subsegment bonded at this edge, it is returned in handle 'checkseg', the //
5151 // edge direction of 'checkseg' is conformed to 'checkedge'. If there isn't, //
5152 // set 'checkseg.sh = dummysh' to indicate it is not a subsegment. //
5153 // //
5154 // To find whether an edge of a tetrahedron is a subsegment or not. First we //
5155 // need find a subface around this edge to see if it contains a subsegment. //
5156 // The reason is there is no direct connection between a tetrahedron and its //
5157 // adjoining subsegments. //
5158 // //
5160 
5161 void tetgenmesh::tsspivot(triface* checkedge, face* checkseg)
5162 {
5163  triface spintet;
5164  face parentsh;
5165  point tapex;
5166  int hitbdry;
5167 
5168  spintet = *checkedge;
5169  tapex = apex(*checkedge);
5170  hitbdry = 0;
5171  do {
5172  tspivot(spintet, parentsh);
5173  // Does spintet have a (non-fake) subface attached?
5174  if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) {
5175  // Find a subface! Find the edge in it.
5176  findedge(&parentsh, org(*checkedge), dest(*checkedge));
5177  sspivot(parentsh, *checkseg);
5178  if (checkseg->sh != dummysh) {
5179  // Find a subsegment! Correct its edge direction before return.
5180  if (sorg(*checkseg) != org(*checkedge)) {
5181  sesymself(*checkseg);
5182  }
5183  }
5184  return;
5185  }
5186  if (!fnextself(spintet)) {
5187  hitbdry++;
5188  if (hitbdry < 2) {
5189  esym(*checkedge, spintet);
5190  if (!fnextself(spintet)) {
5191  hitbdry++;
5192  }
5193  }
5194  }
5195  } while ((apex(spintet) != tapex) && (hitbdry < 2));
5196  // Not find.
5197  checkseg->sh = dummysh;
5198 }
5199 
5201 // //
5202 // sstpivot() Finds a tetrahedron abutting a subsegment. //
5203 // //
5204 // This is the inverse operation of 'tsspivot()'. One subsegment shared by //
5205 // arbitrary number of tetrahedron, the returned tetrahedron is not unique. //
5206 // The edge direction of the returned tetrahedron is conformed to the given //
5207 // subsegment. //
5208 // //
5210 
5211 void tetgenmesh::sstpivot(face* checkseg, triface* retedge)
5212 {
5213  face parentsh;
5214 
5215  // Get the subface which holds the subsegment.
5216  sdecode(checkseg->sh[0], parentsh);
5217 #ifdef SELF_CHECK
5218  assert(parentsh.sh != dummysh);
5219 #endif
5220  // Get a tetraheron to which the subface attches.
5221  stpivot(parentsh, *retedge);
5222  if (retedge->tet == dummytet) {
5223  sesymself(parentsh);
5224  stpivot(parentsh, *retedge);
5225 #ifdef SELF_CHECK
5226  assert(retedge->tet != dummytet);
5227 #endif
5228  }
5229  // Correct the edge direction before return.
5230  findedge(retedge, sorg(*checkseg), sdest(*checkseg));
5231 }
5232 
5234 // //
5235 // findorg() Finds a point in the given handle (tetrahedron or subface). //
5236 // //
5237 // If 'dorg' is a one of vertices of the given handle, set the origin of //
5238 // this handle be that point and return TRUE. Otherwise, return FALSE and //
5239 // 'tface' remains unchanged. //
5240 // //
5242 
5243 bool tetgenmesh::findorg(triface* tface, point dorg)
5244 {
5245  if (org(*tface) == dorg) {
5246  return true;
5247  } else {
5248  if (dest(*tface) == dorg) {
5249  enextself(*tface);
5250  return true;
5251  } else {
5252  if (apex(*tface) == dorg) {
5253  enext2self(*tface);
5254  return true;
5255  } else {
5256  if (oppo(*tface) == dorg) {
5257  // Keep 'tface' referring to the same tet after fnext().
5258  adjustedgering(*tface, CCW);
5259  fnextself(*tface);
5260  enext2self(*tface);
5261  return true;
5262  }
5263  }
5264  }
5265  }
5266  return false;
5267 }
5268 
5269 bool tetgenmesh::findorg(face* sface, point dorg)
5270 {
5271  if (sorg(*sface) == dorg) {
5272  return true;
5273  } else {
5274  if (sdest(*sface) == dorg) {
5275  senextself(*sface);
5276  return true;
5277  } else {
5278  if (sapex(*sface) == dorg) {
5279  senext2self(*sface);
5280  return true;
5281  }
5282  }
5283  }
5284  return false;
5285 }
5286 
5288 // //
5289 // findedge() Find an edge in the given handle (tetrahedron or subface). //
5290 // //
5291 // The edge is given in two points 'eorg' and 'edest'. It is assumed that //
5292 // the edge must exist in the given handle (tetrahedron or subface). This //
5293 // routine sets the right edge version for the input handle. //
5294 // //
5296 
5297 void tetgenmesh::findedge(triface* tface, point eorg, point edest)
5298 {
5299  int i;
5300 
5301  for (i = 0; i < 3; i++) {
5302  if (org(*tface) == eorg) {
5303  if (dest(*tface) == edest) {
5304  // Edge is found, return.
5305  return;
5306  }
5307  } else {
5308  if (org(*tface) == edest) {
5309  if (dest(*tface) == eorg) {
5310  // Edge is found, inverse the direction and return.
5311  esymself(*tface);
5312  return;
5313  }
5314  }
5315  }
5316  enextself(*tface);
5317  }
5318  // It should never be here.
5319  printf("Internalerror in findedge(): Unable to find an edge in tet.\n");
5320  internalerror();
5321 }
5322 
5323 void tetgenmesh::findedge(face* sface, point eorg, point edest)
5324 {
5325  int i;
5326 
5327  for (i = 0; i < 3; i++) {
5328  if (sorg(*sface) == eorg) {
5329  if (sdest(*sface) == edest) {
5330  // Edge is found, return.
5331  return;
5332  }
5333  } else {
5334  if (sorg(*sface) == edest) {
5335  if (sdest(*sface) == eorg) {
5336  // Edge is found, inverse the direction and return.
5337  sesymself(*sface);
5338  return;
5339  }
5340  }
5341  }
5342  senextself(*sface);
5343  }
5344  printf("Internalerror in findedge(): Unable to find an edge in subface.\n");
5345  internalerror();
5346 }
5347 
5349 // //
5350 // findface() Find the face has the given origin, destination and apex. //
5351 // //
5352 // On input, 'fface' is a handle which may contain the three corners or may //
5353 // not or may be dead. On return, it represents exactly the face with the //
5354 // given origin, destination and apex. //
5355 // //
5357 
5358 void tetgenmesh::findface(triface *fface, point forg, point fdest, point fapex)
5359 {
5360  triface spintet;
5361  enum finddirectionresult collinear;
5362  int hitbdry;
5363 
5364  if (!isdead(fface)) {
5365  // First check the easiest case, that 'fface' is just the right one.
5366  if (org(*fface) == forg && dest(*fface) == fdest &&
5367  apex(*fface) == fapex) return;
5368  } else {
5369  // The input handle is dead, use the 'recenttet' if it is alive.
5370  if (!isdead(&recenttet)) *fface = recenttet;
5371  }
5372 
5373  if (!isdead(fface)) {
5374  if (!findorg(fface, forg)) {
5375  // 'forg' is not a corner of 'fface', locate it.
5376  preciselocate(forg, fface, tetrahedrons->items);
5377  }
5378  // It is possible that forg is not found in a non-convex mesh.
5379  if (org(*fface) == forg) {
5380  collinear = finddirection(fface, fdest, tetrahedrons->items);
5381  if (collinear == RIGHTCOLLINEAR) {
5382  // fdest is just the destination.
5383  } else if (collinear == LEFTCOLLINEAR) {
5384  enext2self(*fface);
5385  esymself(*fface);
5386  } else if (collinear == TOPCOLLINEAR) {
5387  fnextself(*fface);
5388  enext2self(*fface);
5389  esymself(*fface);
5390  }
5391  }
5392  // It is possible taht fdest is not found in a non-convex mesh.
5393  if ((org(*fface) == forg) && (dest(*fface) == fdest)) {
5394  // Find the apex of 'fapex'.
5395  spintet = *fface;
5396  hitbdry = 0;
5397  do {
5398  if (apex(spintet) == fapex) {
5399  // We have done. Be careful the edge direction of 'spintet',
5400  // it may reversed because of hitting boundary once.
5401  if (org(spintet) != org(*fface)) {
5402  esymself(spintet);
5403  }
5404  *fface = spintet;
5405  return;
5406  }
5407  if (!fnextself(spintet)) {
5408  hitbdry ++;
5409  if (hitbdry < 2) {
5410  esym(*fface, spintet);
5411  if (!fnextself(spintet)) {
5412  hitbdry ++;
5413  }
5414  }
5415  }
5416  } while (hitbdry < 2 && apex(spintet) != apex(*fface));
5417  // It is possible that fapex is not found in a non-convex mesh.
5418  }
5419  }
5420 
5421  if (isdead(fface) || (org(*fface) != forg) || (dest(*fface) != fdest) ||
5422  (apex(*fface) != fapex)) {
5423  // Too bad, the input handle is useless. We have to find a handle
5424  // for 'fface' contains the 'forg' and 'fdest'. Here a brute force
5425  // search is performed.
5426  if (b->verbose > 1) {
5427  printf("Warning in findface(): Perform a brute-force searching.\n");
5428  }
5429  enum verttype forgty, fdestty, fapexty;
5430  int share, i;
5431  forgty = pointtype(forg);
5432  fdestty = pointtype(fdest);
5433  fapexty = pointtype(fapex);
5434  setpointtype(forg, DEADVERTEX);
5435  setpointtype(fdest, DEADVERTEX);
5436  setpointtype(fapex, DEADVERTEX);
5437  tetrahedrons->traversalinit();
5438  fface->tet = tetrahedrontraverse();
5439  while (fface->tet != (tetrahedron *) NULL) {
5440  share = 0;
5441  for (i = 0; i < 4; i++) {
5442  if (pointtype((point) fface->tet[4 + i]) == DEADVERTEX) share ++;
5443  }
5444  if (share == 3) {
5445  // Found! Set the correct face and desired corners.
5446  if (pointtype((point) fface->tet[4]) != DEADVERTEX) {
5447  fface->loc = 2;
5448  } else if (pointtype((point) fface->tet[5]) != DEADVERTEX) {
5449  fface->loc = 3;
5450  } else if (pointtype((point) fface->tet[6]) != DEADVERTEX) {
5451  fface->loc = 1;
5452  } else { // pointtype((point) fface->tet[7]) != DEADVERTEX
5453  fface->loc = 0;
5454  }
5455  findedge(fface, forg, fdest);
5456  break;
5457  }
5458  fface->tet = tetrahedrontraverse();
5459  }
5460  setpointtype(forg, forgty);
5461  setpointtype(fdest, fdestty);
5462  setpointtype(fapex, fapexty);
5463  if (fface->tet == (tetrahedron *) NULL) {
5464  // It is impossible to reach here.
5465  printf("Internal error: Fail to find the indicated face.\n");
5466  internalerror();
5467  }
5468  }
5469 }
5470 
5472 // //
5473 // getonextseg() Get the next SEGMENT counterclockwise with the same org. //
5474 // //
5475 // 's' is a subface. This routine reteuns the segment which is counterclock- //
5476 // wise with the origin of s. //
5477 // //
5479 
5480 void tetgenmesh::getonextseg(face* s, face* lseg)
5481 {
5482  face checksh, checkseg;
5483  point forg;
5484 
5485  forg = sorg(*s);
5486  checksh = *s;
5487  do {
5488  // Go to the edge at forg's left side.
5489  senext2self(checksh);
5490  // Check if there is a segment attaching this edge.
5491  sspivot(checksh, checkseg);
5492  if (checkseg.sh != dummysh) break;
5493  // No segment! Go to the neighbor of this subface.
5494  spivotself(checksh);
5495 #ifdef SELF_CHECK
5496  // It should always meet a segment before come back.
5497  assert(checksh.sh != s->sh);
5498 #endif
5499  if (sorg(checksh) != forg) {
5500  sesymself(checksh);
5501 #ifdef SELF_CHECK
5502  assert(sorg(checksh) == forg);
5503 #endif
5504  }
5505  } while (true);
5506  if (sorg(checkseg) != forg) sesymself(checkseg);
5507  *lseg = checkseg;
5508 }
5509 
5511 // //
5512 // getseghasorg() Get the segment containing the given point. //
5513 // //
5514 // 'dorg' is an endpoint of a segment S. 'sseg' is a subsegment of S. This //
5515 // routine search a subsegment (along sseg) of S containing dorg. On return, //
5516 // 'sseg' contains 'dorg' as its origin. //
5517 // //
5519 
5520 void tetgenmesh::getseghasorg(face* sseg, point dorg)
5521 {
5522  face nextseg;
5523  point checkpt;
5524 
5525  nextseg = *sseg;
5526  checkpt = sorg(nextseg);
5527  while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) {
5528  // Search dorg along the original direction of sseg.
5529  senext2self(nextseg);
5530  spivotself(nextseg);
5531  nextseg.shver = 0;
5532  if (sdest(nextseg) != checkpt) sesymself(nextseg);
5533  checkpt = sorg(nextseg);
5534  }
5535  if (checkpt == dorg) {
5536  *sseg = nextseg;
5537  return;
5538  }
5539  nextseg = *sseg;
5540  checkpt = sdest(nextseg);
5541  while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) {
5542  // Search dorg along the destinational direction of sseg.
5543  senextself(nextseg);
5544  spivotself(nextseg);
5545  nextseg.shver = 0;
5546  if (sorg(nextseg) != checkpt) sesymself(nextseg);
5547  checkpt = sdest(nextseg);
5548  }
5549  if (checkpt == dorg) {
5550  sesym(nextseg, *sseg);
5551  return;
5552  }
5553  // Should never be here.
5554  printf("Internalerror in getseghasorg(): Unable to find the subseg.\n");
5555  internalerror();
5556 }
5557 
5559 // //
5560 // getsubsegfarorg() Get the origin of the parent segment of a subseg. //
5561 // //
5563 
5564 tetgenmesh::point tetgenmesh::getsubsegfarorg(face* sseg)
5565 {
5566  face prevseg;
5567  point checkpt;
5568 
5569  checkpt = sorg(*sseg);
5570  senext2(*sseg, prevseg);
5571  spivotself(prevseg);
5572  // Search dorg along the original direction of sseg.
5573  while (prevseg.sh != dummysh) {
5574  prevseg.shver = 0;
5575  if (sdest(prevseg) != checkpt) sesymself(prevseg);
5576  checkpt = sorg(prevseg);
5577  senext2self(prevseg);
5578  spivotself(prevseg);
5579  }
5580  return checkpt;
5581 }
5582 
5584 // //
5585 // getsubsegfardest() Get the dest. of the parent segment of a subseg. //
5586 // //
5588 
5589 tetgenmesh::point tetgenmesh::getsubsegfardest(face* sseg)
5590 {
5591  face nextseg;
5592  point checkpt;
5593 
5594  checkpt = sdest(*sseg);
5595  senext(*sseg, nextseg);
5596  spivotself(nextseg);
5597  // Search dorg along the destinational direction of sseg.
5598  while (nextseg.sh != dummysh) {
5599  nextseg.shver = 0;
5600  if (sorg(nextseg) != checkpt) sesymself(nextseg);
5601  checkpt = sdest(nextseg);
5602  senextself(nextseg);
5603  spivotself(nextseg);
5604  }
5605  return checkpt;
5606 }
5607 
5609 // //
5610 // printtet() Print out the details of a tetrahedron on screen. //
5611 // //
5612 // It's also used when the highest level of verbosity (`-VVV') is specified. //
5613 // //
5615 
5616 void tetgenmesh::printtet(triface* tface)
5617 {
5618  triface tmpface, prtface;
5619  point tmppt;
5620  face tmpsh;
5621  int facecount;
5622 
5623  printf("Tetra x%lx with loc(%i) and ver(%i):",
5624  (unsigned long)(tface->tet), tface->loc, tface->ver);
5625  if (infected(*tface)) {
5626  printf(" (infected)");
5627  }
5628  printf("\n");
5629 
5630  tmpface = *tface;
5631  facecount = 0;
5632  while(facecount < 4) {
5633  tmpface.loc = facecount;
5634  sym(tmpface, prtface);
5635  if(prtface.tet == dummytet) {
5636  printf(" [%i] Outer space.\n", facecount);
5637  } else {
5638  printf(" [%i] x%lx loc(%i).", facecount,
5639  (unsigned long)(prtface.tet), prtface.loc);
5640  if (infected(prtface)) {
5641  printf(" (infected)");
5642  }
5643  printf("\n");
5644  }
5645  facecount ++;
5646  }
5647 
5648  tmppt = org(*tface);
5649  if(tmppt == (point) NULL) {
5650  printf(" Org [%i] NULL\n", locver2org[tface->loc][tface->ver]);
5651  } else {
5652  printf(" Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5653  locver2org[tface->loc][tface->ver], (unsigned long)(tmppt),
5654  tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5655  }
5656  tmppt = dest(*tface);
5657  if(tmppt == (point) NULL) {
5658  printf(" Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]);
5659  } else {
5660  printf(" Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5661  locver2dest[tface->loc][tface->ver], (unsigned long)(tmppt),
5662  tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5663  }
5664  tmppt = apex(*tface);
5665  if(tmppt == (point) NULL) {
5666  printf(" Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]);
5667  } else {
5668  printf(" Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5669  locver2apex[tface->loc][tface->ver], (unsigned long)(tmppt),
5670  tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5671  }
5672  tmppt = oppo(*tface);
5673  if(tmppt == (point) NULL) {
5674  printf(" Oppo[%i] NULL\n", loc2oppo[tface->loc]);
5675  } else {
5676  printf(" Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n",
5677  loc2oppo[tface->loc], (unsigned long)(tmppt),
5678  tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt));
5679  }
5680 
5681  if (b->useshelles) {
5682  tmpface = *tface;
5683  facecount = 0;
5684  while(facecount < 6) {
5685  tmpface.loc = facecount;
5686  tspivot(tmpface, tmpsh);
5687  if(tmpsh.sh != dummysh) {
5688  printf(" [%i] x%lx ID(%i) ", facecount,
5689  (unsigned long)(tmpsh.sh), shellmark(tmpsh));
5690  if (sorg(tmpsh) == (point) NULL) {
5691  printf("(fake)");
5692  }
5693  printf("\n");
5694  }
5695  facecount ++;
5696  }
5697  }
5698 }
5699 
5701 // //
5702 // printsh() Print out the details of a subface or subsegment on screen. //
5703 // //
5704 // It's also used when the highest level of verbosity (`-VVV') is specified. //
5705 // //
5707 
5708 void tetgenmesh::printsh(face* sface)
5709 {
5710  face prtsh;
5711  triface prttet;
5712  point printpoint;
5713 
5714  if (sapex(*sface) != NULL) {
5715  printf("subface x%lx, ver %d, mark %d:",
5716  (unsigned long)(sface->sh), sface->shver, shellmark(*sface));
5717  } else {
5718  printf("Subsegment x%lx, ver %d, mark %d:",
5719  (unsigned long)(sface->sh), sface->shver, shellmark(*sface));
5720  }
5721  if (sinfected(*sface)) {
5722  printf(" (infected)");
5723  }
5724  if (shell2badface(*sface)) {
5725  printf(" (queued)");
5726  }
5727  if (sapex(*sface) != NULL) {
5728  if (shelltype(*sface) == SHARP) {
5729  printf(" (sharp)");
5730  }
5731  } else {
5732  if (shelltype(*sface) == SHARP) {
5733  printf(" (sharp)");
5734  }
5735  }
5736  if (checkpbcs) {
5737  if (shellpbcgroup(*sface) >= 0) {
5738  printf(" (pbc %d)", shellpbcgroup(*sface));
5739  }
5740  }
5741  printf("\n");
5742 
5743  sdecode(sface->sh[0], prtsh);
5744  if (prtsh.sh == dummysh) {
5745  printf(" [0] = No shell\n");
5746  } else {
5747  printf(" [0] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5748  }
5749  sdecode(sface->sh[1], prtsh);
5750  if (prtsh.sh == dummysh) {
5751  printf(" [1] = No shell\n");
5752  } else {
5753  printf(" [1] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5754  }
5755  sdecode(sface->sh[2], prtsh);
5756  if (prtsh.sh == dummysh) {
5757  printf(" [2] = No shell\n");
5758  } else {
5759  printf(" [2] = x%lx %d\n", (unsigned long)(prtsh.sh), prtsh.shver);
5760  }
5761 
5762  printpoint = sorg(*sface);
5763  if (printpoint == (point) NULL)
5764  printf(" Org [%d] = NULL\n", vo[sface->shver]);
5765  else
5766  printf(" Org [%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5767  vo[sface->shver], (unsigned long)(printpoint), printpoint[0],
5768  printpoint[1], printpoint[2], pointmark(printpoint));
5769  printpoint = sdest(*sface);
5770  if (printpoint == (point) NULL)
5771  printf(" Dest[%d] = NULL\n", vd[sface->shver]);
5772  else
5773  printf(" Dest[%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5774  vd[sface->shver], (unsigned long)(printpoint), printpoint[0],
5775  printpoint[1], printpoint[2], pointmark(printpoint));
5776 
5777  if (sapex(*sface) != NULL) {
5778  printpoint = sapex(*sface);
5779  if (printpoint == (point) NULL)
5780  printf(" Apex[%d] = NULL\n", va[sface->shver]);
5781  else
5782  printf(" Apex[%d] = x%lx (%.12g,%.12g,%.12g) %d\n",
5783  va[sface->shver], (unsigned long)(printpoint), printpoint[0],
5784  printpoint[1], printpoint[2], pointmark(printpoint));
5785 
5786  decode(sface->sh[6], prttet);
5787  if (prttet.tet == dummytet) {
5788  printf(" [6] = Outer space\n");
5789  } else {
5790  printf(" [6] = x%lx %d\n",
5791  (unsigned long)(prttet.tet), prttet.loc);
5792  }
5793  decode(sface->sh[7], prttet);
5794  if (prttet.tet == dummytet) {
5795  printf(" [7] = Outer space\n");
5796  } else {
5797  printf(" [7] = x%lx %d\n",
5798  (unsigned long)(prttet.tet), prttet.loc);
5799  }
5800 
5801  sdecode(sface->sh[8], prtsh);
5802  if (prtsh.sh == dummysh) {
5803  printf(" [8] = No subsegment\n");
5804  } else {
5805  printf(" [8] = x%lx %d\n",
5806  (unsigned long)(prtsh.sh), prtsh.shver);
5807  }
5808  sdecode(sface->sh[9], prtsh);
5809  if (prtsh.sh == dummysh) {
5810  printf(" [9] = No subsegment\n");
5811  } else {
5812  printf(" [9] = x%lx %d\n",
5813  (unsigned long)(prtsh.sh), prtsh.shver);
5814  }
5815  sdecode(sface->sh[10], prtsh);
5816  if (prtsh.sh == dummysh) {
5817  printf(" [10]= No subsegment\n");
5818  } else {
5819  printf(" [10]= x%lx %d\n",
5820  (unsigned long)(prtsh.sh), prtsh.shver);
5821  }
5822  }
5823 }
5824 
5825 //
5826 // End of advanced primitives
5827 //
5828 
5829 //
5830 // End of mesh manipulation primitives
5831 //
5832 
5833 //
5834 // Begin of mesh items searching routines
5835 //
5836 
5838 // //
5839 // makepoint2tetmap() Construct a mapping from points to tetrahedra. //
5840 // //
5841 // Traverses all the tetrahedra, provides each corner of each tetrahedron //
5842 // with a pointer to that tetrahedera. Some pointers will be overwritten by //
5843 // other pointers because each point may be a corner of several tetrahedra, //
5844 // but in the end every point will point to a tetrahedron that contains it. //
5845 // //
5847 
5848 void tetgenmesh::makepoint2tetmap()
5849 {
5850  triface tetloop;
5851  point pointptr;
5852 
5853  if (b->verbose > 0) {
5854  printf(" Constructing mapping from points to tetrahedra.\n");
5855  }
5856 
5857  // Initialize the point2tet field of each point.
5858  points->traversalinit();
5859  pointptr = pointtraverse();
5860  while (pointptr != (point) NULL) {
5861  setpoint2tet(pointptr, (tetrahedron) NULL);
5862  pointptr = pointtraverse();
5863  }
5864 
5865  tetrahedrons->traversalinit();
5866  tetloop.tet = tetrahedrontraverse();
5867  while (tetloop.tet != (tetrahedron *) NULL) {
5868  // Check all four points of the tetrahedron.
5869  tetloop.loc = 0;
5870  pointptr = org(tetloop);
5871  setpoint2tet(pointptr, encode(tetloop));
5872  pointptr = dest(tetloop);
5873  setpoint2tet(pointptr, encode(tetloop));
5874  pointptr = apex(tetloop);
5875  setpoint2tet(pointptr, encode(tetloop));
5876  pointptr = oppo(tetloop);
5877  setpoint2tet(pointptr, encode(tetloop));
5878  // Get the next tetrahedron in the list.
5879  tetloop.tet = tetrahedrontraverse();
5880  }
5881 }
5882 
5884 // //
5885 // makeindex2pointmap() Create a map from index to vertices. //
5886 // //
5887 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
5888 // to each vertex is set into the array. The pointer to the first vertex is //
5889 // saved in 'idx2verlist[0]'. Don't forget to minus 'in->firstnumber' when //
5890 // to get the vertex form its index. //
5891 // //
5893 
5894 void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
5895 {
5896  point pointloop;
5897  int idx;
5898 
5899  if (b->verbose > 0) {
5900  printf(" Constructing mapping from indices to points.\n");
5901  }
5902 
5903  idx2verlist = new point[points->items];
5904 
5905  points->traversalinit();
5906  pointloop = pointtraverse();
5907  idx = 0;
5908  while (pointloop != (point) NULL) {
5909  idx2verlist[idx] = pointloop;
5910  idx++;
5911  pointloop = pointtraverse();
5912  }
5913 }
5914 
5916 // //
5917 // makesegmentmap() Create a map from vertices (their indices) to //
5918 // segments incident at the same vertices. //
5919 // //
5920 // Two arrays 'idx2seglist' and 'segsperverlist' together return the map. //
5921 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
5922 // number of segments. idx2seglist contains row information and //
5923 // segsperverlist contains all (non-zero) elements. The i-th entry of //
5924 // idx2seglist is the starting position of i-th row's (non-zero) elements in //
5925 // segsperverlist. The number of elements of i-th row is calculated by the //
5926 // (i+1)-th entry minus i-th entry of idx2seglist. //
5927 // //
5928 // NOTE: These two arrays will be created inside this routine, don't forget //
5929 // to free them after using. //
5930 // //
5932 
5933 void tetgenmesh::makesegmentmap(int*& idx2seglist, shellface**& segsperverlist)
5934 {
5935  shellface *shloop;
5936  int i, j, k;
5937 
5938  if (b->verbose > 0) {
5939  printf(" Constructing mapping from points to segments.\n");
5940  }
5941 
5942  // Create and initialize 'idx2seglist'.
5943  idx2seglist = new int[points->items + 1];
5944  for (i = 0; i < points->items + 1; i++) idx2seglist[i] = 0;
5945 
5946  // Loop the set of segments once, counter the number of segments sharing
5947  // each vertex.
5948  subsegs->traversalinit();
5949  shloop = shellfacetraverse(subsegs);
5950  while (shloop != (shellface *) NULL) {
5951  // Increment the number of sharing segments for each endpoint.
5952  for (i = 0; i < 2; i++) {
5953  j = pointmark((point) shloop[3 + i]) - in->firstnumber;
5954  idx2seglist[j]++;
5955  }
5956  shloop = shellfacetraverse(subsegs);
5957  }
5958 
5959  // Calculate the total length of array 'facesperverlist'.
5960  j = idx2seglist[0];
5961  idx2seglist[0] = 0; // Array starts from 0 element.
5962  for (i = 0; i < points->items; i++) {
5963  k = idx2seglist[i + 1];
5964  idx2seglist[i + 1] = idx2seglist[i] + j;
5965  j = k;
5966  }
5967  // The total length is in the last unit of idx2seglist.
5968  segsperverlist = new shellface*[idx2seglist[i]];
5969  // Loop the set of segments again, set the info. of segments per vertex.
5970  subsegs->traversalinit();
5971  shloop = shellfacetraverse(subsegs);
5972  while (shloop != (shellface *) NULL) {
5973  for (i = 0; i < 2; i++) {
5974  j = pointmark((point) shloop[3 + i]) - in->firstnumber;
5975  segsperverlist[idx2seglist[j]] = shloop;
5976  idx2seglist[j]++;
5977  }
5978  shloop = shellfacetraverse(subsegs);
5979  }
5980  // Contents in 'idx2seglist' are shifted, now shift them back.
5981  for (i = points->items - 1; i >= 0; i--) {
5982  idx2seglist[i + 1] = idx2seglist[i];
5983  }
5984  idx2seglist[0] = 0;
5985 }
5986 
5988 // //
5989 // makesubfacemap() Create a map from vertices (their indices) to //
5990 // subfaces incident at the same vertices. //
5991 // //
5992 // Two arrays 'idx2facelist' and 'facesperverlist' together return the map. //
5993 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
5994 // number of subfaces. idx2facelist contains row information and //
5995 // facesperverlist contains all (non-zero) elements. The i-th entry of //
5996 // idx2facelist is the starting position of i-th row's(non-zero) elements in //
5997 // facesperverlist. The number of elements of i-th row is calculated by the //
5998 // (i+1)-th entry minus i-th entry of idx2facelist. //
5999 // //
6000 // NOTE: These two arrays will be created inside this routine, don't forget //
6001 // to free them after using. //
6002 // //
6004 
6005 void tetgenmesh::
6006 makesubfacemap(int*& idx2facelist, shellface**& facesperverlist)
6007 {
6008  shellface *shloop;
6009  int i, j, k;
6010 
6011  if (b->verbose > 0) {
6012  printf(" Constructing mapping from points to subfaces.\n");
6013  }
6014 
6015  // Create and initialize 'idx2facelist'.
6016  idx2facelist = new int[points->items + 1];
6017  for (i = 0; i < points->items + 1; i++) idx2facelist[i] = 0;
6018 
6019  // Loop the set of subfaces once, counter the number of subfaces sharing
6020  // each vertex.
6021  subfaces->traversalinit();
6022  shloop = shellfacetraverse(subfaces);
6023  while (shloop != (shellface *) NULL) {
6024  // Increment the number of sharing segments for each endpoint.
6025  for (i = 0; i < 3; i++) {
6026  j = pointmark((point) shloop[3 + i]) - in->firstnumber;
6027  idx2facelist[j]++;
6028  }
6029  shloop = shellfacetraverse(subfaces);
6030  }
6031 
6032  // Calculate the total length of array 'facesperverlist'.
6033  j = idx2facelist[0];
6034  idx2facelist[0] = 0; // Array starts from 0 element.
6035  for (i = 0; i < points->items; i++) {
6036  k = idx2facelist[i + 1];
6037  idx2facelist[i + 1] = idx2facelist[i] + j;
6038  j = k;
6039  }
6040  // The total length is in the last unit of idx2facelist.
6041  facesperverlist = new shellface*[idx2facelist[i]];
6042  // Loop the set of segments again, set the info. of segments per vertex.
6043  subfaces->traversalinit();
6044  shloop = shellfacetraverse(subfaces);
6045  while (shloop != (shellface *) NULL) {
6046  for (i = 0; i < 3; i++) {
6047  j = pointmark((point) shloop[3 + i]) - in->firstnumber;
6048  facesperverlist[idx2facelist[j]] = shloop;
6049  idx2facelist[j]++;
6050  }
6051  shloop = shellfacetraverse(subfaces);
6052  }
6053  // Contents in 'idx2facelist' are shifted, now shift them back.
6054  for (i = points->items - 1; i >= 0; i--) {
6055  idx2facelist[i + 1] = idx2facelist[i];
6056  }
6057  idx2facelist[0] = 0;
6058 }
6059 
6061 // //
6062 // maketetrahedronmap() Create a map from vertices (their indices) to //
6063 // tetrahedra incident at the same vertices. //
6064 // //
6065 // Two arrays 'idx2tetlist' and 'tetsperverlist' together return the map. //
6066 // They form a sparse matrix structure with size (n + 1) x (n + 1), n is the //
6067 // number of tetrahedra. idx2tetlist contains row information and //
6068 // tetsperverlist contains all (non-zero) elements. The i-th entry of //
6069 // idx2tetlist is the starting position of i-th row's (non-zero) elements in //
6070 // tetsperverlist. The number of elements of i-th row is calculated by the //
6071 // (i+1)-th entry minus i-th entry of idx2tetlist. //
6072 // //
6073 // NOTE: These two arrays will be created inside this routine, don't forget //
6074 // to free them after using. //
6075 // //
6077 
6078 void tetgenmesh::
6079 maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist)
6080 {
6081  tetrahedron *tetloop;
6082  int i, j, k;
6083 
6084  if (b->verbose > 0) {
6085  printf(" Constructing mapping from points to tetrahedra.\n");
6086  }
6087 
6088  // Create and initialize 'idx2tetlist'.
6089  idx2tetlist = new int[points->items + 1];
6090  for (i = 0; i < points->items + 1; i++) idx2tetlist[i] = 0;
6091 
6092  // Loop the set of tetrahedra once, counter the number of tetrahedra
6093  // sharing each vertex.
6094  tetrahedrons->traversalinit();
6095  tetloop = tetrahedrontraverse();
6096  while (tetloop != (tetrahedron *) NULL) {
6097  // Increment the number of sharing tetrahedra for each endpoint.
6098  for (i = 0; i < 4; i++) {
6099  j = pointmark((point) tetloop[4 + i]) - in->firstnumber;
6100  idx2tetlist[j]++;
6101  }
6102  tetloop = tetrahedrontraverse();
6103  }
6104 
6105  // Calculate the total length of array 'tetsperverlist'.
6106  j = idx2tetlist[0];
6107  idx2tetlist[0] = 0; // Array starts from 0 element.
6108  for (i = 0; i < points->items; i++) {
6109  k = idx2tetlist[i + 1];
6110  idx2tetlist[i + 1] = idx2tetlist[i] + j;
6111  j = k;
6112  }
6113  // The total length is in the last unit of idx2tetlist.
6114  tetsperverlist = new tetrahedron*[idx2tetlist[i]];
6115  // Loop the set of tetrahedra again, set the info. of tet. per vertex.
6116  tetrahedrons->traversalinit();
6117  tetloop = tetrahedrontraverse();
6118  while (tetloop != (tetrahedron *) NULL) {
6119  for (i = 0; i < 4; i++) {
6120  j = pointmark((point) tetloop[4 + i]) - in->firstnumber;
6121  tetsperverlist[idx2tetlist[j]] = tetloop;
6122  idx2tetlist[j]++;
6123  }
6124  tetloop = tetrahedrontraverse();
6125  }
6126  // Contents in 'idx2tetlist' are shifted, now shift them back.
6127  for (i = points->items - 1; i >= 0; i--) {
6128  idx2tetlist[i + 1] = idx2tetlist[i];
6129  }
6130  idx2tetlist[0] = 0;
6131 }
6132 
6133 //
6134 // End of mesh items searching routines
6135 //
6136 
6137 //
6138 // Begin of linear algebra functions
6139 //
6140 
6141 // dot() returns the dot product: v1 dot v2.
6142 
6143 inline REAL tetgenmesh::dot(REAL* v1, REAL* v2)
6144 {
6145  return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
6146 }
6147 
6148 // cross() computes the cross product: n = v1 cross v2.
6149 
6150 inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n)
6151 {
6152  n[0] = v1[1] * v2[2] - v2[1] * v1[2];
6153  n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]);
6154  n[2] = v1[0] * v2[1] - v2[0] * v1[1];
6155 }
6156 
6157 // initm44() initializes a 4x4 matrix.
6158 static void initm44(REAL a00, REAL a01, REAL a02, REAL a03,
6159  REAL a10, REAL a11, REAL a12, REAL a13,
6160  REAL a20, REAL a21, REAL a22, REAL a23,
6161  REAL a30, REAL a31, REAL a32, REAL a33,
6162  REAL M[4][4])
6163 {
6164  M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03;
6165  M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13;
6166  M[2][0] = a20; M[2][1] = a21; M[2][2] = a22; M[2][3] = a23;
6167  M[3][0] = a30; M[3][1] = a31; M[3][2] = a32; M[3][3] = a33;
6168 }
6169 
6170 // m4xm4() multiplies 2 4x4 matrics: m1 = m1 * m2.
6171 static void m4xm4(REAL m1[4][4], REAL m2[4][4])
6172 {
6173  REAL tmp[4];
6174  int i, j;
6175 
6176  for (i = 0; i < 4; i++) { // i-th row
6177  for (j = 0; j < 4; j++) { // j-th col
6178  tmp[j] = m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j]
6179  + m1[i][2] * m2[2][j] + m1[i][3] * m2[3][j];
6180  }
6181  for (j = 0; j < 4; j++)
6182  m1[i][j] = tmp[j];
6183  }
6184 }
6185 
6186 // m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1
6187 static void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4])
6188 {
6189  v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3];
6190  v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3];
6191  v2[2] = m[2][0]*v1[0] + m[2][1]*v1[1] + m[2][2]*v1[2] + m[2][3]*v1[3];
6192  v2[3] = m[3][0]*v1[0] + m[3][1]*v1[1] + m[3][2]*v1[2] + m[3][3]*v1[3];
6193 }
6194 
6196 // //
6197 // lu_decmp() Compute the LU decomposition of a matrix. //
6198 // //
6199 // Compute the LU decomposition of a (non-singular) square matrix A using //
6200 // partial pivoting and implicit row exchanges. The result is: //
6201 // A = P * L * U, //
6202 // where P is a permutation matrix, L is unit lower triangular, and U is //
6203 // upper triangular. The factored form of A is used in combination with //
6204 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
6205 // //
6206 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
6207 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
6208 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
6209 // permutation effected by the partial pivoting, effectively, 'ps' array //
6210 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
6211 // depending on whether the number of row interchanges was even or odd, //
6212 // respectively. //
6213 // //
6214 // Return true if the LU decomposition is successfully computed, otherwise, //
6215 // return false in case that A is a singular matrix. //
6216 // //
6218 
6219 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6220 {
6221  REAL scales[4];
6222  REAL pivot, biggest, mult, tempf;
6223  int pivotindex = 0;
6224  int i, j, k;
6225 
6226  *d = 1.0; // No row interchanges yet.
6227 
6228  for (i = N; i < n + N; i++) { // For each row.
6229  // Find the largest element in each row for row equilibration
6230  biggest = 0.0;
6231  for (j = N; j < n + N; j++)
6232  if (biggest < (tempf = fabs(lu[i][j])))
6233  biggest = tempf;
6234  if (biggest != 0.0)
6235  scales[i] = 1.0 / biggest;
6236  else {
6237  scales[i] = 0.0;
6238  return false; // Zero row: singular matrix.
6239  }
6240  ps[i] = i; // Initialize pivot sequence.
6241  }
6242 
6243  for (k = N; k < n + N - 1; k++) { // For each column.
6244  // Find the largest element in each column to pivot around.
6245  biggest = 0.0;
6246  for (i = k; i < n + N; i++) {
6247  if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6248  biggest = tempf;
6249  pivotindex = i;
6250  }
6251  }
6252  if (biggest == 0.0) {
6253  return false; // Zero column: singular matrix.
6254  }
6255  if (pivotindex != k) { // Update pivot sequence.
6256  j = ps[k];
6257  ps[k] = ps[pivotindex];
6258  ps[pivotindex] = j;
6259  *d = -(*d); // ...and change the parity of d.
6260  }
6261 
6262  // Pivot, eliminating an extra variable each time
6263  pivot = lu[ps[k]][k];
6264  for (i = k + 1; i < n + N; i++) {
6265  lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6266  if (mult != 0.0) {
6267  for (j = k + 1; j < n + N; j++)
6268  lu[ps[i]][j] -= mult * lu[ps[k]][j];
6269  }
6270  }
6271  }
6272 
6273  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6274  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6275 }
6276 
6278 // //
6279 // lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6280 // has been decomposed into the lower and upper triangular //
6281 // matrices L and U, where A = LU. //
6282 // //
6283 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6284 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6285 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6286 // is input as the right-hand side vector, and returns with the solution //
6287 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6288 // left in place for successive calls with different right-hand sides 'b'. //
6289 // //
6291 
6292 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6293 {
6294  int i, j;
6295  REAL X[4], dot;
6296 
6297  for (i = N; i < n + N; i++) X[i] = 0.0;
6298 
6299  // Vector reduction using U triangular matrix.
6300  for (i = N; i < n + N; i++) {
6301  dot = 0.0;
6302  for (j = N; j < i + N; j++)
6303  dot += lu[ps[i]][j] * X[j];
6304  X[i] = b[ps[i]] - dot;
6305  }
6306 
6307  // Back substitution, in L triangular matrix.
6308  for (i = n + N - 1; i >= N; i--) {
6309  dot = 0.0;
6310  for (j = i + 1; j < n + N; j++)
6311  dot += lu[ps[i]][j] * X[j];
6312  X[i] = (X[i] - dot) / lu[ps[i]][i];
6313  }
6314 
6315  for (i = N; i < n + N; i++) b[i] = X[i];
6316 }
6317 
6318 //
6319 // End of linear algebra functions
6320 //
6321 
6322 //
6323 // Begin of geometric tests
6324 //
6325 
6326 // All the following routines require the input objects are not degenerate.
6327 // i.e., a triangle must has three non-collinear corners; an edge must
6328 // has two identical endpoints. Degenerate cases should have to detect
6329 // first and then handled as special cases.
6330 
6332 // //
6333 // edge_vert_col_inter() Test whether an edge (ab) and a collinear vertex //
6334 // (p) are intersecting or not. //
6335 // //
6336 // Possible cases are p is coincident to a (p = a), or to b (p = b), or p is //
6337 // inside ab (a < p < b), or outside ab (p < a or p > b). These cases can be //
6338 // quickly determined by comparing the corresponding coords of a, b, and p //
6339 // (which are not all equal). //
6340 // //
6341 // The return value indicates one of the three cases: DISJOINT, SHAREVERTEX //
6342 // (p = a or p = b), and INTERSECT (a < p < b). //
6343 // //
6345 
6346 enum tetgenmesh::interresult tetgenmesh::edge_vert_col_inter(REAL* A, REAL* B,
6347  REAL* P)
6348 {
6349  int i = 0;
6350  do {
6351  if (A[i] < B[i]) {
6352  if (P[i] < A[i]) {
6353  return DISJOINT;
6354  } else if (P[i] > A[i]) {
6355  if (P[i] < B[i]) {
6356  return INTERSECT;
6357  } else if (P[i] > B[i]) {
6358  return DISJOINT;
6359  } else {
6360  // assert(P[i] == B[i]);
6361  return SHAREVERTEX;
6362  }
6363  } else {
6364  // assert(P[i] == A[i]);
6365  return SHAREVERTEX;
6366  }
6367  } else if (A[i] > B[i]) {
6368  if (P[i] < B[i]) {
6369  return DISJOINT;
6370  } else if (P[i] > B[i]) {
6371  if (P[i] < A[i]) {
6372  return INTERSECT;
6373  } else if (P[i] > A[i]) {
6374  return DISJOINT;
6375  } else {
6376  // assert(P[i] == A[i]);
6377  return SHAREVERTEX;
6378  }
6379  } else {
6380  // assert(P[i] == B[i]);
6381  return SHAREVERTEX;
6382  }
6383  }
6384  // i-th coordinates are equal, try i+1-th;
6385  i++;
6386  } while (i < 3);
6387  // Should never be here.
6388  return DISJOINT;
6389 }
6390 
6392 // //
6393 // edge_edge_cop_inter() Test whether two coplanar edges (ab, and pq) are //
6394 // intersecting or not. //
6395 // //
6396 // Possible cases are ab and pq are disjointed, or proper intersecting (int- //
6397 // ersect at a point other than their endpoints), or both collinear and int- //
6398 // ersecting, or sharing at a common endpoint, or are coincident. //
6399 // //
6400 // A reference point R is required, which is exactly not coplanar with these //
6401 // two edges. Since the caller knows these two edges are coplanar, it must //
6402 // be able to provide (or calculate) such a point. //
6403 // //
6404 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6405 // SHAREEDGE, and INTERSECT. //
6406 // //
6408 
6409 enum tetgenmesh::interresult tetgenmesh:: edge_edge_cop_inter(REAL* A, REAL* B,
6410  REAL* P, REAL* Q, REAL* R)
6411 {
6412  REAL s1, s2, s3, s4;
6413 
6414 #ifdef SELF_CHECK
6415  assert(R != NULL);
6416 #endif
6417  s1 = orient3d(A, B, R, P);
6418  s2 = orient3d(A, B, R, Q);
6419  if (s1 * s2 > 0.0) {
6420  // Both p and q are at the same side of ab.
6421  return DISJOINT;
6422  }
6423  s3 = orient3d(P, Q, R, A);
6424  s4 = orient3d(P, Q, R, B);
6425  if (s3 * s4 > 0.0) {
6426  // Both a and b are at the same side of pq.
6427  return DISJOINT;
6428  }
6429 
6430  // Possible degenerate cases are:
6431  // (1) Only one of p and q is collinear with ab;
6432  // (2) Both p and q are collinear with ab;
6433  // (3) Only one of a and b is collinear with pq.
6434  enum interresult abp, abq;
6435  enum interresult pqa, pqb;
6436 
6437  if (s1 == 0.0) {
6438  // p is collinear with ab.
6439  abp = edge_vert_col_inter(A, B, P);
6440  if (abp == INTERSECT) {
6441  // p is inside ab.
6442  return INTERSECT;
6443  }
6444  if (s2 == 0.0) {
6445  // q is collinear with ab. Case (2).
6446  abq = edge_vert_col_inter(A, B, Q);
6447  if (abq == INTERSECT) {
6448  // q is inside ab.
6449  return INTERSECT;
6450  }
6451  if (abp == SHAREVERTEX && abq == SHAREVERTEX) {
6452  // ab and pq are identical.
6453  return SHAREEDGE;
6454  }
6455  pqa = edge_vert_col_inter(P, Q, A);
6456  if (pqa == INTERSECT) {
6457  // a is inside pq.
6458  return INTERSECT;
6459  }
6460  pqb = edge_vert_col_inter(P, Q, B);
6461  if (pqb == INTERSECT) {
6462  // b is inside pq.
6463  return INTERSECT;
6464  }
6465  if (abp == SHAREVERTEX || abq == SHAREVERTEX) {
6466  // either p or q is coincident with a or b.
6467 #ifdef SELF_CHECK
6468  // ONLY one case is possible, otherwise, shoule be SHAREEDGE.
6469  assert(abp ^ abq);
6470 #endif
6471  return SHAREVERTEX;
6472  }
6473  // The last case. They are disjointed.
6474 #ifdef SELF_CHECK
6475  assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb));
6476 #endif
6477  return DISJOINT;
6478  } else {
6479  // p is collinear with ab. Case (1).
6480 #ifdef SELF_CHECK
6481  assert(abp == SHAREVERTEX || abp == DISJOINT);
6482 #endif
6483  return abp;
6484  }
6485  }
6486  // p is NOT collinear with ab.
6487  if (s2 == 0.0) {
6488  // q is collinear with ab. Case (1).
6489  abq = edge_vert_col_inter(A, B, Q);
6490 #ifdef SELF_CHECK
6491  assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT);
6492 #endif
6493  return abq;
6494  }
6495 
6496  // We have found p and q are not collinear with ab. However, it is still
6497  // possible that a or b is collinear with pq (ONLY one of a and b).
6498  if (s3 == 0.0) {
6499  // a is collinear with pq. Case (3).
6500 #ifdef SELF_CHECK
6501  assert(s4 != 0.0);
6502 #endif
6503  pqa = edge_vert_col_inter(P, Q, A);
6504 #ifdef SELF_CHECK
6505  // This case should have been detected in above.
6506  assert(pqa != SHAREVERTEX);
6507  assert(pqa == INTERSECT || pqa == DISJOINT);
6508 #endif
6509  return pqa;
6510  }
6511  if (s4 == 0.0) {
6512  // b is collinear with pq. Case (3).
6513 #ifdef SELF_CHECK
6514  assert(s3 != 0.0);
6515 #endif
6516  pqb = edge_vert_col_inter(P, Q, B);
6517 #ifdef SELF_CHECK
6518  // This case should have been detected in above.
6519  assert(pqb != SHAREVERTEX);
6520  assert(pqb == INTERSECT || pqb == DISJOINT);
6521 #endif
6522  return pqb;
6523  }
6524 
6525  // ab and pq are intersecting properly.
6526  return INTERSECT;
6527 }
6528 
6530 // //
6531 // Notations //
6532 // //
6533 // Let ABC be the plane passes through a, b, and c; ABC+ be the halfspace //
6534 // including the set of all points x, such that orient3d(a, b, c, x) > 0; //
6535 // ABC- be the other halfspace, such that for each point x in ABC-, //
6536 // orient3d(a, b, c, x) < 0. For the set of x which are on ABC, orient3d(a, //
6537 // b, c, x) = 0. //
6538 // //
6540 
6542 // //
6543 // tri_vert_copl_inter() Test whether a triangle (abc) and a coplanar //
6544 // point (p) are intersecting or not. //
6545 // //
6546 // Possible cases are p is inside abc, or on an edge of, or coincident with //
6547 // a vertex of, or outside abc. //
6548 // //
6549 // A reference point R is required. R is exactly not coplanar with abc and p.//
6550 // Since the caller knows they are coplanar, it must be able to provide (or //
6551 // calculate) such a point. //
6552 // //
6553 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6554 // and INTERSECT. //
6555 // //
6557 
6558 enum tetgenmesh::interresult tetgenmesh::tri_vert_cop_inter(REAL* A, REAL* B,
6559  REAL* C, REAL* P, REAL* R)
6560 {
6561  REAL s1, s2, s3;
6562  int sign;
6563 
6564 #ifdef SELF_CHECK
6565  assert(R != (REAL *) NULL);
6566 #endif
6567  // Adjust the orientation of a, b, c and r, so that we can assume that
6568  // r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule).
6569  s1 = orient3d(A, B, C, R);
6570 #ifdef SELF_CHECK
6571  assert(s1 != 0.0);
6572 #endif
6573  sign = s1 < 0.0 ? 1 : -1;
6574 
6575  // Test starts from here.
6576  s1 = orient3d(A, B, R, P) * sign;
6577  if (s1 < 0.0) {
6578  // p is in ABR-.
6579  return DISJOINT;
6580  }
6581  s2 = orient3d(B, C, R, P) * sign;
6582  if (s2 < 0.0) {
6583  // p is in BCR-.
6584  return DISJOINT;
6585  }
6586  s3 = orient3d(C, A, R, P) * sign;
6587  if (s3 < 0.0) {
6588  // p is in CAR-.
6589  return DISJOINT;
6590  }
6591  if (s1 == 0.0) {
6592  // p is on ABR.
6593  if (s2 == 0.0) {
6594  // p is on BCR.
6595 #ifdef SELF_CHECK
6596  assert(s3 > 0.0);
6597 #endif
6598  // p is coincident with b.
6599  return SHAREVERTEX;
6600  }
6601  if (s3 == 0.0) {
6602  // p is on CAR.
6603  // p is coincident with a.
6604  return SHAREVERTEX;
6605  }
6606  // p is on edge ab.
6607  return INTERSECT;
6608  }
6609  // p is in ABR+.
6610  if (s2 == 0.0) {
6611  // p is on BCR.
6612  if (s3 == 0.0) {
6613  // p is on CAR.
6614  // p is coincident with c.
6615  return SHAREVERTEX;
6616  }
6617  // p is on edge bc.
6618  return INTERSECT;
6619  }
6620  if (s3 == 0.0) {
6621  // p is on CAR.
6622  // p is on edge ca.
6623  return INTERSECT;
6624  }
6625 
6626  // p is strictly inside abc.
6627  return INTERSECT;
6628 }
6629 
6631 // //
6632 // tri_edge_cop_inter() Test whether a triangle (abc) and a coplanar edge //
6633 // (pq) are intersecting or not. //
6634 // //
6635 // A reference point R is required. R is exactly not coplanar with abc and //
6636 // pq. Since the caller knows they are coplanar, it must be able to provide //
6637 // (or calculate) such a point. //
6638 // //
6639 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6640 // SHAREEDGE, and INTERSECT. //
6641 // //
6643 
6644 enum tetgenmesh::interresult tetgenmesh::tri_edge_cop_inter(REAL* A, REAL* B,
6645  REAL* C, REAL* P, REAL* Q, REAL* R)
6646 {
6647  enum interresult abpq, bcpq, capq;
6648  enum interresult abcp, abcq;
6649 
6650  // Test if pq is intersecting one of edges of abc.
6651  abpq = edge_edge_cop_inter(A, B, P, Q, R);
6652  if (abpq == INTERSECT || abpq == SHAREEDGE) {
6653  return abpq;
6654  }
6655  bcpq = edge_edge_cop_inter(B, C, P, Q, R);
6656  if (bcpq == INTERSECT || bcpq == SHAREEDGE) {
6657  return bcpq;
6658  }
6659  capq = edge_edge_cop_inter(C, A, P, Q, R);
6660  if (capq == INTERSECT || capq == SHAREEDGE) {
6661  return capq;
6662  }
6663 
6664  // Test if p and q is inside abc.
6665  abcp = tri_vert_cop_inter(A, B, C, P, R);
6666  if (abcp == INTERSECT) {
6667  return INTERSECT;
6668  }
6669  abcq = tri_vert_cop_inter(A, B, C, Q, R);
6670  if (abcq == INTERSECT) {
6671  return INTERSECT;
6672  }
6673 
6674  // Combine the test results of edge intersectings and triangle insides
6675  // to detect whether abc and pq are sharing vertex or disjointed.
6676  if (abpq == SHAREVERTEX) {
6677  // p or q is coincident with a or b.
6678 #ifdef SELF_CHECK
6679  assert(abcp ^ abcq);
6680 #endif
6681  return SHAREVERTEX;
6682  }
6683  if (bcpq == SHAREVERTEX) {
6684  // p or q is coincident with b or c.
6685 #ifdef SELF_CHECK
6686  assert(abcp ^ abcq);
6687 #endif
6688  return SHAREVERTEX;
6689  }
6690  if (capq == SHAREVERTEX) {
6691  // p or q is coincident with c or a.
6692 #ifdef SELF_CHECK
6693  assert(abcp ^ abcq);
6694 #endif
6695  return SHAREVERTEX;
6696  }
6697 
6698  // They are disjointed.
6699  return DISJOINT;
6700 }
6701 
6703 // //
6704 // tri_edge_inter_tail() Test whether a triangle (abc) and an edge (pq) //
6705 // are intersecting or not. //
6706 // //
6707 // s1 and s2 are results of pre-performed orientation tests. s1 = orient3d( //
6708 // a, b, c, p); s2 = orient3d(a, b, c, q). To separate this routine from //
6709 // tri_edge_inter() can save two orientation tests in tri_tri_inter(). //
6710 // //
6711 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6712 // SHAREEDGE, and INTERSECT. //
6713 // //
6715 
6716 enum tetgenmesh::interresult tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B,
6717  REAL* C, REAL* P, REAL* Q, REAL s1, REAL s2)
6718 {
6719  REAL s3, s4, s5;
6720  int sign;
6721 
6722  if (s1 * s2 > 0.0) {
6723  // p, q are at the same halfspace of ABC, no intersection.
6724  return DISJOINT;
6725  }
6726 
6727  if (s1 * s2 < 0.0) {
6728  // p, q are both not on ABC (and not sharing vertices, edges of abc).
6729  // Adjust the orientation of a, b, c and p, so that we can assume that
6730  // p is strictly in ABC-, and q is strictly in ABC+.
6731  sign = s1 < 0.0 ? 1 : -1;
6732  s3 = orient3d(A, B, P, Q) * sign;
6733  if (s3 < 0.0) {
6734  // q is at ABP-.
6735  return DISJOINT;
6736  }
6737  s4 = orient3d(B, C, P, Q) * sign;
6738  if (s4 < 0.0) {
6739  // q is at BCP-.
6740  return DISJOINT;
6741  }
6742  s5 = orient3d(C, A, P, Q) * sign;
6743  if (s5 < 0.0) {
6744  // q is at CAP-.
6745  return DISJOINT;
6746  }
6747  if (s3 == 0.0) {
6748  // q is on ABP.
6749  if (s4 == 0.0) {
6750  // q is on BCP (and q must in CAP+).
6751 #ifdef SELF_CHECK
6752  assert(s5 > 0.0);
6753 #endif
6754  // pq intersects abc at vertex b.
6755  return SHAREVERTEX;
6756  }
6757  if (s5 == 0.0) {
6758  // q is on CAP (and q must in BCP+).
6759  // pq intersects abc at vertex a.
6760  return SHAREVERTEX;
6761  }
6762  // q in both BCP+ and CAP+.
6763  // pq crosses ab properly.
6764  return INTERSECT;
6765  }
6766  // q is in ABP+;
6767  if (s4 == 0.0) {
6768  // q is on BCP.
6769  if (s5 == 0.0) {
6770  // q is on CAP.
6771  // pq intersects abc at vertex c.
6772  return SHAREVERTEX;
6773  }
6774  // pq crosses bc properly.
6775  return INTERSECT;
6776  }
6777  // q is in BCP+;
6778  if (s5 == 0.0) {
6779  // q is on CAP.
6780  // pq crosses ca properly.
6781  return INTERSECT;
6782  }
6783  // q is in CAP+;
6784  // pq crosses abc properly.
6785  return INTERSECT;
6786  }
6787 
6788  if (s1 != 0.0 || s2 != 0.0) {
6789  // Either p or q is coplanar with abc. ONLY one of them is possible.
6790  if (s1 == 0.0) {
6791  // p is coplanar with abc, q can be used as reference point.
6792 #ifdef SELF_CHECK
6793  assert(s2 != 0.0);
6794 #endif
6795  return tri_vert_cop_inter(A, B, C, P, Q);
6796  } else {
6797  // q is coplanar with abc, p can be used as reference point.
6798 #ifdef SELF_CHECK
6799  assert(s2 == 0.0);
6800 #endif
6801  return tri_vert_cop_inter(A, B, C, Q, P);
6802  }
6803  }
6804 
6805  // pq is coplanar with abc. Calculate a point which is exactly not
6806  // coplanar with a, b, and c.
6807  REAL R[3], N[3];
6808  REAL ax, ay, az, bx, by, bz;
6809 
6810  ax = A[0] - B[0];
6811  ay = A[1] - B[1];
6812  az = A[2] - B[2];
6813  bx = A[0] - C[0];
6814  by = A[1] - C[1];
6815  bz = A[2] - C[2];
6816  N[0] = ay * bz - by * az;
6817  N[1] = az * bx - bz * ax;
6818  N[2] = ax * by - bx * ay;
6819  // The normal should not be a zero vector (otherwise, abc are collinear).
6820 #ifdef SELF_CHECK
6821  assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0);
6822 #endif
6823  // The reference point R is lifted from A to the normal direction with
6824  // a distance d = average edge length of the triangle abc.
6825  R[0] = N[0] + A[0];
6826  R[1] = N[1] + A[1];
6827  R[2] = N[2] + A[2];
6828  // Becareful the case: if the non-zero component(s) in N is smaller than
6829  // the machine epsilon (i.e., 2^(-16) for double), R will exactly equal
6830  // to A due to the round-off error. Do check if it is.
6831  if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) {
6832  int i, j;
6833  for (i = 0; i < 3; i++) {
6834 #ifdef SELF_CHECK
6835  assert (R[i] == A[i]);
6836 #endif
6837  j = 2;
6838  do {
6839  if (N[i] > 0.0) {
6840  N[i] += (j * macheps);
6841  } else {
6842  N[i] -= (j * macheps);
6843  }
6844  R[i] = N[i] + A[i];
6845  j *= 2;
6846  } while (R[i] == A[i]);
6847  }
6848  }
6849 
6850  return tri_edge_cop_inter(A, B, C, P, Q, R);
6851 }
6852 
6854 // //
6855 // tri_edge_inter() Test whether a triangle (abc) and an edge (pq) are //
6856 // intersecting or not. //
6857 // //
6858 // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, //
6859 // SHAREEDGE, and INTERSECT. //
6860 // //
6862 
6863 enum tetgenmesh::interresult tetgenmesh::tri_edge_inter(REAL* A, REAL* B,
6864  REAL* C, REAL* P, REAL* Q)
6865 {
6866  REAL s1, s2;
6867 
6868  // Test the locations of p and q with respect to ABC.
6869  s1 = orient3d(A, B, C, P);
6870  s2 = orient3d(A, B, C, Q);
6871 
6872  return tri_edge_inter_tail(A, B, C, P, Q, s1, s2);
6873 }
6874 
6876 // //
6877 // tri_tri_inter() Test whether two triangle (abc) and (opq) are //
6878 // intersecting or not. //
6879 // //
6880 // The return value indicates one of the five cases: DISJOINT, SHAREVERTEX, //
6881 // SHAREEDGE, SHAREFACE, and INTERSECT. //
6882 // //
6884 
6885 enum tetgenmesh::interresult tetgenmesh::tri_tri_inter(REAL* A, REAL* B,
6886  REAL* C, REAL* O, REAL* P, REAL* Q)
6887 {
6888  REAL s_o, s_p, s_q;
6889  REAL s_a, s_b, s_c;
6890 
6891  s_o = orient3d(A, B, C, O);
6892  s_p = orient3d(A, B, C, P);
6893  s_q = orient3d(A, B, C, Q);
6894  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
6895  // o, p, q are all in the same halfspace of ABC.
6896  return DISJOINT;
6897  }
6898 
6899  s_a = orient3d(O, P, Q, A);
6900  s_b = orient3d(O, P, Q, B);
6901  s_c = orient3d(O, P, Q, C);
6902  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
6903  // a, b, c are all in the same halfspace of OPQ.
6904  return DISJOINT;
6905  }
6906 
6907  enum interresult abcop, abcpq, abcqo;
6908  int shareedge = 0;
6909 
6910  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
6911  if (abcop == INTERSECT) {
6912  return INTERSECT;
6913  } else if (abcop == SHAREEDGE) {
6914  shareedge++;
6915  }
6916  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
6917  if (abcpq == INTERSECT) {
6918  return INTERSECT;
6919  } else if (abcpq == SHAREEDGE) {
6920  shareedge++;
6921  }
6922  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
6923  if (abcqo == INTERSECT) {
6924  return INTERSECT;
6925  } else if (abcqo == SHAREEDGE) {
6926  shareedge++;
6927  }
6928  if (shareedge == 3) {
6929  // opq are coincident with abc.
6930  return SHAREFACE;
6931  }
6932 #ifdef SELF_CHECK
6933  // It is only possible either no share edge or one.
6934  assert(shareedge == 0 || shareedge == 1);
6935 #endif
6936 
6937  // Continue to detect whether opq and abc are intersecting or not.
6938  enum interresult opqab, opqbc, opqca;
6939 
6940  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
6941  if (opqab == INTERSECT) {
6942  return INTERSECT;
6943  }
6944  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
6945  if (opqbc == INTERSECT) {
6946  return INTERSECT;
6947  }
6948  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
6949  if (opqca == INTERSECT) {
6950  return INTERSECT;
6951  }
6952 
6953  // At this point, two triangles are not intersecting and not coincident.
6954  // They may be share an edge, or share a vertex, or disjoint.
6955  if (abcop == SHAREEDGE) {
6956 #ifdef SELF_CHECK
6957  assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX);
6958 #endif
6959  // op is coincident with an edge of abc.
6960  return SHAREEDGE;
6961  }
6962  if (abcpq == SHAREEDGE) {
6963 #ifdef SELF_CHECK
6964  assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX);
6965 #endif
6966  // pq is coincident with an edge of abc.
6967  return SHAREEDGE;
6968  }
6969  if (abcqo == SHAREEDGE) {
6970 #ifdef SELF_CHECK
6971  assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX);
6972 #endif
6973  // qo is coincident with an edge of abc.
6974  return SHAREEDGE;
6975  }
6976 
6977  // They may share a vertex or disjoint.
6978  if (abcop == SHAREVERTEX) {
6979  // o or p is coincident with a vertex of abc.
6980  if (abcpq == SHAREVERTEX) {
6981  // p is the coincident vertex.
6982 #ifdef SELF_CHECK
6983  assert(abcqo != SHAREVERTEX);
6984 #endif
6985  } else {
6986  // o is the coincident vertex.
6987 #ifdef SELF_CHECK
6988  assert(abcqo == SHAREVERTEX);
6989 #endif
6990  }
6991  return SHAREVERTEX;
6992  }
6993  if (abcpq == SHAREVERTEX) {
6994  // q is the coincident vertex.
6995 #ifdef SELF_CHECK
6996  assert(abcqo == SHAREVERTEX);
6997 #endif
6998  return SHAREVERTEX;
6999  }
7000 
7001  // They are disjoint.
7002  return DISJOINT;
7003 }
7004 
7006 // //
7007 // insphere_sos() Insphere test with symbolic perturbation. //
7008 // //
7009 // The input points a, b, c, and d should be non-coplanar. They must be ord- //
7010 // ered so that they have a positive orientation (as defined by orient3d()), //
7011 // or the sign of the result will be reversed. //
7012 // //
7013 // Return a positive value if the point e lies inside the circumsphere of a, //
7014 // b, c, and d; a negative value if it lies outside. //
7015 // //
7017 
7018 REAL tetgenmesh::insphere_sos(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
7019  int ia, int ib, int ic, int id, int ie)
7020 {
7021  REAL det;
7022 
7023  det = insphere(pa, pb, pc, pd, pe);
7024  if (det != 0.0) {
7025  return det;
7026  }
7027 
7028  // det = 0.0, use symbolic perturbation.
7029  REAL *p[5], *tmpp;
7030  REAL sign, det_c, det_d;
7031  int idx[5], perm, tmp;
7032  int n, i, j;
7033 
7034  p[0] = pa; idx[0] = ia;
7035  p[1] = pb; idx[1] = ib;
7036  p[2] = pc; idx[2] = ic;
7037  p[3] = pd; idx[3] = id;
7038  p[4] = pe; idx[4] = ie;
7039 
7040  // Bubble sort the points by the increasing order of the indices.
7041  n = 5;
7042  perm = 0; // The number of total swaps.
7043  for (i = 0; i < n - 1; i++) {
7044  for (j = 0; j < n - 1 - i; j++) {
7045  if (idx[j + 1] < idx[j]) { // compare the two neighbors.
7046  tmp = idx[j]; // swap idx[j] and idx[j + 1]
7047  idx[j] = idx[j + 1];
7048  idx[j + 1] = tmp;
7049  tmpp = p[j]; // swap p[j] and p[j + 1]
7050  p[j] = p[j + 1];
7051  p[j + 1] = tmpp;
7052  perm++;
7053  }
7054  }
7055  }
7056 
7057  sign = (perm % 2 == 0) ? 1.0 : -1.0;
7058  det_c = orient3d(p[1], p[2], p[3], p[4]); // orient3d(b, c, d, e)
7059  if (det_c != 0.0) {
7060  return sign * det_c;
7061  }
7062  det_d = orient3d(p[0], p[2], p[3], p[4]); // orient3d(a, c, d, e)
7063  return -sign * det_d;
7064 }
7065 
7067 // //
7068 // iscollinear() Check if three points are approximately collinear. //
7069 // //
7070 // 'eps' is a relative error tolerance. The collinearity is determined by //
7071 // the value q = cos(theta), where theta is the angle between two vectors //
7072 // A->B and A->C. They're collinear if 1.0 - q <= epspp. //
7073 // //
7075 
7076 bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps)
7077 {
7078  REAL abx, aby, abz;
7079  REAL acx, acy, acz;
7080  REAL Lv, Lw, dd;
7081  REAL d, q;
7082 
7083  // Limit of two closed points.
7084  q = longest * eps;
7085  q *= q;
7086 
7087  abx = A[0] - B[0];
7088  aby = A[1] - B[1];
7089  abz = A[2] - B[2];
7090  acx = A[0] - C[0];
7091  acy = A[1] - C[1];
7092  acz = A[2] - C[2];
7093  Lv = abx * abx + aby * aby + abz * abz;
7094  // Is AB (nearly) indentical?
7095  if (Lv < q) return true;
7096  Lw = acx * acx + acy * acy + acz * acz;
7097  // Is AC (nearly) indentical?
7098  if (Lw < q) return true;
7099  dd = abx * acx + aby * acy + abz * acz;
7100 
7101  d = (dd * dd) / (Lv * Lw);
7102  if (d > 1.0) d = 1.0; // Rounding.
7103  q = 1.0 - sqrt(d); // Notice 0 < q < 1.0.
7104 
7105  return q <= eps;
7106 }
7107 
7109 // //
7110 // iscoplanar() Check if four points are approximately coplanar. //
7111 // //
7112 // 'vol6' is six times of the signed volume of the tetrahedron formed by the //
7113 // four points. 'eps' is the relative error tolerance. The coplanarity is //
7114 // determined by the value: q = fabs(vol6) / L^3, where L is the average //
7115 // edge length of the tet. They're coplanar if q <= eps. //
7116 // //
7118 
7119 bool tetgenmesh::
7120 iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps)
7121 {
7122  REAL L, q;
7123  REAL x, y, z;
7124 
7125  if (vol6 == 0.0) return true;
7126 
7127  x = k[0] - l[0];
7128  y = k[1] - l[1];
7129  z = k[2] - l[2];
7130  L = sqrt(x * x + y * y + z * z);
7131  x = l[0] - m[0];
7132  y = l[1] - m[1];
7133  z = l[2] - m[2];
7134  L += sqrt(x * x + y * y + z * z);
7135  x = m[0] - k[0];
7136  y = m[1] - k[1];
7137  z = m[2] - k[2];
7138  L += sqrt(x * x + y * y + z * z);
7139  x = k[0] - n[0];
7140  y = k[1] - n[1];
7141  z = k[2] - n[2];
7142  L += sqrt(x * x + y * y + z * z);
7143  x = l[0] - n[0];
7144  y = l[1] - n[1];
7145  z = l[2] - n[2];
7146  L += sqrt(x * x + y * y + z * z);
7147  x = m[0] - n[0];
7148  y = m[1] - n[1];
7149  z = m[2] - n[2];
7150  L += sqrt(x * x + y * y + z * z);
7151 #ifdef SELF_CHECK
7152  assert(L > 0.0);
7153 #endif
7154  L /= 6.0;
7155  q = fabs(vol6) / (L * L * L);
7156 
7157  return q <= eps;
7158 }
7159 
7161 // //
7162 // iscospheric() Check if five points are approximately coplanar. //
7163 // //
7164 // 'vol24' is the 24 times of the signed volume of the 4-dimensional simplex //
7165 // formed by the five points. 'eps' is the relative tolerance. The cosphere //
7166 // case is determined by the value: q = fabs(vol24) / L^4, where L is the //
7167 // average edge length of the simplex. They're cosphere if q <= eps. //
7168 // //
7170 
7171 bool tetgenmesh::
7172 iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL vol24, REAL eps)
7173 {
7174  REAL L, q;
7175 
7176  // A 4D simplex has 10 edges.
7177  L = distance(k, l);
7178  L += distance(l, m);
7179  L += distance(m, k);
7180  L += distance(k, n);
7181  L += distance(l, n);
7182  L += distance(m, n);
7183  L += distance(k, o);
7184  L += distance(l, o);
7185  L += distance(m, o);
7186  L += distance(n, o);
7187 #ifdef SELF_CHECK
7188  assert(L > 0.0);
7189 #endif
7190  L /= 10.0;
7191  q = fabs(vol24) / (L * L * L * L);
7192 
7193  return q < eps;
7194 }
7195 
7196 //
7197 // End of geometric tests
7198 //
7199 
7200 //
7201 // Begin of Geometric quantities calculators
7202 //
7203 
7204 // distance() computs the Euclidean distance between two points.
7205 inline REAL tetgenmesh::distance(REAL* p1, REAL* p2)
7206 {
7207  return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) +
7208  (p2[1] - p1[1]) * (p2[1] - p1[1]) +
7209  (p2[2] - p1[2]) * (p2[2] - p1[2]));
7210 }
7211 
7213 // //
7214 // shortdistance() Returns the shortest distance from point p to a line //
7215 // defined by two points e1 and e2. //
7216 // //
7217 // First compute the projection length l_p of the vector v1 = p - e1 along //
7218 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
7219 // shortest distance. //
7220 // //
7221 // This routine allows that p is collinear with the line. In this case, the //
7222 // return value is zero. The two points e1 and e2 should not be identical. //
7223 // //
7225 
7226 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
7227 {
7228  REAL v1[3], v2[3];
7229  REAL len, l_p;
7230 
7231  v1[0] = e2[0] - e1[0];
7232  v1[1] = e2[1] - e1[1];
7233  v1[2] = e2[2] - e1[2];
7234  v2[0] = p[0] - e1[0];
7235  v2[1] = p[1] - e1[1];
7236  v2[2] = p[2] - e1[2];
7237 
7238  len = sqrt(dot(v1, v1));
7239 #ifdef SELF_CHECK
7240  assert(len != 0.0);
7241 #endif
7242  v1[0] /= len;
7243  v1[1] /= len;
7244  v1[2] /= len;
7245  l_p = dot(v1, v2);
7246 
7247  return sqrt(dot(v2, v2) - l_p * l_p);
7248 }
7249 
7251 // //
7252 // shortdistance() Returns the shortest distance from point p to a face. //
7253 // //
7255 
7256 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3)
7257 {
7258  REAL prj[3];
7259 
7260  projpt2face(p, e1, e2, e3, prj);
7261  return distance(p, prj);
7262 }
7263 
7265 // //
7266 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
7267 // o->p1 and o->p2. //
7268 // //
7269 // 'n' is the normal of the plane containing face (o, p1, p2). The interior //
7270 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
7271 // the position of p1 and p2 will get the complement angle of the other one. //
7272 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
7273 // 'n' be NULL if you only want the interior angle between 0 - PI. //
7274 // //
7276 
7277 REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
7278 {
7279  REAL v1[3], v2[3], np[3];
7280  REAL theta, costheta, lenlen;
7281  REAL ori, len1, len2;
7282 
7283  // Get the interior angle (0 - PI) between o->p1, and o->p2.
7284  v1[0] = p1[0] - o[0];
7285  v1[1] = p1[1] - o[1];
7286  v1[2] = p1[2] - o[2];
7287  v2[0] = p2[0] - o[0];
7288  v2[1] = p2[1] - o[1];
7289  v2[2] = p2[2] - o[2];
7290  len1 = sqrt(dot(v1, v1));
7291  len2 = sqrt(dot(v2, v2));
7292  lenlen = len1 * len2;
7293 #ifdef SELF_CHECK
7294  assert(lenlen != 0.0);
7295 #endif
7296  costheta = dot(v1, v2) / lenlen;
7297  if (costheta > 1.0) {
7298  costheta = 1.0; // Roundoff.
7299  } else if (costheta < -1.0) {
7300  costheta = -1.0; // Roundoff.
7301  }
7302  theta = acos(costheta);
7303  if (n != NULL) {
7304  // Get a point above the face (o, p1, p2);
7305  np[0] = o[0] + n[0];
7306  np[1] = o[1] + n[1];
7307  np[2] = o[2] + n[2];
7308  // Adjust theta (0 - 2 * PI).
7309  ori = orient3d(p1, o, np, p2);
7310  if (ori > 0.0) {
7311  theta = 2 * PI - theta;
7312  }
7313  }
7314 
7315  return theta;
7316 }
7317 
7319 // //
7320 // projpt2edge() Return the projection point from a point to an edge. //
7321 // //
7323 
7324 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
7325 {
7326  REAL v1[3], v2[3];
7327  REAL len, l_p;
7328 
7329  v1[0] = e2[0] - e1[0];
7330  v1[1] = e2[1] - e1[1];
7331  v1[2] = e2[2] - e1[2];
7332  v2[0] = p[0] - e1[0];
7333  v2[1] = p[1] - e1[1];
7334  v2[2] = p[2] - e1[2];
7335 
7336  len = sqrt(dot(v1, v1));
7337 #ifdef SELF_CHECK
7338  assert(len != 0.0);
7339 #endif
7340  v1[0] /= len;
7341  v1[1] /= len;
7342  v1[2] /= len;
7343  l_p = dot(v1, v2);
7344 
7345  prj[0] = e1[0] + l_p * v1[0];
7346  prj[1] = e1[1] + l_p * v1[1];
7347  prj[2] = e1[2] + l_p * v1[2];
7348 }
7349 
7351 // //
7352 // projpt2face() Return the projection point from a point to a face. //
7353 // //
7355 
7356 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
7357 {
7358  REAL fnormal[3], v1[3];
7359  REAL len, dist;
7360 
7361  // Get the unit face normal.
7362  facenormal(f1, f2, f3, fnormal, &len);
7363 #ifdef SELF_CHECK
7364  assert(len > 0.0);
7365 #endif
7366  fnormal[0] /= len;
7367  fnormal[1] /= len;
7368  fnormal[2] /= len;
7369  // Get the vector v1 = |p - f1|.
7370  v1[0] = p[0] - f1[0];
7371  v1[1] = p[1] - f1[1];
7372  v1[2] = p[2] - f1[2];
7373  // Get the project distance.
7374  dist = dot(fnormal, v1);
7375 
7376  // Get the project point.
7377  prj[0] = p[0] - dist * fnormal[0];
7378  prj[1] = p[1] - dist * fnormal[1];
7379  prj[2] = p[2] - dist * fnormal[2];
7380 }
7381 
7383 // //
7384 // facenormal() Calculate the normal of a face given by three points. //
7385 // //
7386 // In general, the face normal can be calculate by the cross product of any //
7387 // pair of the three edge vectors. However, if the three points are nearly //
7388 // collinear, the rounding error may harm the result. To choose a good pair //
7389 // of vectors is helpful to reduce the error. //
7390 // //
7392 
7393 void tetgenmesh::facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen)
7394 {
7395  REAL v1[3], v2[3];
7396 
7397  v1[0] = pb[0] - pa[0];
7398  v1[1] = pb[1] - pa[1];
7399  v1[2] = pb[2] - pa[2];
7400  v2[0] = pc[0] - pa[0];
7401  v2[1] = pc[1] - pa[1];
7402  v2[2] = pc[2] - pa[2];
7403 
7404  cross(v1, v2, n);
7405  if (nlen != (REAL *) NULL) {
7406  *nlen = sqrt(dot(n, n));
7407  }
7408 }
7409 
7411 // //
7412 // edgeorthonormal() Return the unit normal of an edge in a given plane. //
7413 // //
7414 // The edge is from e1 to e2, the plane is defined by given an additional //
7415 // point op, which is non-collinear with the edge. In addition, the side of //
7416 // the edge in which op lies defines the positive position of the normal. //
7417 // //
7418 // Let v1 be the unit vector from e1 to e2, v2 be the unit edge vector from //
7419 // e1 to op, fn be the unit face normal calculated by fn = v1 x v2. Then the //
7420 // unit edge normal of e1e2 pointing to op is n = fn x v1. Note, we should //
7421 // not change the position of fn and v1, otherwise, we get the edge normal //
7422 // pointing to the other side of op. //
7423 // //
7425 
7426 void tetgenmesh::edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n)
7427 {
7428  REAL v1[3], v2[3], fn[3];
7429  REAL len;
7430 
7431  // Get the edge vector v1.
7432  v1[0] = e2[0] - e1[0];
7433  v1[1] = e2[1] - e1[1];
7434  v1[2] = e2[2] - e1[2];
7435  // Get the edge vector v2.
7436  v2[0] = op[0] - e1[0];
7437  v2[1] = op[1] - e1[1];
7438  v2[2] = op[2] - e1[2];
7439  // Get the face normal fn = v1 x v2.
7440  cross(v1, v2, fn);
7441  // Get the edge normal n pointing to op. n = fn x v1.
7442  cross(fn, v1, n);
7443  // Normalize the vector.
7444  len = sqrt(dot(n, n));
7445  n[0] /= len;
7446  n[1] /= len;
7447  n[2] /= len;
7448 }
7449 
7451 // //
7452 // facedihedral() Return the dihedral angle (in radian) between two //
7453 // adjoining faces. //
7454 // //
7455 // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are //
7456 // apexes of these two faces. Return the angle (between 0 to 2*pi) between //
7457 // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). //
7458 // //
7460 
7461 REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
7462 {
7463  REAL n1[3], n2[3];
7464  REAL n1len, n2len;
7465  REAL costheta, ori;
7466  REAL theta;
7467 
7468  facenormal(pa, pb, pc1, n1, &n1len);
7469  facenormal(pa, pb, pc2, n2, &n2len);
7470  costheta = dot(n1, n2) / (n1len * n2len);
7471  // Be careful rounding error!
7472  if (costheta > 1.0) {
7473  costheta = 1.0;
7474  } else if (costheta < -1.0) {
7475  costheta = -1.0;
7476  }
7477  theta = acos(costheta);
7478  ori = orient3d(pa, pb, pc1, pc2);
7479  if (ori > 0.0) {
7480  theta = 2 * PI - theta;
7481  }
7482 
7483  return theta;
7484 }
7485 
7487 // //
7488 // tetalldihedral() Get all (six) dihedral angles of a tet. //
7489 // //
7490 // The tet is given by its four corners a, b, c, and d. If 'cosdd' is not //
7491 // NULL, it returns the cosines of the 6 dihedral angles, the corresponding //
7492 // edges are: ab, bc, ca, ad, bd, and cd. If 'cosmaxd' (or 'cosmind') is not //
7493 // NULL, it returns the cosine of the maximal (or minimal) dihedral angle. //
7494 // //
7496 
7497 void tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
7498  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
7499 {
7500  REAL N[4][3], cosd, len;
7501  int f1, f2, i, j;
7502 
7503  f1=0;
7504  f2=0;
7505 
7506  // Get four normals of faces of the tet.
7507  tetallnormal(pa, pb, pc, pd, N, NULL);
7508  // Normalize the normals.
7509  for (i = 0; i < 4; i++) {
7510  len = sqrt(dot(N[i], N[i]));
7511  if (len != 0.0) {
7512  for (j = 0; j < 3; j++) N[i][j] /= len;
7513  }
7514  }
7515 
7516  for (i = 0; i < 6; i++) {
7517  switch (i) {
7518  case 0: f1 = 2; f2 = 3; break; // edge ab.
7519  case 1: f1 = 0; f2 = 3; break; // edge bc.
7520  case 2: f1 = 1; f2 = 3; break; // edge ca.
7521  case 3: f1 = 1; f2 = 2; break; // edge ad.
7522  case 4: f1 = 2; f2 = 0; break; // edge bd.
7523  case 5: f1 = 0; f2 = 1; break; // edge cd.
7524  }
7525  cosd = -dot(N[f1], N[f2]);
7526  if (cosdd) cosdd[i] = cosd;
7527  if (i == 0) {
7528  if (cosmaxd) *cosmaxd = cosd;
7529  if (cosmind) *cosmind = cosd;
7530  } else {
7531  if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
7532  if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
7533  }
7534  }
7535 }
7536 
7538 // //
7539 // tetallnormal() Get the in-noramls of the four faces of a given tet. //
7540 // //
7541 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
7542 // N[1] acd, N[2] bad, N[3] abc. These normals are unnormalized. //
7543 // //
7545 
7546 void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
7547  REAL N[4][3], REAL* volume)
7548 {
7549  REAL A[4][4], rhs[4], D;
7550  int indx[4];
7551  int i, j;
7552 
7553  // get the entries of A[3][3].
7554  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
7555  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
7556  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
7557  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
7558  lu_decmp(A, 3, indx, &D, 0); // Decompose the matrix just once.
7559  if (volume != NULL) {
7560  // Get the volume of the tet.
7561  *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
7562  }
7563  for (j = 0; j < 3; j++) {
7564  for (i = 0; i < 3; i++) rhs[i] = 0.0;
7565  rhs[j] = 1.0; // Positive means the inside direction
7566  lu_solve(A, 3, indx, rhs, 0);
7567  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
7568  }
7569  // Get the fourth normal by summing up the first three.
7570  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
7571 }
7572 
7574 // //
7575 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
7576 // //
7577 // The aspect ratio of a tet is R/h, where R is the circumradius and h is //
7578 // the shortest height of the tet. //
7579 // //
7581 
7582 REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
7583 {
7584  REAL vda[3], vdb[3], vdc[3];
7585  REAL N[4][3], A[4][4], rhs[4], D;
7586  REAL H[4], volume, radius2, minheightinv;
7587  int indx[4];
7588  int i, j;
7589 
7590  // Set the matrix A = [vda, vdb, vdc]^T.
7591  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
7592  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
7593  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
7594  // Lu-decompose the matrix A.
7595  lu_decmp(A, 3, indx, &D, 0);
7596  // Get the volume of abcd.
7597  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
7598  // Check if it is zero.
7599  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
7600  // if (volume < 0.0) volume = -volume;
7601  // Check the radiu-edge ratio of the tet.
7602  rhs[0] = 0.5 * dot(vda, vda);
7603  rhs[1] = 0.5 * dot(vdb, vdb);
7604  rhs[2] = 0.5 * dot(vdc, vdc);
7605  lu_solve(A, 3, indx, rhs, 0);
7606  // Get the circumcenter.
7607  // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
7608  // Get the square of the circumradius.
7609  radius2 = dot(rhs, rhs);
7610 
7611  // Compute the 4 face normals (N[0], ..., N[3]).
7612  for (j = 0; j < 3; j++) {
7613  for (i = 0; i < 3; i++) rhs[i] = 0.0;
7614  rhs[j] = 1.0; // Positive means the inside direction
7615  lu_solve(A, 3, indx, rhs, 0);
7616  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
7617  }
7618  // Get the fourth normal by summing up the first three.
7619  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
7620  // Normalized the normals.
7621  for (i = 0; i < 4; i++) {
7622  // H[i] is the inverse of the height of its corresponding face.
7623  H[i] = sqrt(dot(N[i], N[i]));
7624  // if (H[i] > 0.0) {
7625  // for (j = 0; j < 3; j++) N[i][j] /= H[i];
7626  // }
7627  }
7628  // Get the radius of the inscribed sphere.
7629  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
7630  // Get the biggest H[i] (corresponding to the smallest height).
7631  minheightinv = H[0];
7632  for (i = 1; i < 3; i++) {
7633  if (H[i] > minheightinv) minheightinv = H[i];
7634  }
7635 
7636  return sqrt(radius2) * minheightinv;
7637 }
7638 
7640 // //
7641 // circumsphere() Calculate the smallest circumsphere (center and radius) //
7642 // of the given three or four points. //
7643 // //
7644 // The circumsphere of four points (a tetrahedron) is unique if they are not //
7645 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
7646 // the diametral sphere of the triangle if they are not degenerate. //
7647 // //
7648 // Return TRUE if the input points are not degenerate and the circumcenter //
7649 // and circumradius are returned in 'cent' and 'radius' respectively if they //
7650 // are not NULLs. Otherwise, return FALSE indicated the points are degenrate.//
7651 // //
7653 
7654 bool tetgenmesh::
7655 circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius)
7656 {
7657  REAL A[4][4], rhs[4], D;
7658  int indx[4];
7659 
7660  // Compute the coefficient matrix A (3x3).
7661  A[0][0] = pb[0] - pa[0];
7662  A[0][1] = pb[1] - pa[1];
7663  A[0][2] = pb[2] - pa[2];
7664  A[1][0] = pc[0] - pa[0];
7665  A[1][1] = pc[1] - pa[1];
7666  A[1][2] = pc[2] - pa[2];
7667  if (pd != NULL) {
7668  A[2][0] = pd[0] - pa[0];
7669  A[2][1] = pd[1] - pa[1];
7670  A[2][2] = pd[2] - pa[2];
7671  } else {
7672  cross(A[0], A[1], A[2]);
7673  }
7674 
7675  // Compute the right hand side vector b (3x1).
7676  rhs[0] = 0.5 * dot(A[0], A[0]);
7677  rhs[1] = 0.5 * dot(A[1], A[1]);
7678  if (pd != NULL) {
7679  rhs[2] = 0.5 * dot(A[2], A[2]);
7680  } else {
7681  rhs[2] = 0.0;
7682  }
7683 
7684  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
7685  // and backward and forward substitute..
7686  if (!lu_decmp(A, 3, indx, &D, 0)) {
7687  if (radius != (REAL *) NULL) *radius = 0.0;
7688  return false;
7689  }
7690  lu_solve(A, 3, indx, rhs, 0);
7691  if (cent != (REAL *) NULL) {
7692  cent[0] = pa[0] + rhs[0];
7693  cent[1] = pa[1] + rhs[1];
7694  cent[2] = pa[2] + rhs[2];
7695  }
7696  if (radius != (REAL *) NULL) {
7697  *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
7698  }
7699  return true;
7700 }
7701 
7703 // //
7704 // inscribedsphere() Compute the radius and center of the biggest //
7705 // inscribed sphere of a given tetrahedron. //
7706 // //
7707 // The tetrahedron is given by its four points, it must not be degenerate. //
7708 // The center and radius are returned in 'cent' and 'radius' respectively if //
7709 // they are not NULLs. //
7710 // //
7711 // Geometrical fact. For any simplex in d dimension, //
7712 // r/h1 + r/h2 + ... r/hn = 1 (n <= d + 1); //
7713 // where r is the radius of inscribed ball, and h is the height of each side //
7714 // of the simplex. The value of 'r/h' is just the barycenter coordinates of //
7715 // each vertex of the simplex. Therefore, we can compute the radius and //
7716 // center of the smallest inscribed ball as following equations: //
7717 // r = 1.0 / (1/h1 + 1/h2 + ... + 1/hn); (1) //
7718 // C = r/h1 * P1 + r/h2 * P2 + ... + r/hn * Pn; (2) //
7719 // where C is the vector of center, P1, P2, .. Pn are vectors of vertices. //
7720 // Here (2) contains n linear equations with n variables. (h, P) must be a //
7721 // pair, h is the height from P to its opposite face. //
7722 // //
7724 
7725 void tetgenmesh::inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
7726  REAL* cent, REAL* radius)
7727 {
7728  REAL N[4][3], H[4]; // Normals (colume vectors) and heights of each face.
7729  REAL rd;
7730  int i;
7731 
7732  // Get the all normals of the tet.
7733  tetallnormal(pa, pb, pc, pd, N, NULL);
7734  for (i = 0; i < 4; i++) {
7735  // H[i] is the inverse of height of its corresponding face.
7736  H[i] = sqrt(dot(N[i], N[i]));
7737  }
7738  // Compute the radius use eq. (1).
7739  rd = 1.0 / (H[0] + H[1] + H[2] + H[3]);
7740  if (radius != (REAL*) NULL) *radius = rd;
7741  if (cent != (REAL*) NULL) {
7742  // Compute the center use eq. (2).
7743  cent[0] = rd * (H[0] * pa[0] + H[1] * pb[0] + H[2] * pc[0] + H[3] * pd[0]);
7744  cent[1] = rd * (H[0] * pa[1] + H[1] * pb[1] + H[2] * pc[1] + H[3] * pd[1]);
7745  cent[2] = rd * (H[0] * pa[2] + H[1] * pb[2] + H[2] * pc[2] + H[3] * pd[2]);
7746  }
7747 }
7748 
7750 // //
7751 // rotatepoint() Create a point by rotating an existing point. //
7752 // //
7753 // Create a 3D point by rotating point 'p' with an angle 'rotangle' (in arc //
7754 // degree) around a rotating axis given by a vector from point 'p1' to 'p2'. //
7755 // The rotation is according with right-hand rule, i.e., use your right-hand //
7756 // to grab the axis with your thumber pointing to its positive direction, //
7757 // your fingers indicate the rotating direction. //
7758 // //
7759 // The rotating steps are the following: //
7760 // 1. Translate vector 'p1->p2' to origin, M1; //
7761 // 2. Rotate vector around the Y-axis until it lies in the YZ plane, M2; //
7762 // 3. Rotate vector around the X-axis until it lies on the Z axis, M3; //
7763 // 4. Perform the rotation of 'p' around the z-axis, M4; //
7764 // 5. Undo Step 3, M5; //
7765 // 6. Undo Step 2, M6; //
7766 // 7. Undo Step 1, M7; //
7767 // Use matrix multiplication to combine the above sequences, we get: //
7768 // p0' = T * p0, where T = M7 * M6 * M5 * M4 * M3 * M2 * M1 //
7769 // //
7771 
7772 void tetgenmesh::rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2)
7773 {
7774  REAL T[4][4], pp0[4], p0t[4], p2t[4];
7775  REAL roty, rotx, alphaR, projlen;
7776  REAL dx, dy, dz;
7777 
7778  initm44(1, 0, 0, -p1[0],
7779  0, 1, 0, -p1[1],
7780  0, 0, 1, -p1[2],
7781  0, 0, 0, 1, T);
7782  pp0[0] = p[0]; pp0[1] = p[1]; pp0[2] = p[2]; pp0[3] = 1.0;
7783  m4xv4(p0t, T, pp0); // Step 1
7784  pp0[0] = p2[0]; pp0[1] = p2[1]; pp0[2] = p2[2]; pp0[3] = 1.0;
7785  m4xv4(p2t, T, pp0); // Step 1
7786 
7787  // Get the rotation angle around y-axis;
7788  dx = p2t[0];
7789  dz = p2t[2];
7790  projlen = sqrt(dx * dx + dz * dz);
7791  if (projlen <= (b->epsilon * 1e-2) * longest) {
7792  roty = 0;
7793  } else {
7794  roty = acos(dz / projlen);
7795  if (dx < 0) {
7796  roty = -roty;
7797  }
7798  }
7799 
7800  initm44(cos(-roty), 0, sin(-roty), 0,
7801  0, 1, 0, 0,
7802  -sin(-roty), 0, cos(-roty), 0,
7803  0, 0, 0, 1, T);
7804  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7805  m4xv4(p0t, T, pp0); // Step 2
7806  pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0;
7807  m4xv4(p2t, T, pp0); // Step 2
7808 
7809  // Get the rotation angle around x-axis
7810  dy = p2t[1];
7811  dz = p2t[2];
7812  projlen = sqrt(dy * dy + dz * dz);
7813  if (projlen <= (b->epsilon * 1e-2) * longest) {
7814  rotx = 0;
7815  } else {
7816  rotx = acos(dz / projlen);
7817  if (dy < 0) {
7818  rotx = -rotx;
7819  }
7820  }
7821 
7822  initm44(1, 0, 0, 0,
7823  0, cos(rotx), -sin(rotx), 0,
7824  0, sin(rotx), cos(rotx), 0,
7825  0, 0, 0, 1, T);
7826  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7827  m4xv4(p0t, T, pp0); // Step 3
7828  // pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0;
7829  // m4xv4(p2t, T, pp0); // Step 3
7830 
7831  alphaR = rotangle;
7832  initm44(cos(alphaR), -sin(alphaR), 0, 0,
7833  sin(alphaR), cos(alphaR), 0, 0,
7834  0, 0, 1, 0,
7835  0, 0, 0, 1, T);
7836  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7837  m4xv4(p0t, T, pp0); // Step 4
7838 
7839  initm44(1, 0, 0, 0,
7840  0, cos(-rotx), -sin(-rotx), 0,
7841  0, sin(-rotx), cos(-rotx), 0,
7842  0, 0, 0, 1, T);
7843  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7844  m4xv4(p0t, T, pp0); // Step 5
7845 
7846  initm44(cos(roty), 0, sin(roty), 0,
7847  0, 1, 0, 0,
7848  -sin(roty), 0, cos(roty), 0,
7849  0, 0, 0, 1, T);
7850  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7851  m4xv4(p0t, T, pp0); // Step 6
7852 
7853  initm44(1, 0, 0, p1[0],
7854  0, 1, 0, p1[1],
7855  0, 0, 1, p1[2],
7856  0, 0, 0, 1, T);
7857  pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0;
7858  m4xv4(p0t, T, pp0); // Step 7
7859 
7860  p[0] = p0t[0];
7861  p[1] = p0t[1];
7862  p[2] = p0t[2];
7863 }
7864 
7866 // //
7867 // spherelineint() 3D line sphere (or circle) intersection. //
7868 // //
7869 // The line is given by two points p1, and p2, the sphere is centered at c //
7870 // with radius r. This function returns a pointer array p which first index //
7871 // indicates the number of intersection point, followed by coordinate pairs. //
7872 // //
7873 // The following code are adapted from: http://astronomy.swin.edu.au/pbourke //
7874 // /geometry/sphereline. Paul Bourke pbourke@swin.edu.au //
7875 // //
7877 
7878 void tetgenmesh::spherelineint(REAL* p1, REAL* p2, REAL* C, REAL R, REAL p[7])
7879 {
7880  REAL x1, y1, z1; // P1 coordinates (point of line)
7881  REAL x2, y2, z2; // P2 coordinates (point of line)
7882  REAL x3, y3, z3, r; // P3 coordinates and radius (sphere)
7883  REAL a, b, c, mu, i ;
7884 
7885  x1 = p1[0]; y1 = p1[1]; z1 = p1[2];
7886  x2 = p2[0]; y2 = p2[1]; z2 = p2[2];
7887  x3 = C[0]; y3 = C[1]; z3 = C[2];
7888  r = R;
7889 
7890  a = (x2 - x1) * (x2 - x1)
7891  + (y2 - y1) * (y2 - y1)
7892  + (z2 - z1) * (z2 - z1);
7893  b = 2 * ( (x2 - x1) * (x1 - x3)
7894  + (y2 - y1) * (y1 - y3)
7895  + (z2 - z1) * (z1 - z3) ) ;
7896  c = (x3 * x3) + (y3 * y3) + (z3 * z3)
7897  + (x1 * x1) + (y1 * y1) + (z1 * z1)
7898  - 2 * (x3 * x1 + y3 * y1 + z3 * z1) - (r * r) ;
7899  i = b * b - 4 * a * c ;
7900 
7901  if (i < 0.0) {
7902  // no intersection
7903  p[0] = 0.0;
7904  } else if (i == 0.0) {
7905  // one intersection
7906  p[0] = 1.0;
7907  mu = -b / (2 * a) ;
7908  p[1] = x1 + mu * (x2 - x1);
7909  p[2] = y1 + mu * (y2 - y1);
7910  p[3] = z1 + mu * (z2 - z1);
7911  } else {
7912  // two intersections
7913  p[0] = 2.0;
7914  // first intersection
7915  mu = (-b + sqrt((b * b) - 4 * a * c)) / (2 * a);
7916  p[1] = x1 + mu * (x2 - x1);
7917  p[2] = y1 + mu * (y2 - y1);
7918  p[3] = z1 + mu * (z2 - z1);
7919  // second intersection
7920  mu = (-b - sqrt((b * b) - 4 * a * c)) / (2 * a);
7921  p[4] = x1 + mu * (x2 - x1);
7922  p[5] = y1 + mu * (y2 - y1);
7923  p[6] = z1 + mu * (z2 - z1);
7924  }
7925 }
7926 
7928 // //
7929 // linelineint() Calculate the shortest line between two lines in 3D. //
7930 // //
7931 // Two 3D lines generally don't intersect at a point, they may be parallel ( //
7932 // no intersections), or coincident (infinite intersections) but most often //
7933 // only their projections onto a plane intersect. If they don't exactly int- //
7934 // ersect at a point they can be connected by a line segment, the shortest //
7935 // segment is unique and is often considered to be their intersection in 3D. //
7936 // //
7937 // The following code are adapted from: http://astronomy.swin.edu.au/pbourke //
7938 // /geometry/lineline3d. Paul Bourke pbourke@swin.edu.au //
7939 // //
7940 // Calculate the line segment PaPb that is the shortest route between two //
7941 // lines P1P2 and P3P4. This function returns a pointer array p which first //
7942 // index indicates there exists solution or not, 0 means no solution, 1 meas //
7943 // has solution followed by two coordinate pairs. //
7944 // //
7946 
7947 void tetgenmesh::linelineint(REAL *p1,REAL *p2, REAL *p3, REAL *p4, REAL p[7])
7948 {
7949  REAL p13[3], p43[3], p21[3];
7950  REAL d1343, d4321, d1321, d4343, d2121;
7951  REAL numer, denom;
7952  REAL mua, mub;
7953 
7954  p13[0] = p1[0] - p3[0];
7955  p13[1] = p1[1] - p3[1];
7956  p13[2] = p1[2] - p3[2];
7957  p43[0] = p4[0] - p3[0];
7958  p43[1] = p4[1] - p3[1];
7959  p43[2] = p4[2] - p3[2];
7960  if (p43[0] == 0.0 && p43[1] == 0.0 && p43[2] == 0.0) {
7961  p[0] = 0.0;
7962  return;
7963  }
7964 
7965  p21[0] = p2[0] - p1[0];
7966  p21[1] = p2[1] - p1[1];
7967  p21[2] = p2[2] - p1[2];
7968  if (p21[0] == 0.0 && p21[1] == 0.0 && p21[2] == 0.0) {
7969  p[0] = 0.0;
7970  return;
7971  }
7972 
7973  d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2];
7974  d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2];
7975  d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2];
7976  d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2];
7977  d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2];
7978 
7979  denom = d2121 * d4343 - d4321 * d4321;
7980  if (denom == 0.0) {
7981  p[0] = 0.0;
7982  return;
7983  }
7984  numer = d1343 * d4321 - d1321 * d4343;
7985  mua = numer / denom;
7986  mub = (d1343 + d4321 * mua) / d4343;
7987 
7988  p[0] = 1.0;
7989  p[1] = p1[0] + mua * p21[0];
7990  p[2] = p1[1] + mua * p21[1];
7991  p[3] = p1[2] + mua * p21[2];
7992  p[4] = p3[0] + mub * p43[0];
7993  p[5] = p3[1] + mub * p43[1];
7994  p[6] = p3[2] + mub * p43[2];
7995 }
7996 
7998 // //
7999 // planelineint() Calculate the intersection of a line and a plane. //
8000 // //
8001 // The equation of a plane (points P are on the plane with normal N and P3 //
8002 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
8003 // line (points P on the line passing through P1 and P2) can be written as: //
8004 // P = P1 + u (P2 - P1). The intersection of these two occurs when: //
8005 // N dot (P1 + u (P2 - P1)) = N dot P3. //
8006 // Solving for u gives: //
8007 // N dot (P3 - P1) //
8008 // u = ------------------. //
8009 // N dot (P2 - P1) //
8010 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
8011 // to the line. Thus the line is either parallel to the plane and there are //
8012 // no solutions or the line is on the plane in which case there are an infi- //
8013 // nite number of solutions. //
8014 // //
8015 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
8016 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
8017 // //
8019 
8020 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
8021  REAL* ip, REAL* u)
8022 {
8023  REAL n[3], det, det1;
8024 
8025  // Calculate N.
8026  facenormal(pa, pb, pc, n, NULL);
8027  // Calculate N dot (e2 - e1).
8028  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
8029  + n[2] * (e2[2] - e1[2]);
8030  if (det != 0.0) {
8031  // Calculate N dot (pa - e1)
8032  det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
8033  + n[2] * (pa[2] - e1[2]);
8034  *u = det1 / det;
8035  ip[0] = e1[0] + *u * (e2[0] - e1[0]);
8036  ip[1] = e1[1] + *u * (e2[1] - e1[1]);
8037  ip[2] = e1[2] + *u * (e2[2] - e1[2]);
8038  } else {
8039  *u = 0.0;
8040  }
8041 }
8042 
8043 //
8044 // End of Geometric quantities calculators
8045 //
8046 
8047 //
8048 // Begin of memory management routines
8049 //
8050 
8052 // //
8053 // dummyinit() Initialize the tetrahedron that fills "outer space" and //
8054 // the omnipresent subface. //
8055 // //
8056 // The tetrahedron that fills "outer space" called 'dummytet', is pointed to //
8057 // by every tetrahedron and subface on a boundary (be it outer or inner) of //
8058 // the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron //
8059 // on the convex hull(until the holes and concavities are carved), making it //
8060 // possible to find a starting tetrahedron for point location. //
8061 // //
8062 // The omnipresent subface,'dummysh', is pointed to by every tetrahedron or //
8063 // subface that doesn't have a full complement of real subface to point to. //
8064 // //
8066 
8067 void tetgenmesh::dummyinit(int tetwords, int shwords)
8068 {
8069  unsigned long alignptr;
8070 
8071  // Set up 'dummytet', the 'tetrahedron' that occupies "outer space".
8072  dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron)
8073  + tetrahedrons->alignbytes];
8074  // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary.
8075  alignptr = (unsigned long) dummytetbase;
8076  dummytet = (tetrahedron *)
8077  (alignptr + (unsigned long) tetrahedrons->alignbytes
8078  - (alignptr % (unsigned long) tetrahedrons->alignbytes));
8079  // Initialize the four adjoining tetrahedra to be "outer space". These
8080  // will eventually be changed by various bonding operations, but their
8081  // values don't really matter, as long as they can legally be
8082  // dereferenced.
8083  dummytet[0] = (tetrahedron) dummytet;
8084  dummytet[1] = (tetrahedron) dummytet;
8085  dummytet[2] = (tetrahedron) dummytet;
8086  dummytet[3] = (tetrahedron) dummytet;
8087  // Four null vertex points.
8088  dummytet[4] = (tetrahedron) NULL;
8089  dummytet[5] = (tetrahedron) NULL;
8090  dummytet[6] = (tetrahedron) NULL;
8091  dummytet[7] = (tetrahedron) NULL;
8092 
8093  if (b->useshelles) {
8094  // Set up 'dummysh', the omnipresent "subface" pointed to by any
8095  // tetrahedron side or subface end that isn't attached to a real
8096  // subface.
8097  dummyshbase = (shellface *) new char[shwords * sizeof(shellface)
8098  + subfaces->alignbytes];
8099  // Align 'dummysh' on a 'subfaces->alignbytes'-byte boundary.
8100  alignptr = (unsigned long) dummyshbase;
8101  dummysh = (shellface *)
8102  (alignptr + (unsigned long) subfaces->alignbytes
8103  - (alignptr % (unsigned long) subfaces->alignbytes));
8104  // Initialize the three adjoining subfaces to be the omnipresent
8105  // subface. These will eventually be changed by various bonding
8106  // operations, but their values don't really matter, as long as they
8107  // can legally be dereferenced.
8108  dummysh[0] = (shellface) dummysh;
8109  dummysh[1] = (shellface) dummysh;
8110  dummysh[2] = (shellface) dummysh;
8111  // Three null vertex points.
8112  dummysh[3] = (shellface) NULL;
8113  dummysh[4] = (shellface) NULL;
8114  dummysh[5] = (shellface) NULL;
8115  // Initialize the two adjoining tetrahedra to be "outer space".
8116  dummysh[6] = (shellface) dummytet;
8117  dummysh[7] = (shellface) dummytet;
8118  // Initialize the three adjoining subsegments to be "out boundary".
8119  dummysh[8] = (shellface) dummysh;
8120  dummysh[9] = (shellface) dummysh;
8121  dummysh[10] = (shellface) dummysh;
8122  // Initialize the pointer to badface structure.
8123  dummysh[11] = (shellface) NULL;
8124  // Initialize the four adjoining subfaces of 'dummytet' to be the
8125  // omnipresent subface.
8126  dummytet[8 ] = (tetrahedron) dummysh;
8127  dummytet[9 ] = (tetrahedron) dummysh;
8128  dummytet[10] = (tetrahedron) dummysh;
8129  dummytet[11] = (tetrahedron) dummysh;
8130  }
8131 }
8132 
8134 // //
8135 // initializepools() Calculate the sizes of the point, tetrahedron, and //
8136 // subface. Initialize their memory pools. //
8137 // //
8138 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
8139 // and 'point2pbcptindex' used to find values within each point; computes //
8140 // indices 'highorderindex', 'elemattribindex', and 'volumeboundindex' used //
8141 // to find values within each tetrahedron. //
8142 // //
8143 // There are two types of boundary elements, which are subfaces and subsegs, //
8144 // they are stored in seperate pools. However, the data structures of them //
8145 // are the same. A subsegment can be regarded as a degenerate subface, i.e.,//
8146 // one of its three corners is not used. We set the apex of it be 'NULL' to //
8147 // distinguish it's a subsegment. //
8148 // //
8150 
8151 void tetgenmesh::initializepools()
8152 {
8153  enum wordtype wtype;
8154  int pointsize, elesize, shsize;
8155 
8156  // Default checkpbc = 0;
8157  if ((b->plc || b->refine) && (in->pbcgrouplist != NULL)) {
8158  checkpbcs = 1;
8159  }
8160  // Default varconstraint = 0;
8161  if (in->segmentconstraintlist || in->facetconstraintlist) {
8162  varconstraint = 1;
8163  }
8164 
8165  // The index within each point at which its metric tensor is found. It is
8166  // saved directly after the list of point attributes.
8167  pointmtrindex = 3 + in->numberofpointattributes;
8168  // Decide the size (1, 3, or 6) of the metric tensor.
8169  if (b->metric) {
8170  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
8171  if (bgm != (tetgenmesh *) NULL) {
8172  // A background mesh is allocated. It may not exist though.
8173  sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
8174  bgm->in->numberofpointmtrs : in->numberofpointmtrs;
8175  } else {
8176  // No given background mesh - Itself is a background mesh.
8177  sizeoftensor = in->numberofpointmtrs;
8178  }
8179  // Make sure sizeoftensor is at least 1.
8180  sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
8181  } else {
8182  // For '-q' option. Make sure to have space for saving a scalar value.
8183  sizeoftensor = b->quality ? 1 : 0;
8184  }
8185  // The index within each point at which an element pointer is found, where
8186  // the index is measured in pointers. Ensure the index is aligned to a
8187  // sizeof(tetrahedron)-byte address.
8188  point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
8189  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
8190  if (b->plc || b->refine) {
8191  // Increase the point size by three pointers, which are:
8192  // - a pointer to a tet, read by point2tet();
8193  // - a pointer to a subface/subsegment , read by point2sh();
8194  // - a pointer to a parent point, read by point2ppt()).
8195  if (b->metric) {
8196  // Increase one pointer to a tet of the background mesh.
8197  pointsize = (point2simindex + 4) * sizeof(tetrahedron);
8198  } else {
8199  pointsize = (point2simindex + 3) * sizeof(tetrahedron);
8200  }
8201  // The index within each point at which a pbc point is found.
8202  point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1)
8203  / sizeof(tetrahedron);
8204  if (checkpbcs) {
8205  // Increase the size by one pointer to a corresponding pbc point,
8206  // read by point2pbcpt().
8207  pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron);
8208  }
8209  } else {
8210  pointsize = point2simindex * sizeof(tetrahedron);
8211  }
8212  // The index within each point at which the boundary marker is found,
8213  // Ensure the point marker is aligned to a sizeof(int)-byte address.
8214  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
8215  // Now point size is the ints (inidcated by pointmarkindex) plus:
8216  // - an integer for boundary marker;
8217  // - an integer for vertex type;
8218  pointsize = (pointmarkindex + 2) * sizeof(int);
8219  // Decide the wordtype used in vertex pool.
8220  wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER;
8221  // Initialize the pool of vertices.
8222  points = new memorypool(pointsize, VERPERBLOCK, wtype, 0);
8223 
8224  // The number of bytes occupied by a tetrahedron. There are four pointers
8225  // to other tetrahedra, four pointers to corners, and possibly four
8226  // pointers to subfaces.
8227  elesize = (8 + b->useshelles * 6) * sizeof(tetrahedron);
8228  // If Voronoi diagram is wanted, make sure we have additional space.
8229  if (b->voroout && (b->useshelles == 0)) {
8230  elesize = (8 + 4) * sizeof(tetrahedron);
8231  }
8232  // The index within each element at which its attributes are found, where
8233  // the index is measured in REALs.
8234  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
8235  // The index within each element at which the maximum voulme bound is
8236  // found, where the index is measured in REALs. Note that if the
8237  // `b->regionattrib' flag is set, an additional attribute will be added.
8238  volumeboundindex = elemattribindex + in->numberoftetrahedronattributes
8239  + (b->regionattrib > 0);
8240  // If element attributes or an constraint are needed, increase the number
8241  // of bytes occupied by an element.
8242  if (b->varvolume) {
8243  elesize = (volumeboundindex + 1) * sizeof(REAL);
8244  } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) {
8245  elesize = volumeboundindex * sizeof(REAL);
8246  }
8247  // If element neighbor graph is requested (-n switch), an additional
8248  // integer is allocated for each element.
8249  elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int);
8250  if (b->neighout || b->voroout) {
8251  elesize = (elemmarkerindex + 1) * sizeof(int);
8252  }
8253  // If -o2 switch is used, an additional pointer pointed to the list of
8254  // higher order nodes is allocated for each element.
8255  highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
8256  if (b->order == 2) {
8257  elesize = (highorderindex + 1) * sizeof(tetrahedron);
8258  }
8259  // Having determined the memory size of an element, initialize the pool.
8260  tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8);
8261 
8262  if (b->useshelles) {
8263  // The number of bytes occupied by a subface. The list of pointers
8264  // stored in a subface are: three to other subfaces, three to corners,
8265  // three to subsegments, two to tetrahedra, and one to a badface.
8266  shsize = 12 * sizeof(shellface);
8267  // The index within each subface at which the maximum area bound is
8268  // found, where the index is measured in REALs.
8269  areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
8270  // If -q switch is in use, increase the number of bytes occupied by
8271  // a subface for saving maximum area bound.
8272  if (b->quality && varconstraint) {
8273  shsize = (areaboundindex + 1) * sizeof(REAL);
8274  } else {
8275  shsize = areaboundindex * sizeof(REAL);
8276  }
8277  // The index within subface at which the facet marker is found. Ensure
8278  // the marker is aligned to a sizeof(int)-byte address.
8279  shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
8280  // Increase the number of bytes by two or three integers, one for facet
8281  // marker, one for shellface type, and optionally one for pbc group.
8282  shsize = (shmarkindex + 2 + checkpbcs) * sizeof(int);
8283  // Initialize the pool of subfaces. Each subface record is eight-byte
8284  // aligned so it has room to store an edge version (from 0 to 5) in
8285  // the least three bits.
8286  subfaces = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
8287  // Initialize the pool of subsegments. The subsegment's record is same
8288  // with subface.
8289  subsegs = new memorypool(shsize, SUBPERBLOCK, POINTER, 8);
8290  // Initialize the "outer space" tetrahedron and omnipresent subface.
8291  dummyinit(tetrahedrons->itemwords, subfaces->itemwords);
8292  } else {
8293  // Initialize the "outer space" tetrahedron.
8294  dummyinit(tetrahedrons->itemwords, 0);
8295  }
8296 }
8297 
8299 // //
8300 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
8301 // //
8303 
8304 void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
8305 {
8306  // Set tetrahedron's vertices to NULL. This makes it possible to detect
8307  // dead tetrahedra when traversing the list of all tetrahedra.
8308  dyingtetrahedron[4] = (tetrahedron) NULL;
8309  dyingtetrahedron[5] = (tetrahedron) NULL;
8310  dyingtetrahedron[6] = (tetrahedron) NULL;
8311  dyingtetrahedron[7] = (tetrahedron) NULL;
8312  tetrahedrons->dealloc((void *) dyingtetrahedron);
8313 }
8314 
8316 // //
8317 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
8318 // //
8320 
8321 tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
8322 {
8323  tetrahedron *newtetrahedron;
8324 
8325  do {
8326  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
8327  if (newtetrahedron == (tetrahedron *) NULL) {
8328  return (tetrahedron *) NULL;
8329  }
8330  } while (newtetrahedron[7] == (tetrahedron) NULL); // Skip dead ones.
8331  return newtetrahedron;
8332 }
8333 
8335 // //
8336 // shellfacedealloc() Deallocate space for a shellface, marking it dead. //
8337 // Used both for dealloc a subface and subsegment. //
8338 // //
8340 
8341 void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
8342 {
8343  // Set shellface's vertices to NULL. This makes it possible to detect dead
8344  // shellfaces when traversing the list of all shellfaces.
8345  dyingsh[3] = (shellface) NULL;
8346  dyingsh[4] = (shellface) NULL;
8347  dyingsh[5] = (shellface) NULL;
8348  pool->dealloc((void *) dyingsh);
8349 }
8350 
8352 // //
8353 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
8354 // for both subfaces and subsegments pool traverse. //
8355 // //
8357 
8358 tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
8359 {
8360  shellface *newshellface;
8361 
8362  do {
8363  newshellface = (shellface *) pool->traverse();
8364  if (newshellface == (shellface *) NULL) {
8365  return (shellface *) NULL;
8366  }
8367  } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
8368  return newshellface;
8369 }
8370 
8372 // //
8373 // badfacedealloc() Deallocate space for a badface, marking it dead. //
8374 // //
8376 
8377 void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying)
8378 {
8379  // Set badface's forg to NULL. This makes it possible to detect dead
8380  // ones when traversing the list of all items.
8381  dying->forg = (point) NULL;
8382  pool->dealloc((void *) dying);
8383 }
8384 
8386 // //
8387 // badfacetraverse() Traverse the pools, skipping dead ones. //
8388 // //
8390 
8391 tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool)
8392 {
8393  badface *newsh;
8394 
8395  do {
8396  newsh = (badface *) pool->traverse();
8397  if (newsh == (badface *) NULL) {
8398  return (badface *) NULL;
8399  }
8400  } while (newsh->forg == (point) NULL); // Skip dead ones.
8401  return newsh;
8402 }
8403 
8405 // //
8406 // pointdealloc() Deallocate space for a point, marking it dead. //
8407 // //
8409 
8410 void tetgenmesh::pointdealloc(point dyingpoint)
8411 {
8412  // Mark the point as dead. This makes it possible to detect dead points
8413  // when traversing the list of all points.
8414  setpointtype(dyingpoint, DEADVERTEX);
8415  points->dealloc((void *) dyingpoint);
8416 }
8417 
8419 // //
8420 // pointtraverse() Traverse the points, skipping dead ones. //
8421 // //
8423 
8424 tetgenmesh::point tetgenmesh::pointtraverse()
8425 {
8426  point newpoint;
8427 
8428  do {
8429  newpoint = (point) points->traverse();
8430  if (newpoint == (point) NULL) {
8431  return (point) NULL;
8432  }
8433  } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
8434  return newpoint;
8435 }
8436 
8438 // //
8439 // maketetrahedron() Create a new tetrahedron. //
8440 // //
8442 
8443 void tetgenmesh::maketetrahedron(triface *newtet)
8444 {
8445  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
8446  // Initialize the four adjoining tetrahedra to be "outer space".
8447  newtet->tet[0] = (tetrahedron) dummytet;
8448  newtet->tet[1] = (tetrahedron) dummytet;
8449  newtet->tet[2] = (tetrahedron) dummytet;
8450  newtet->tet[3] = (tetrahedron) dummytet;
8451  // Four NULL vertices.
8452  newtet->tet[4] = (tetrahedron) NULL;
8453  newtet->tet[5] = (tetrahedron) NULL;
8454  newtet->tet[6] = (tetrahedron) NULL;
8455  newtet->tet[7] = (tetrahedron) NULL;
8456  // Initialize the four adjoining subfaces to be the omnipresent subface.
8457  if (b->useshelles) {
8458  newtet->tet[8 ] = (tetrahedron) dummysh;
8459  newtet->tet[9 ] = (tetrahedron) dummysh;
8460  newtet->tet[10] = (tetrahedron) dummysh;
8461  newtet->tet[11] = (tetrahedron) dummysh;
8462  newtet->tet[12] = (tetrahedron) dummysh;
8463  newtet->tet[13] = (tetrahedron) dummysh;
8464  }
8465  for (int i = 0; i < in->numberoftetrahedronattributes; i++) {
8466  setelemattribute(newtet->tet, i, 0.0);
8467  }
8468  if (b->varvolume) {
8469  setvolumebound(newtet->tet, -1.0);
8470  }
8471  // Initialize the location and version to be Zero.
8472  newtet->loc = 0;
8473  newtet->ver = 0;
8474 }
8475 
8477 // //
8478 // makeshellface() Create a new shellface with version zero. Used for //
8479 // both subfaces and seusegments. //
8480 // //
8482 
8483 void tetgenmesh::makeshellface(memorypool *pool, face *newface)
8484 {
8485  newface->sh = (shellface *) pool->alloc();
8486  //Initialize the three adjoining subfaces to be the omnipresent subface.
8487  newface->sh[0] = (shellface) dummysh;
8488  newface->sh[1] = (shellface) dummysh;
8489  newface->sh[2] = (shellface) dummysh;
8490  // Three NULL vertices.
8491  newface->sh[3] = (shellface) NULL;
8492  newface->sh[4] = (shellface) NULL;
8493  newface->sh[5] = (shellface) NULL;
8494  // Initialize the two adjoining tetrahedra to be "outer space".
8495  newface->sh[6] = (shellface) dummytet;
8496  newface->sh[7] = (shellface) dummytet;
8497  // Initialize the three adjoining subsegments to be the omnipresent
8498  // subsegments.
8499  newface->sh [8] = (shellface) dummysh;
8500  newface->sh [9] = (shellface) dummysh;
8501  newface->sh[10] = (shellface) dummysh;
8502  // Initialize the pointer to badface structure.
8503  newface->sh[11] = (shellface) NULL;
8504  if (b->quality && varconstraint) {
8505  // Initialize the maximum area bound.
8506  setareabound(*newface, 0.0);
8507  }
8508  // Set the boundary marker to zero.
8509  setshellmark(*newface, 0);
8510  // Set the type.
8511  setshelltype(*newface, NSHARP);
8512  if (checkpbcs) {
8513  // Set the pbcgroup be ivalid.
8514  setshellpbcgroup(*newface, -1);
8515  }
8516  // Initialize the version to be Zero.
8517  newface->shver = 0;
8518 }
8519 
8521 // //
8522 // makepoint() Create a new point. //
8523 // //
8525 
8526 void tetgenmesh::makepoint(point* pnewpoint)
8527 {
8528  int ptmark, i;
8529 
8530  *pnewpoint = (point) points->alloc();
8531  // Initialize three coordinates.
8532  (*pnewpoint)[0] = 0.0;
8533  (*pnewpoint)[1] = 0.0;
8534  (*pnewpoint)[2] = 0.0;
8535  // Initialize the list of user-defined attributes.
8536  for (i = 0; i < in->numberofpointattributes; i++) {
8537  (*pnewpoint)[3 + i] = 0.0;
8538  }
8539  // Initialize the metric tensor.
8540  for (i = 0; i < sizeoftensor; i++) {
8541  (*pnewpoint)[pointmtrindex + i] = 0.0;
8542  }
8543  if (b->plc || b->refine) {
8544  // Initialize the point-to-simplex filed.
8545  setpoint2tet(*pnewpoint, NULL);
8546  setpoint2sh(*pnewpoint, NULL);
8547  setpoint2ppt(*pnewpoint, NULL);
8548  if (b->metric) {
8549  setpoint2bgmtet(*pnewpoint, NULL);
8550  }
8551  if (checkpbcs) {
8552  // Initialize the other pointer to its pbc point.
8553  setpoint2pbcpt(*pnewpoint, NULL);
8554  }
8555  }
8556  // Initialize the point marker (starting from in->firstnumber).
8557  ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
8558  setpointmark(*pnewpoint, ptmark);
8559  // Initialize the point type.
8560  setpointtype(*pnewpoint, UNUSEDVERTEX);
8561 }
8562 
8563 //
8564 // End of memory management routines
8565 //
8566 
8567 //
8568 // Begin of point location routines
8569 //
8570 
8572 // //
8573 // randomnation() Generate a random number between 0 and 'choices' - 1. //
8574 // //
8576 
8577 unsigned long tetgenmesh::randomnation(unsigned int choices)
8578 {
8579  unsigned long newrandom;
8580 
8581  if (choices >= 714025l) {
8582  newrandom = (randomseed * 1366l + 150889l) % 714025l;
8583  randomseed = (newrandom * 1366l + 150889l) % 714025l;
8584  newrandom = newrandom * (choices / 714025l) + randomseed;
8585  if (newrandom >= choices) {
8586  return newrandom - choices;
8587  } else {
8588  return newrandom;
8589  }
8590  } else {
8591  randomseed = (randomseed * 1366l + 150889l) % 714025l;
8592  return randomseed % choices;
8593  }
8594  // Old function.
8595  // randomseed = (randomseed * 1366l + 150889l) % 714025l;
8596  // return randomseed / (714025l / choices + 1);
8597 }
8598 
8600 // //
8601 // distance2() Returns the square "distance" of a tetrahedron to point p. //
8602 // //
8604 
8605 REAL tetgenmesh::distance2(tetrahedron* tetptr, point p)
8606 {
8607  point p1, p2, p3, p4;
8608  REAL dx, dy, dz;
8609 
8610  p1 = (point) tetptr[4];
8611  p2 = (point) tetptr[5];
8612  p3 = (point) tetptr[6];
8613  p4 = (point) tetptr[7];
8614 
8615  dx = p[0] - 0.25 * (p1[0] + p2[0] + p3[0] + p4[0]);
8616  dy = p[1] - 0.25 * (p1[1] + p2[1] + p3[1] + p4[1]);
8617  dz = p[2] - 0.25 * (p1[2] + p2[2] + p3[2] + p4[2]);
8618 
8619  return dx * dx + dy * dy + dz * dz;
8620 }
8621 
8623 // //
8624 // preciselocate() Find a simplex containing a given point. //
8625 // //
8626 // This routine implements the simple Walk-through point location algorithm. //
8627 // Begins its search from 'searchtet', assume there is a line segment L from //
8628 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
8629 // towards 'searchpt' by traversing all faces intersected by L. //
8630 // //
8631 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
8632 // returned value indicates one of the following cases: //
8633 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchtet' //
8634 // is a handle whose origin is the existing vertex. //
8635 // - Returns ONEDGE if the point lies on a mesh edge. 'searchtet' is a //
8636 // handle whose primary edge is the edge on which the point lies. //
8637 // - Returns ONFACE if the point lies strictly within a face. 'searchtet' //
8638 // is a handle whose primary face is the face on which the point lies. //
8639 // - Returns INTETRAHEDRON if the point lies strictly in a tetrahededron. //
8640 // 'searchtet' is a handle on the tetrahedron that contains the point. //
8641 // - Returns OUTSIDE if the point lies outside the mesh. 'searchtet' is a //
8642 // handle whose location is the face the point is to 'above' of. //
8643 // //
8644 // WARNING: This routine is designed for convex triangulations, and will not //
8645 // generally work after the holes and concavities have been carved. //
8646 // //
8647 // If 'maxtetnumber' > 0, stop the searching process if the number of passed //
8648 // tets is larger than it and return OUTSIDE. //
8649 // //
8651 
8652 enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt,
8653  triface* searchtet, long maxtetnumber)
8654 {
8655  triface backtracetet;
8656  triface walkthroface;
8657  point forg, fdest, fapex, toppo;
8658  REAL ori1, ori2, ori3, ori4;
8659  long tetnumber;
8660  int side;
8661 
8662  if (isdead(searchtet)) searchtet->tet = dummytet;
8663  if (searchtet->tet == dummytet) {
8664  searchtet->loc = 0;
8665  symself(*searchtet);
8666  }
8667  // 'searchtet' should be a valid tetrahedron now.
8668 #ifdef SELF_CHECK
8669  // assert(!isdead(searchtet) && (searchtet->tet != dummytet));
8670 #endif
8671  if (isdead(searchtet)) {
8672  printf("Warning: Point location failed.\n");
8673  return OUTSIDE;
8674  }
8675 
8676  searchtet->ver = 0; // Keep in CCW edge ring.
8677  // Find a face of 'searchtet' such that the 'searchpt' lies strictly
8678  // above it. Such face should always exist.
8679  for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) {
8680  forg = org(*searchtet);
8681  fdest = dest(*searchtet);
8682  fapex = apex(*searchtet);
8683  ori1 = orient3d(forg, fdest, fapex, searchpt);
8684  if (ori1 < 0.0) break;
8685  }
8686 #ifdef SELF_CHECK
8687  assert(searchtet->loc < 4);
8688 #endif
8689 
8690  // Define 'tetnumber' for exit the loop when it's running endless.
8691  tetnumber = 0l;
8692  while ((maxtetnumber > 0l) && (tetnumber <= maxtetnumber)) {
8693  // Check if we are reaching the boundary of the triangulation.
8694  if (searchtet->tet == dummytet) {
8695  *searchtet = backtracetet;
8696  return OUTSIDE;
8697  }
8698  // Initialize the face for returning the walk-through face.
8699  walkthroface.tet = (tetrahedron *) NULL;
8700  // Adjust the edge ring, so that 'ori1 < 0.0' holds.
8701  searchtet->ver = 0;
8702  // 'toppo' remains unchange for the following orientation tests.
8703  toppo = oppo(*searchtet);
8704  // Check the three sides of 'searchtet' to find the face through which
8705  // we can walk next.
8706  for (side = 0; side < 3; side++) {
8707  forg = org(*searchtet);
8708  fdest = dest(*searchtet);
8709  ori2 = orient3d(forg, fdest, toppo, searchpt);
8710  if (ori2 == 0.0) {
8711  // They are coplanar, check if 'searchpt' lies inside, or on an edge,
8712  // or coindice with a vertex of face (forg, fdest, toppo).
8713  fapex = apex(*searchtet);
8714  ori3 = orient3d(fdest, fapex, toppo, searchpt);
8715  if (ori3 < 0.0) {
8716  // Outside the face (fdest, fapex, toppo), walk through it.
8717  enextself(*searchtet);
8718  fnext(*searchtet, walkthroface);
8719  break;
8720  }
8721  ori4 = orient3d(fapex, forg, toppo, searchpt);
8722  if (ori4 < 0.0) {
8723  // Outside the face (fapex, forg, toppo), walk through it.
8724  enext2self(*searchtet);
8725  fnext(*searchtet, walkthroface);
8726  break;
8727  }
8728  // Remember, ori1 < 0.0, which means 'searchpt' will not on edge
8729  // (forg, fdest) or on vertex forg or fdest.
8730 #ifdef SELF_CHECK
8731  assert(ori1 < 0.0);
8732 #endif
8733  // The rest possible cases are:
8734  // (1) 'searchpt' lies on edge (fdest, toppo);
8735  // (2) 'searchpt' lies on edge (toppo, forg);
8736  // (3) 'searchpt' coincident with toppo;
8737  // (4) 'searchpt' lies inside face (forg, fdest, toppo).
8738  fnextself(*searchtet);
8739  if (ori3 == 0.0) {
8740  if (ori4 == 0.0) {
8741  // Case (4).
8742  enext2self(*searchtet);
8743  return ONVERTEX;
8744  } else {
8745  // Case (1).
8746  enextself(*searchtet);
8747  return ONEDGE;
8748  }
8749  }
8750  if (ori4 == 0.0) {
8751  // Case (2).
8752  enext2self(*searchtet);
8753  return ONEDGE;
8754  }
8755  // Case (4).
8756  return ONFACE;
8757  } else if (ori2 < 0.0) {
8758  // Outside the face (forg, fdest, toppo), walk through it.
8759  fnext(*searchtet, walkthroface);
8760  break;
8761  }
8762  // Go to check next side.
8763  enextself(*searchtet);
8764  }
8765  if (side >= 3) {
8766  // Found! Inside tetrahedron.
8767  return INTETRAHEDRON;
8768  }
8769  // We walk through the face 'walkthroface' and continue the searching.
8770 #ifdef SELF_CHECK
8771  assert(walkthroface.tet != (tetrahedron *) NULL);
8772 #endif
8773  // Store the face handle in 'backtracetet' before we take the real walk.
8774  // So we are able to restore the handle to 'searchtet' if we are
8775  // reaching the outer boundary.
8776  backtracetet = walkthroface;
8777  sym(walkthroface, *searchtet);
8778  tetnumber++;
8779  }
8780 
8781  // Should never be here.
8782  // printf("Internal error in preciselocate(): Point location failed.\n");
8783  // internalerror();
8784  return OUTSIDE;
8785 }
8786 
8788 // //
8789 // locate() Find a simplex containing a given point. //
8790 // //
8791 // This routine implements Muecke's Jump-and-walk point location algorithm. //
8792 // It improves the simple walk-through by "jumping" to a good starting point //
8793 // via random sampling. Searching begins from one of handles: the input //
8794 // 'searchtet', a recently encountered tetrahedron 'recenttet', or from one //
8795 // chosen from a random sample. The choice is made by determining which one //
8796 // 's barycenter is closest to the point we are searcing for. Having chosen //
8797 // the starting tetrahedron, the simple Walk-through algorithm is used to do //
8798 // the real walking. //
8799 // //
8800 // The return value indicates the location of the 'searchpt' (INTETRAHEDRON, //
8801 // or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding //
8802 // to that value. See the introduction part of preciselocate() for detail. //
8803 // //
8804 // WARNING: This routine is designed for convex triangulations, and will not //
8805 // generally work after the holes and concavities have been carved. //
8806 // //
8808 
8809 enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt,
8810  triface *searchtet)
8811 {
8812  tetrahedron *firsttet, *tetptr;
8813  void **sampleblock;
8814  long sampleblocks, samplesperblock, samplenum;
8815  long tetblocks, i, j;
8816  unsigned long alignptr;
8817  REAL searchdist, dist;
8818 
8819  // 'searchtet' should be a valid tetrahedron.
8820  if (isdead(searchtet)) {
8821  searchtet->tet = dummytet;
8822  }
8823  if (searchtet->tet == dummytet) {
8824  // This is an 'Outer Space' handle, get a hull tetrahedron.
8825  searchtet->loc = 0;
8826  symself(*searchtet);
8827  }
8828 #ifdef SELF_CHECK
8829  // assert(!isdead(searchtet));
8830 #endif
8831  if (isdead(searchtet)) {
8832  printf("Warning: Point location failed.\n");
8833  return OUTSIDE;
8834  }
8835 
8836  // Get the distance from the suggested starting tet to the point we seek.
8837  searchdist = distance2(searchtet->tet, searchpt);
8838 
8839  // If a recently encountered tetrahedron has been recorded and has not
8840  // been deallocated, test it as a good starting point.
8841  if (!isdead(&recenttet) && (recenttet.tet != searchtet->tet)) {
8842  dist = distance2(recenttet.tet, searchpt);
8843  if (dist < searchdist) {
8844  *searchtet = recenttet;
8845  searchdist = dist;
8846  }
8847  }
8848 
8849  // Select "good" candidate using k random samples, taking the closest one.
8850  // The number of random samples taken is proportional to the fourth root
8851  // of the number of tetrahedra in the mesh. The next bit of code assumes
8852  // that the number of tetrahedra increases monotonically.
8853  while (SAMPLEFACTOR * samples * samples * samples * samples <
8854  tetrahedrons->items) {
8855  samples++;
8856  }
8857  // Find how much blocks in current tet pool.
8858  tetblocks = (tetrahedrons->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK;
8859  // Find the average samles per block. Each block at least have 1 sample.
8860  samplesperblock = 1 + (samples / tetblocks);
8861  sampleblocks = samples / samplesperblock;
8862  sampleblock = tetrahedrons->firstblock;
8863  for (i = 0; i < sampleblocks; i++) {
8864  alignptr = (unsigned long) (sampleblock + 1);
8865  firsttet = (tetrahedron *)
8866  (alignptr + (unsigned long) tetrahedrons->alignbytes
8867  - (alignptr % (unsigned long) tetrahedrons->alignbytes));
8868  for (j = 0; j < samplesperblock; j++) {
8869  if (i == tetblocks - 1) {
8870  // This is the last block.
8871  samplenum = randomnation((int)
8872  (tetrahedrons->maxitems - (i * ELEPERBLOCK)));
8873  } else {
8874  samplenum = randomnation(ELEPERBLOCK);
8875  }
8876  tetptr = (tetrahedron *)
8877  (firsttet + (samplenum * tetrahedrons->itemwords));
8878  if (tetptr[4] != (tetrahedron) NULL) {
8879  dist = distance2(tetptr, searchpt);
8880  if (dist < searchdist) {
8881  searchtet->tet = tetptr;
8882  searchdist = dist;
8883  }
8884  }
8885  }
8886  sampleblock = (void **) *sampleblock;
8887  }
8888 
8889  // Call simple walk-through to locate the point.
8890  return preciselocate(searchpt, searchtet, tetrahedrons->items);
8891 }
8892 
8894 // //
8895 // adjustlocate() Adjust the precise location of a vertex. //
8896 // //
8897 // 'precise' is the value returned from preciselocate(). It indicates the //
8898 // exact location of the point 'searchpt' with respect to the tetrahedron //
8899 // 'searchtet'. 'epspp' is a given relative tolerance. //
8900 // //
8901 // This routine re-evaluates the orientations of searchpt with respect to //
8902 // the four sides of searchtet. Detects the coplanarities by additinal tests //
8903 // which are based on the given tolerance. If 'precise' is ONFACE or ONEDGE, //
8904 // we can save one or two orientation tests. //
8905 // //
8906 // The return value indicates the location of the 'searchpt' (INTETRAHEDRON, //
8907 // or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding //
8908 // to that value. See the introduction part of preciselocate() for detail. //
8909 // //
8910 // WARNING: This routine detect degenerate case using relative tolerance. //
8911 // It is better used after locate() or preciselocate(). For general inputs, //
8912 // it may not able to tell the correct location. //
8913 // //
8915 
8916 enum tetgenmesh::locateresult tetgenmesh::adjustlocate(point searchpt,
8917  triface* searchtet, enum locateresult precise, REAL epspp)
8918 {
8919  point torg, tdest, tapex, toppo;
8920  REAL s1, s2, s3, s4;
8921 
8922  // For the given 'searchtet', the orientations tests are:
8923  // s1: (tdest, torg, tapex, searchpt);
8924  // s2: (torg, tdest, toppo, searchpt);
8925  // s3: (tdest, tapex, toppo, searchpt);
8926  // s4: (tapex, torg, toppo, searchpt);
8927  adjustedgering(*searchtet, CCW);
8928  torg = org(*searchtet);
8929  tdest = dest(*searchtet);
8930  tapex = apex(*searchtet);
8931  toppo = oppo(*searchtet);
8932 
8933  switch (precise) {
8934  case ONVERTEX:
8935  // This case we don't need do any further test.
8936  return ONVERTEX;
8937  case ONEDGE:
8938  // (torg, tdest);
8939  s1 = 0.0;
8940  s2 = 0.0;
8941  break;
8942  case ONFACE:
8943  // (tdest, torg, tapex);
8944  s1 = 0.0;
8945  s2 = orient3d(torg, tdest, toppo, searchpt);
8946  break;
8947  default: // INTETRAHEDRON or OUTSIDE
8948  s1 = orient3d(tdest, torg, tapex, searchpt);
8949  s2 = orient3d(torg, tdest, toppo, searchpt);
8950  }
8951 
8952  if (s1 != 0.0) {
8953  if (iscoplanar(tdest, torg, tapex, searchpt, s1, epspp)) {
8954  s1 = 0.0;
8955  }
8956  }
8957  if (s1 < 0.0) {
8958  return OUTSIDE;
8959  }
8960 
8961  if (s2 != 0.0) {
8962  if (iscoplanar(torg, tdest, toppo, searchpt, s2, epspp)) {
8963  s2 = 0.0;
8964  }
8965  }
8966  if (s2 < 0.0) {
8967  fnextself(*searchtet);
8968  return OUTSIDE;
8969  }
8970 
8971  s3 = orient3d(tdest, tapex, toppo, searchpt);
8972  if (s3 != 0.0) {
8973  if (iscoplanar(tdest, tapex, toppo, searchpt, s3, epspp)) {
8974  s3 = 0.0;
8975  }
8976  }
8977  if (s3 < 0.0) {
8978  enextfnextself(*searchtet);
8979  return OUTSIDE;
8980  }
8981 
8982  s4 = orient3d(tapex, torg, toppo, searchpt);
8983  if (s4 != 0.0) {
8984  if (iscoplanar(tapex, torg, toppo, searchpt, s4, epspp)) {
8985  s4 = 0.0;
8986  }
8987  }
8988  if (s4 < 0.0) {
8989  enext2fnextself(*searchtet);
8990  return OUTSIDE;
8991  }
8992 
8993  // Determine degenerate cases.
8994  if (s1 == 0.0) {
8995  if (s2 == 0.0) {
8996  if (s3 == 0.0) {
8997  // On tdest.
8998  enextself(*searchtet);
8999  return ONVERTEX;
9000  }
9001  if (s4 == 0.0) {
9002  // On torg.
9003  return ONVERTEX;
9004  }
9005  // On edge (torg, tdest).
9006  return ONEDGE;
9007  }
9008  if (s3 == 0.0) {
9009  if (s4 == 0.0) {
9010  // On tapex.
9011  enext2self(*searchtet);
9012  return ONVERTEX;
9013  }
9014  // On edge (tdest, tapex).
9015  enextself(*searchtet);
9016  return ONEDGE;
9017  }
9018  if (s4 == 0.0) {
9019  // On edge (tapex, torg).
9020  enext2self(*searchtet);
9021  return ONEDGE;
9022  }
9023  // On face (torg, tdest, tapex).
9024  return ONFACE;
9025  }
9026  if (s2 == 0.0) {
9027  fnextself(*searchtet);
9028  if (s3 == 0.0) {
9029  if (s4 == 0.0) {
9030  // On toppo.
9031  enext2self(*searchtet);
9032  return ONVERTEX;
9033  }
9034  // On edge (tdest, toppo).
9035  enextself(*searchtet);
9036  return ONEDGE;
9037  }
9038  if (s4 == 0.0) {
9039  // On edge (toppo, torg).
9040  enext2self(*searchtet);
9041  return ONEDGE;
9042  }
9043  // On face (torg, tdest, toppo).
9044  return ONFACE;
9045  }
9046  if (s3 == 0.0) {
9047  enextfnextself(*searchtet);
9048  if (s4 == 0.0) {
9049  // On edge (tapex, toppo).
9050  enextself(*searchtet);
9051  return ONEDGE;
9052  }
9053  // On face (tdest, tapex, toppo).
9054  return ONFACE;
9055  }
9056  if (s4 == 0.0) {
9057  enext2fnextself(*searchtet);
9058  // On face (tapex, torg, toppo).
9059  return ONFACE;
9060  }
9061 
9062  // Inside tetrahedron.
9063  return INTETRAHEDRON;
9064 }
9065 
9067 // //
9068 // hullwalk() Find a tetrahedron on the hull to continue search. //
9069 // //
9071 
9072 enum tetgenmesh::locateresult tetgenmesh::hullwalk(point searchpt,
9073  triface *hulltet)
9074 {
9075  list* travtetlist;
9076  triface travtet, neightet;
9077  point pa, pb, pc;
9078  enum locateresult loc;
9079  REAL ori;
9080  int i;
9081 
9082  travtetlist = new list(sizeof(triface), NULL, 256);
9083  travtet = *hulltet;
9084  infect(travtet);
9085  travtetlist->append(&travtet);
9086 
9087  loc = OUTSIDE;
9088  for (i = 0; i < travtetlist->len(); i++) {
9089  travtet = * (triface *)(* travtetlist)[i];
9090  // Choose the CCW-edgering in face.
9091  travtet.ver = 0;
9092  // Look for a side where pt lies below it.
9093  for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
9094  pa = org(travtet);
9095  pb = dest(travtet);
9096  pc = apex(travtet);
9097  ori = orient3d(pa, pb, pc, searchpt);
9098  if (ori > 0.0) break;
9099  }
9100  // Is pt above all (or coplanar with some of) the four sides?
9101  if (travtet.loc == 4) {
9102  hulltet->tet = travtet.tet;
9103  loc = adjustlocate(searchpt, hulltet, INTETRAHEDRON, b->epsilon);
9104  assert(loc != OUTSIDE);
9105  } else { // ori > 0.0
9106  // pt is below (behind) this side. We want to walk through it.
9107  sym(travtet, neightet);
9108  if (neightet.tet == dummytet) {
9109  // This is a hull side. Is p approximately on this side.
9110  loc = adjustlocate(searchpt, &travtet, OUTSIDE, b->epsilon);
9111  }
9112  if (loc == OUTSIDE) {
9113  // Let's collect all the neighbors for next searching.
9114  for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) {
9115  sym(travtet, neightet);
9116  if ((neightet.tet != dummytet) && !infected(neightet)) {
9117  // Neighbor exists and not visited.
9118  infect(neightet);
9119  travtetlist->append(&neightet);
9120  }
9121  } // for (travtet.loc = 0;
9122  } // if (loc == OUTSIDE)
9123  } // if (travtet.loc == 4)
9124  if (loc != OUTSIDE) break;
9125  } // for (i = 0; i < travtetlist->len(); i++)
9126 
9127  // Uninfect traversed tets.
9128  for (i = 0; i < travtetlist->len(); i++) {
9129  travtet = * (triface *)(* travtetlist)[i];
9130  uninfect(travtet);
9131  }
9132 
9133  delete travtetlist;
9134  return loc;
9135 }
9136 
9138 // //
9139 // locatesub() Find a point in the surface mesh of a facet. //
9140 // //
9141 // Searching begins from the input 'searchsh', it should be a handle on the //
9142 // convex hull of the facet triangulation. //
9143 // //
9144 // If 'stopatseg' is nonzero, the search will stop if it tries to walk //
9145 // through a subsegment, and will return OUTSIDE. //
9146 // //
9147 // On completion, 'searchsh' is a subface that contains 'searchpt'. //
9148 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' //
9149 // is a handle whose origin is the existing vertex. //
9150 // - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a //
9151 // handle whose primary edge is the edge on which the point lies. //
9152 // - Returns ONFACE if the point lies strictly within a subface. //
9153 // 'searchsh' is a handle on which the point lies. //
9154 // - Returns OUTSIDE if the point lies outside the triangulation. //
9155 // //
9156 // WARNING: This routine is designed for convex triangulations, and will not //
9157 // not generally work after the holes and concavities have been carved. //
9158 // //
9160 
9161 enum tetgenmesh::locateresult tetgenmesh::locatesub(point searchpt,
9162  face* searchsh, int stopatseg, REAL epspp)
9163 {
9164  face backtracksh, spinsh, checkedge;
9165  point forg, fdest, fapex;
9166  REAL orgori, destori;
9167  REAL ori, sign;
9168  int moveleft, i;
9169 
9170  if (searchsh->sh == dummysh) {
9171  searchsh->shver = 0;
9172  spivotself(*searchsh);
9173 #ifdef SELF_CHECK
9174  assert(searchsh->sh != dummysh);
9175 #endif
9176  }
9177  // Find the sign to simulate that abovepoint is 'above' the facet.
9178  adjustedgering(*searchsh, CCW);
9179  forg = sorg(*searchsh);
9180  fdest = sdest(*searchsh);
9181  fapex = sapex(*searchsh);
9182  ori = orient3d(forg, fdest, fapex, abovepoint);
9183  sign = ori > 0.0 ? -1 : 1;
9184 
9185  // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has
9186  // CCW orientation with respect to searchsh in plane). Such edge
9187  // should always exist. Save it as (forg, fdest).
9188  for (i = 0; i < 3; i++) {
9189  forg = sorg(*searchsh);
9190  fdest = sdest(*searchsh);
9191  ori = orient3d(forg, fdest, abovepoint, searchpt) * sign;
9192  if (ori > 0.0) break;
9193  senextself(*searchsh);
9194  }
9195 #ifdef SELF_CHECK
9196  assert(i < 3);
9197 #endif
9198 
9199  while (1) {
9200  fapex = sapex(*searchsh);
9201  // Check whether the apex is the point we seek.
9202  if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] &&
9203  fapex[2] == searchpt[2]) {
9204  senext2self(*searchsh);
9205  return ONVERTEX;
9206  }
9207  // Does the point lie on the other side of the line defined by the
9208  // triangle edge opposite the triangle's destination?
9209  destori = orient3d(forg, fapex, abovepoint, searchpt) * sign;
9210  if (epspp > 0.0) {
9211  if (iscoplanar(forg, fapex, abovepoint, searchpt, destori, epspp)) {
9212  destori = 0.0;
9213  }
9214  }
9215  // Does the point lie on the other side of the line defined by the
9216  // triangle edge opposite the triangle's origin?
9217  orgori = orient3d(fapex, fdest, abovepoint, searchpt) * sign;
9218  if (epspp > 0.0) {
9219  if (iscoplanar(fapex, fdest, abovepoint, searchpt, orgori, epspp)) {
9220  orgori = 0.0;
9221  }
9222  }
9223  if (destori > 0.0) {
9224  moveleft = 1;
9225  } else {
9226  if (orgori > 0.0) {
9227  moveleft = 0;
9228  } else {
9229  // The point must be on the boundary of or inside this triangle.
9230  if (destori == 0.0) {
9231  senext2self(*searchsh);
9232  return ONEDGE;
9233  }
9234  if (orgori == 0.0) {
9235  senextself(*searchsh);
9236  return ONEDGE;
9237  }
9238  return ONFACE;
9239  }
9240  }
9241  // Move to another triangle. Leave a trace `backtracksh' in case
9242  // walking off a boundary of the triangulation.
9243  if (moveleft) {
9244  senext2(*searchsh, backtracksh);
9245  fdest = fapex;
9246  } else {
9247  senext(*searchsh, backtracksh);
9248  forg = fapex;
9249  }
9250  // Check if we meet a segment.
9251  sspivot(backtracksh, checkedge);
9252  if (checkedge.sh != dummysh) {
9253  if (stopatseg) {
9254  // The flag indicates we should not cross a segment. Stop.
9255  *searchsh = backtracksh;
9256  return OUTSIDE;
9257  }
9258  // Try to walk through a segment. We need to find a coplanar subface
9259  // sharing this segment to get into.
9260  spinsh = backtracksh;
9261  do {
9262  spivotself(spinsh);
9263  if (spinsh.sh == backtracksh.sh) {
9264  // Turn back, no coplanar subface is found.
9265  break;
9266  }
9267  // Are they belong to the same facet.
9268  if (shellmark(spinsh) == shellmark(backtracksh)) {
9269  // Find a coplanar subface. Walk into it.
9270  *searchsh = spinsh;
9271  break;
9272  }
9273  // Are they (nearly) coplanar?
9274  ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh));
9275  if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori,
9276  b->epsilon)) {
9277  // Find a coplanar subface. Walk into it.
9278  *searchsh = spinsh;
9279  break;
9280  }
9281  } while (spinsh.sh != backtracksh.sh);
9282  } else {
9283  spivot(backtracksh, *searchsh);
9284  }
9285  // Check for walking right out of the triangulation.
9286  if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) {
9287  // Go back to the last triangle.
9288  *searchsh = backtracksh;
9289  return OUTSIDE;
9290  }
9291  // To keep the same orientation wrt abovepoint.
9292  if (sorg(*searchsh) != forg) sesymself(*searchsh);
9293 #ifdef SELF_CHECK
9294  assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest));
9295 #endif
9296  }
9297 }
9298 
9300 // //
9301 // adjustlocatesub() Adjust the precise location of a vertex. //
9302 // //
9303 // 'precise' is the precise location (returned from locatesub()) of 'searcht'//
9304 // with respect to 'searchsh'. 'epspp' is the given relative tolerance. //
9305 // //
9306 // This routine re-evaluates the orientations of 'searchpt' with respect to //
9307 // the three edges of 'searchsh'. Detects the collinearities by additinal //
9308 // tests based on the given tolerance. If 'precise' is ONEDGE, one can save //
9309 // one orientation test for the current edge of 'searchsh'. //
9310 // //
9311 // On completion, 'searchsh' is a subface contains 'searchpt'. The returned //
9312 // value indicates one of the following cases: //
9313 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' //
9314 // is a handle whose origin is the existing vertex. //
9315 // - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a //
9316 // handle whose primary edge is the edge on which the point lies. //
9317 // - Returns ONFACE if the point lies strictly within a subface. //
9318 // 'searchsh' is a handle on which the point lies. //
9319 // - Returns OUTSIDE if the point lies outside 'searchsh'. //
9320 // //
9322 
9323 enum tetgenmesh::locateresult tetgenmesh::
9324 adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise,
9325  REAL epspp)
9326 {
9327  point pa, pb, pc;
9328  bool s1, s2, s3;
9329 
9330  pa = sorg(*searchsh);
9331  pb = sdest(*searchsh);
9332  pc = sapex(*searchsh);
9333 
9334  if (precise == ONEDGE) {
9335  s1 = true;
9336  } else {
9337  s1 = iscollinear(pa, pb, searchpt, epspp);
9338  }
9339  s2 = iscollinear(pb, pc, searchpt, epspp);
9340  s3 = iscollinear(pc, pa, searchpt, epspp);
9341  if (s1) {
9342  if (s2) {
9343  // on vertex pb.
9344 #ifdef SELF_CHECK
9345  assert(!s3);
9346 #endif
9347  senextself(*searchsh);
9348  return ONVERTEX;
9349  } else if (s3) {
9350  // on vertex pa.
9351  return ONVERTEX;
9352  } else {
9353  // on edge pa->pb.
9354  return ONEDGE;
9355  }
9356  } else if (s2) {
9357  if (s3) {
9358  // on vertex pc.
9359  senext2self(*searchsh);
9360  return ONVERTEX;
9361  } else {
9362  // on edge pb->pc.
9363  senextself(*searchsh);
9364  return ONEDGE;
9365  }
9366  } else if (s3) {
9367  // on edge pc->pa.
9368  senext2self(*searchsh);
9369  return ONEDGE;
9370  } else {
9371  return precise;
9372  }
9373 }
9374 
9376 // //
9377 // locateseg() Find a point in subsegments. //
9378 // //
9379 // Searching begins from the input 'searchseg', it should be a subsegment of //
9380 // the whole segment. //
9381 // //
9382 // On completion, 'searchseg' is a subsegment that contains 'searchpt'. //
9383 // - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' //
9384 // is a handle whose origin is the existing vertex. //
9385 // - Returns ONEDGE if the point lies inside 'searchseg'. //
9386 // - Returns OUTSIDE if the point lies outside the segment. //
9387 // //
9389 
9390 enum tetgenmesh::locateresult tetgenmesh::
9391 locateseg(point searchpt, face* searchseg)
9392 {
9393  face backtraceseg;
9394  point pa, pb;
9395  REAL dx, dy, dz;
9396  int moveleft;
9397  int i;
9398 
9399  moveleft = 0;
9400  while (1) {
9401  searchseg->shver = 0;
9402  pa = sorg(*searchseg);
9403  pb = sdest(*searchseg);
9404  // Find the biggest difference in x, y, and z coordinates of a and b.
9405  dx = fabs(pb[0] - pa[0]);
9406  dy = fabs(pb[1] - pa[1]);
9407  dz = fabs(pb[2] - pa[2]);
9408  if (dx > dy) {
9409  if (dx > dz) {
9410  i = 0;
9411  } else {
9412  i = 2;
9413  }
9414  } else {
9415  if (dy > dz) {
9416  i = 1;
9417  } else {
9418  i = 2;
9419  }
9420  }
9421  if (pa[i] < pb[i]) {
9422  if (searchpt[i] < pa[i]) {
9423  moveleft = 1;
9424  } else if (searchpt[i] > pa[i]) {
9425  if (searchpt[i] < pb[i]) {
9426  return ONEDGE;
9427  } else if (searchpt[i] > pb[i]) {
9428  moveleft = 0;
9429  } else {
9430 #ifdef SELF_CHECK
9431  assert(searchpt[i] == pb[i]);
9432 #endif
9433  sesymself(*searchseg);
9434  return ONVERTEX;
9435  }
9436  } else {
9437 #ifdef SELF_CHECK
9438  assert(searchpt[i] == pa[i]);
9439 #endif
9440  return ONVERTEX;
9441  }
9442  } else if (pa[i] > pb[i]) {
9443  if (searchpt[i] < pb[i]) {
9444  moveleft = 0;
9445  } else if (searchpt[i] > pb[i]) {
9446  if (searchpt[i] < pa[i]) {
9447  return ONEDGE;
9448  } else if (searchpt[i] > pa[i]) {
9449  moveleft = 1;
9450  } else {
9451 #ifdef SELF_CHECK
9452  assert(searchpt[i] == pa[i]);
9453 #endif
9454  return ONVERTEX;
9455  }
9456  } else {
9457 #ifdef SELF_CHECK
9458  assert(searchpt[i] == pb[i]);
9459 #endif
9460  sesymself(*searchseg);
9461  return ONVERTEX;
9462  }
9463  }
9464  backtraceseg = *searchseg;
9465  if (moveleft) {
9466  senext2self(*searchseg);
9467  } else {
9468  senextself(*searchseg);
9469  }
9470  spivotself(*searchseg);
9471  if (searchseg->sh == dummysh) {
9472  *searchseg = backtraceseg;
9473  break;
9474  }
9475  }
9476 
9477  return OUTSIDE;
9478 }
9479 
9481 // //
9482 // adjustlocateseg() Adjust the precise location of a vertex on segment. //
9483 // //
9484 // 'searchpt' is either inside or ouside the segment 'searchseg'. It will be //
9485 // adjusted to on vertex if it is very close to an endpoint of 'searchseg'. //
9486 // 'epspp' is the given relative tolerance. //
9487 // //
9489 
9490 enum tetgenmesh::locateresult tetgenmesh::
9491 adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise,
9492  REAL epspp)
9493 {
9494  point pa, pb;
9495  REAL L, d, r;
9496 
9497  pa = sorg(*searchseg);
9498  pb = sdest(*searchseg);
9499  L = distance(pa, pb);
9500 
9501  // Is searchpt approximate to pa?
9502  d = distance(pa, searchpt);
9503  r = d / L;
9504  if (r <= epspp) {
9505  return ONVERTEX;
9506  }
9507  // Is searchpt approximate to pb?
9508  d = distance(pb, searchpt);
9509  r = d / L;
9510  if (r <= epspp) {
9511  sesymself(*searchseg);
9512  return ONVERTEX;
9513  }
9514 
9515  return precise;
9516 }
9517 
9518 //
9519 // End of point location routines
9520 //
9521 
9522 //
9523 // Begin of mesh transformation routines
9524 //
9525 
9527 // //
9528 // Flip operations //
9529 // //
9530 // If abc is a hull face, it is unflipable, and is locally Delaunay. In the //
9531 // following, we assume abc is an interior face, and the other tetrahedron //
9532 // adjoining at abc is bace. //
9533 // //
9534 // If the convex hull CH of the set {a, b, c, d, e} only has four vertices, //
9535 // i.e., one vertex lies inside CH, then abc is unflipable, and is locally //
9536 // Delaunay. If CH is the vertex set itself, we have the following cases to //
9537 // determine whether abc is flipable or not. //
9538 // //
9539 // If no four points of {a, b, c, d, e} are coplanar, a 2-to-3 flip can be //
9540 // applied to abc if the edge de crosses the triangle abc; a 3-to-2 flip can //
9541 // be applied to abc if ab crosses cde, and abde exists, otherwise, face abc //
9542 // is unflipable, i.e., the tetrahedron abde is not present. //
9543 // //
9544 // If four points of {a, b, c, d, e} are coplanar (two faces are coplanar). //
9545 // Assume faces abd and abe are coplanar (it is impossible be abc). If a, b, //
9546 // d, e form a non-convex quadrilateral, then abc is unflipable, furthermore,//
9547 // it is locally Delaunay. Assume they are convex quadrilateral, if abd and //
9548 // abe are hull faces, a 2-to-2 flip can be applied to abc; if abd and abe //
9549 // are interior faces, assume two tetrahedra adjoining abd and abe at the //
9550 // opposite sides are abdg and abef, respectively. If g = f, a 4-to-4 flip //
9551 // can be applied to abc, otherwise, abc is unflipable. //
9552 // //
9553 // There are other cases which can cause abc unflipable. If abc is a subface,//
9554 // a 2-to-3 flip is forbidden; if ab is a subsegment, flips 3-to-2, 2-to-2, //
9555 // and 4-to-4 are forbidden. //
9556 // //
9558 
9560 // //
9561 // categorizeface() Determine the flip type of a given face. //
9562 // //
9563 // On input, 'horiz' represents the face abc we want to flip (imagine it is //
9564 // parallel to the horizon). Let the tet above it be abcd. //
9565 // //
9566 // This routine determines the suitable type of flip operation for 'horiz'. //
9567 // - Returns T23 if a 2-to-3 flip is applicable. 'horiz' is same as input. //
9568 // - Returns T32 if a 3-to-2 flip is applicable. 'horiz' returns the edge //
9569 // of abc which is the flipable. //
9570 // - Returns T22 if a 2-to-2 or 4-to-4 flip is applicable. 'horiz' returns //
9571 // the edge of abc which is flipable. //
9572 // - Returns N32 indicates it is unflipable due to the absence of a tet. //
9573 // 'horize' returns the unflipable edge. //
9574 // - Returns N40 indicates it is unflipable and is locally Delaunay. //
9575 // - Returns FORBIDDENFACE indicates abc is a subface. //
9576 // - Returns FORBIDDENEDGE indicates the flipable edge of abc is a segment.//
9577 // 'horize' returns the flipable edge. //
9578 // //
9579 // Given a face abc, with two adjoining tetrahedra abcd and bace. If abc is //
9580 // flipable, i.e., T23, T32, T22 or T44, its flip type can be determined by //
9581 // doing five orientation tests: two tests for determining that d, e lie on //
9582 // the different sides of abc, three tests for determining if the edge de //
9583 // intersects the face abc. However, if we use the neighbor information of //
9584 // the mesh data structure, we can reduce the five orientation tests to at //
9585 // most three tests, that is, the two tests for determining whether d and e //
9586 // lie on the different sides of abc can be saved. //
9587 // //
9589 
9590 enum tetgenmesh::fliptype tetgenmesh::categorizeface(triface& horiz)
9591 {
9592  triface symhoriz, casing;
9593  face checksh, checkseg;
9594  face cassh1, cassh2;
9595  point pa, pb, pc, pd, pe, pf, pg;
9596  point abdoppo, bcdoppo, cadoppo;
9597  REAL ori1, ori2, ori3;
9598  int adjtet;
9599 
9600  sym(horiz, symhoriz);
9601  if (symhoriz.tet == dummytet) {
9602  // A hull face is unflipable and locally Delaunay.
9603  return N40;
9604  }
9605 
9606  adjustedgering(horiz, CCW);
9607  findedge(&symhoriz, dest(horiz), org(horiz));
9608  pa = org(horiz);
9609  pb = dest(horiz);
9610  pc = apex(horiz);
9611  pd = oppo(horiz);
9612  pe = oppo(symhoriz);
9613 
9614  // Find the number of adjacent tetrahedra of abc, which have d, e, and one
9615  // of corners of abc as their corners. This number can be 0, 1 and 2.
9616  abdoppo = bcdoppo = cadoppo = (point) NULL;
9617  adjtet = 0;
9618  fnext(horiz, casing); // at edge 'ab'.
9619  symself(casing);
9620  if (casing.tet != dummytet) {
9621  abdoppo = oppo(casing);
9622  if (abdoppo == pe) adjtet++;
9623  }
9624  enextfnext(horiz, casing); // at edge 'bc'.
9625  symself(casing);
9626  if (casing.tet != dummytet) {
9627  bcdoppo = oppo(casing);
9628  if (bcdoppo == pe) adjtet++;
9629  }
9630  enext2fnext(horiz, casing); // at edge 'ca'.
9631  symself(casing);
9632  if (casing.tet != dummytet) {
9633  cadoppo = oppo(casing);
9634  if (cadoppo == pe) adjtet++;
9635  }
9636 
9637  if (adjtet == 0) {
9638  // No adjacent tetrahedron. Types T23, T22 and T44 are possible.
9639  ori1 = orient3d(pa, pb, pd, pe);
9640  if (checksubfaces && ori1 != 0.0) {
9641  // Check if abd and abe are both boundary faces?
9642  fnext(horiz, casing);
9643  tspivot(casing, cassh1);
9644  fnext(symhoriz, casing);
9645  tspivot(casing, cassh2);
9646  if ((cassh1.sh != dummysh) && (cassh2.sh != dummysh)) {
9647  // abd and abe are both boundary faces. Check if ab is a segment.
9648  findedge(&cassh1, pa, pb);
9649  sspivot(cassh1, checkseg);
9650  if (checkseg.sh == dummysh) {
9651  // ab is not a segment - abd and abe belong to the same facet.
9652  // The four points are forced to be coplanar.
9653  ori1 = 0.0;
9654  } else {
9655  // ab is a segment - abd and abe belong to two different facets.
9656  // In principle, a, b, c and d can form a tetrahedron (since
9657  // ori1 != 0.0). However, we should avoid to create a very
9658  // flat one which may form a sequence of extremely badly-shaped
9659  // or even wrong orientational tets. Test with a larger epsilon.
9660  if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
9661  }
9662  } else {
9663  // abd and abe are not both boundary faces. Check if abd and bae
9664  // are approximately coplanar with respect to the epsilon.
9665  if (iscoplanar(pa, pb, pd, pe, ori1, b->epsilon)) ori1 = 0.0;
9666  }
9667  }
9668  if (ori1 < 0.0) {
9669  // e lies above abd, unflipable, tet abde is not present.
9670 #ifdef SELF_CHECK
9671  if (!nonconvex) {
9672  // abd and abe should not be hull faces, check it.
9673  fnext(horiz, casing);
9674  symself(casing);
9675  assert(casing.tet != dummytet);
9676  fnext(symhoriz, casing);
9677  symself(casing);
9678  assert(casing.tet != dummytet);
9679  }
9680 #endif
9681  if (checksubfaces) {
9682  // The nonconvexbility may be casued by existing an subsegment.
9683  tsspivot(&horiz, &checkseg);
9684  if (checkseg.sh != dummysh) {
9685  return FORBIDDENEDGE;
9686  }
9687  }
9688  return N32;
9689  }
9690  ori2 = orient3d(pb, pc, pd, pe);
9691  if (checksubfaces && ori2 != 0.0) {
9692  // Check if bcd and cbe are both boundary faces.
9693  enextfnext(horiz, casing);
9694  tspivot(casing, cassh1);
9695  enext2fnext(symhoriz, casing);
9696  tspivot(casing, cassh2);
9697  if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9698  // bcd and cbe are both boundary faces. Check if bc is a segment.
9699  findedge(&cassh1, pb, pc);
9700  sspivot(cassh1, checkseg);
9701  if (checkseg.sh == dummysh) {
9702  // bc is not a segment - bcd and cbe belong to the same facet.
9703  // The four points are forced to be coplanar.
9704  ori2 = 0.0;
9705  } else {
9706  if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
9707  }
9708  } else {
9709  // bcd and cbe are not both boundary faces. Check if bcd and cbe
9710  // are approximately coplanar with respect to the epsilon.
9711  if (iscoplanar(pb, pc, pd, pe, ori2, b->epsilon)) ori2 = 0.0;
9712  }
9713  }
9714  if (ori2 < 0.0) {
9715  // e lies above bcd, unflipable, tet bcde is not present.
9716 #ifdef SELF_CHECK
9717  if (!nonconvex) {
9718  // bcd and cbe should not be hull faces, check it.
9719  enextfnext(horiz, casing);
9720  symself(casing);
9721  assert(casing.tet != dummytet);
9722  enext2fnext(symhoriz, casing);
9723  symself(casing);
9724  assert(casing.tet != dummytet);
9725  }
9726 #endif
9727  enextself(horiz);
9728  if (checksubfaces) {
9729  // The nonconvexbility may be casued by existing an subsegment.
9730  tsspivot(&horiz, &checkseg);
9731  if (checkseg.sh != dummysh) {
9732  return FORBIDDENEDGE;
9733  }
9734  }
9735  return N32;
9736  }
9737  ori3 = orient3d(pc, pa, pd, pe);
9738  if (checksubfaces && ori3 != 0.0) {
9739  // Check if cad and ace are both boundary faces.
9740  enext2fnext(horiz, casing);
9741  tspivot(casing, cassh1);
9742  enextfnext(symhoriz, casing);
9743  tspivot(casing, cassh2);
9744  if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9745  // cad and ace are both boundary faces. Check if ca is a segment.
9746  findedge(&cassh1, pc, pa);
9747  sspivot(cassh1, checkseg);
9748  if (checkseg.sh == dummysh) {
9749  // ca is not a segment - cad and ace belong to the same facet.
9750  // The four points are forced to be coplanar.
9751  ori3 = 0.0;
9752  } else {
9753  // ca is a segment - cad and ace belong to two different facets.
9754  // In principle, c, a, d and e can form a tetrahedron (since
9755  // ori3 != 0.0). Use a larger eps to test if they're coplanar.
9756  if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon * 1e+2)) ori3 = 0.0;
9757  }
9758  } else {
9759  // cad and ace are not both boundary faces. Check if cad and ace
9760  // are approximately coplanar with respect to the epsilon.
9761  if (iscoplanar(pc, pa, pd, pe, ori3, b->epsilon)) ori3 = 0.0;
9762  }
9763  }
9764  if (ori3 < 0.0) {
9765  // e lies above cad, unflipable, tet cade is not present.
9766 #ifdef SELF_CHECK
9767  if (!nonconvex) {
9768  // cad and ace should not be hull faces, check it.
9769  enext2fnext(horiz, casing);
9770  symself(casing);
9771  assert(casing.tet != dummytet);
9772  enextfnext(symhoriz, casing);
9773  symself(casing);
9774  assert(casing.tet != dummytet);
9775  }
9776 #endif
9777  enext2self(horiz);
9778  if (checksubfaces) {
9779  // The nonconvexbility may be casued by existing an subsegment.
9780  tsspivot(&horiz, &checkseg);
9781  if (checkseg.sh != dummysh) {
9782  return FORBIDDENEDGE;
9783  }
9784  }
9785  return N32;
9786  }
9787  if (ori1 == 0.0) {
9788  // e is coplanar with abd.
9789  if (ori2 * ori3 == 0.0) {
9790  // only one zero is possible.
9791  // assert(!(ori2 == 0.0 && ori3 == 0.0));
9792  // Three points (d, e, and a or b) are collinear, abc is unflipable
9793  // and locally Delaunay.
9794  return N40;
9795  }
9796  } else if (ori2 == 0.0) {
9797  // e is coplanar with bcd.
9798  if (ori1 * ori3 == 0.0) {
9799  // only one zero is possible.
9800  // assert(!(ori1 == 0.0 && ori3 == 0.0));
9801  // Three points (d, e, and b or c) are collinear, abc is unflipable
9802  // and locally Delaunay.
9803  return N40;
9804  }
9805  // Adjust 'horiz' and 'symhoriz' be the edge bc.
9806  enextself(horiz);
9807  enext2self(symhoriz);
9808  } else if (ori3 == 0.0) {
9809  // e is coplanar with cad.
9810  if (ori1 * ori2 == 0.0) {
9811  // only one zero is possible.
9812  // assert(!(ori1 == 0.0 && ori2 == 0.0));
9813  // Three points (d, e, and c or a) are collinear, abc is unflipable
9814  // and locally Delaunay.
9815  return N40;
9816  }
9817  // Adjust 'horiz' and 'symhoriz' be the edge ca.
9818  enext2self(horiz);
9819  enextself(symhoriz);
9820  } else {
9821  // e lies below all three faces, flipable.
9822  if (checksubfaces) {
9823  tspivot(horiz, checksh);
9824  if (checksh.sh != dummysh) {
9825  // To flip a subface is forbidden.
9826  return FORBIDDENFACE;
9827  }
9828  }
9829  return T23;
9830  }
9831  // Four points are coplanar, T22 or T44 is possible.
9832  if (checksubfaces) {
9833  tsspivot(&horiz, &checkseg);
9834  if (checkseg.sh != dummysh) {
9835  // To flip a subsegment is forbidden.
9836  return FORBIDDENEDGE;
9837  }
9838  tspivot(horiz, checksh);
9839  if (checksh.sh != dummysh) {
9840  // To flip a subface is forbidden.
9841  return FORBIDDENFACE;
9842  }
9843  }
9844  // Assume the four coplanar points are a, b, d, e, abd and abe are two
9845  // coplanar faces. If both abd and abe are hull faces, flipable(T22).
9846  // If they are interior faces, get the opposite tetrahedra abdf and
9847  // abeg, if f = g, flipable (T44). Otherwise, unflipable.
9848  pf = pg = (point) NULL;
9849  fnext(horiz, casing);
9850  symself(casing);
9851  if (casing.tet != dummytet) {
9852  pf = oppo(casing);
9853  }
9854  fnext(symhoriz, casing);
9855  symself(casing);
9856  if (casing.tet != dummytet) {
9857  pg = oppo(casing);
9858  }
9859  if (pf == pg) {
9860  // Either T22 (pf == pg == NULL) or T44 (pf and pg) is possible.
9861  if (checksubfaces) {
9862  // Retreat the corner points a, b, and c.
9863  pa = org(horiz);
9864  pb = dest(horiz);
9865  pc = apex(horiz);
9866  // Be careful not to create an inverted tetrahedron. Check the case.
9867  ori1 = orient3d(pc, pd, pe, pa);
9868  if (ori1 <= 0) return N40;
9869  ori1 = orient3d(pd, pc, pe, pb);
9870  if (ori1 <= 0) return N40;
9871  if (pf != (point) NULL) {
9872  ori1 = orient3d(pd, pf, pe, pa);
9873  if (ori1 <= 0) return N40;
9874  ori1 = orient3d(pf, pd, pe, pb);
9875  if (ori1 <= 0) return N40;
9876  }
9877  }
9878  if (pf == (point) NULL) {
9879  // abd and abe are hull faces, flipable.
9880  return T22;
9881  } else {
9882  // abd and abe are interior faces, flipable.
9883 #ifdef SELF_CHECK
9884  assert(pf != (point) NULL);
9885 #endif
9886  return T44;
9887  }
9888  } else {
9889  // ab has more than four faces around it, unflipable.
9890  return N32;
9891  }
9892  } else if (adjtet == 1) {
9893  // One of its three edges is locally non-convex. Type T32 is possible.
9894  // Adjust current configuration so that edge ab is non-convex.
9895  if (bcdoppo == pe) {
9896  // Edge bc is non-convex. Adjust 'horiz' and 'symhoriz' be edge bc.
9897  enextself(horiz);
9898  enext2self(symhoriz);
9899  pa = org(horiz);
9900  pb = dest(horiz);
9901  pc = apex(horiz);
9902  } else if (cadoppo == pe) {
9903  // Edge ca is non-convex. Adjust 'horiz' and 'symhoriz' be edge ca.
9904  enext2self(horiz);
9905  enextself(symhoriz);
9906  pa = org(horiz);
9907  pb = dest(horiz);
9908  pc = apex(horiz);
9909  } else {
9910  // Edge ab is non-convex.
9911 #ifdef SELF_CHECK
9912  assert(abdoppo == pe);
9913 #endif
9914  } // Now ab is the non-convex edge.
9915  // In order to be flipable, ab should cross face cde. Check it.
9916  ori1 = orient3d(pc, pd, pe, pa);
9917  if (checksubfaces && ori1 != 0.0) {
9918  // Check if cad and ace are both boundary faces.
9919  enext2fnext(horiz, casing);
9920  tspivot(casing, cassh1);
9921  enextfnext(symhoriz, casing);
9922  tspivot(casing, cassh2);
9923  if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9924  // cad and ace are both boundary faces. Check if ca is a segment.
9925  findedge(&cassh1, pc, pa);
9926  sspivot(cassh1, checkseg);
9927  if (checkseg.sh == dummysh) {
9928  // ca is not a segment. cad and ace belong to the same facet.
9929  // The four points are forced to be coplanar.
9930  ori1 = 0.0;
9931  } else {
9932  // ca is a segment. cad and ace belong to different facets.
9933  // In principle, c, d, e, and a can form a tetrahedron (since
9934  // ori1 != 0.0). However, we should avoid to create a very
9935  // flat tet. Use a larger epsilon to test if they're coplanar.
9936  if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon * 1e+2)) ori1 = 0.0;
9937  }
9938  } else {
9939  // Check if c, d, e, and a are approximately coplanar.
9940  if (iscoplanar(pc, pd, pe, pa, ori1, b->epsilon)) ori1 = 0.0;
9941  }
9942  }
9943  if (ori1 <= 0.0) {
9944  // a lies above or is coplanar cde, abc is locally Delaunay.
9945  return N40;
9946  }
9947  ori2 = orient3d(pd, pc, pe, pb);
9948  if (checksubfaces && ori2 != 0.0) {
9949  // Check if bcd and cbe are both boundary faces.
9950  enextfnext(horiz, casing);
9951  tspivot(casing, cassh1);
9952  enext2fnext(symhoriz, casing);
9953  tspivot(casing, cassh2);
9954  if (cassh1.sh != dummysh && cassh2.sh != dummysh) {
9955  // bcd and cbe are both boundary faces. Check if bc is a segment.
9956  findedge(&cassh1, pb, pc);
9957  sspivot(cassh1, checkseg);
9958  if (checkseg.sh == dummysh) {
9959  // bc is not a segment. bcd and cbe belong to the same facet.
9960  // The four points are forced to be coplanar.
9961  ori2 = 0.0;
9962  } else {
9963  // bc is a segment. bcd and cbe belong to different facets.
9964  // In principle, d, c, e, and b can form a tetrahedron (since
9965  // ori2 != 0.0). However, we should avoid to create a very
9966  // flat tet. Use a larger epsilon to test if they're coplanar.
9967  if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon * 1e+2)) ori2 = 0.0;
9968  }
9969  } else {
9970  // Check if d, c, e, and b are approximately coplanar.
9971  if (iscoplanar(pd, pc, pe, pb, ori2, b->epsilon)) ori2 = 0.0;
9972  }
9973  }
9974  if (ori2 <= 0.0) {
9975  // b lies above dce, unflipable, and abc is locally Delaunay.
9976  return N40;
9977  }
9978  // Edge ab crosses face cde properly.
9979  if (checksubfaces) {
9980  // If abc is subface, then ab must be a subsegment (because abde is
9981  // a tetrahedron and ab crosses cde properly).
9982  tsspivot(&horiz, &checkseg);
9983  if (checkseg.sh != dummysh) {
9984  // To flip a subsegment is forbidden.
9985  return FORBIDDENEDGE;
9986  }
9987  // Both abd and bae should not be subfaces (because they're not
9988  // coplanar and ab is not a subsegment). However, they may be
9989  // subfaces and belong to a facet (created during facet recovery),
9990  // that is, abde is an invalid tetrahedron. Find this case out.
9991  fnext(horiz, casing);
9992  tspivot(casing, cassh1);
9993  fnext(symhoriz, casing);
9994  tspivot(casing, cassh2);
9995  if (cassh1.sh != dummysh || cassh2.sh != dummysh) {
9996  if (!b->quiet) {
9997  // Unfortunately, they're subfaces. Corrections need be done here.
9998  printf("Warning: A tetrahedron spans two subfaces of a facet.\n");
9999  }
10000  // Temporarily, let it be there.
10001  return N32;
10002  }
10003  }
10004  return T32;
10005  } else {
10006  // The convex hull of {a, b, c, d, e} has only four vertices, abc is
10007  // unflipable, furthermore, it is locally Delaunay.
10008  return N40;
10009  }
10010 }
10011 
10013 // //
10014 // enqueueflipface(), enqueueflipedge() Queue a face (or an edge). //
10015 // //
10016 // The face (or edge) may be non-locally Delaunay. It is queued for process- //
10017 // ing in flip() (or flipsub()). The vertices of the face (edge) are stored //
10018 // seperatly to ensure the face (or edge) is still the same one when we save //
10019 // it since other flips will cause this face (or edge) be changed or dead. //
10020 // //
10022 
10023 void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue)
10024 {
10025  badface *queface;
10026  triface symface;
10027 
10028  sym(checkface, symface);
10029  if (symface.tet != dummytet) {
10030  queface = (badface *) flipqueue->push((void *) NULL);
10031  queface->tt = checkface;
10032  queface->foppo = oppo(symface);
10033  }
10034 }
10035 
10036 void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue)
10037 {
10038  badface *queface;
10039 
10040  queface = (badface *) flipqueue->push((void *) NULL);
10041  queface->ss = checkedge;
10042  queface->forg = sorg(checkedge);
10043  queface->fdest = sdest(checkedge);
10044 }
10045 
10047 // //
10048 // flip23() Perform a 2-to-3 flip. //
10049 // //
10050 // On input, 'flipface' represents the face will be flipped. Let it is abc, //
10051 // the two tetrahedra sharing abc are abcd, bace. abc is not a subface. //
10052 // //
10053 // A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra //
10054 // edab, edbc, and edca. As a result, face abc has been removed and three //
10055 // new faces eda, edb and edc have been created. //
10056 // //
10057 // On completion, 'flipface' returns edab. If 'flipqueue' is not NULL, all //
10058 // possibly non-Delaunay faces are added into it. //
10059 // //
10061 
10062 void tetgenmesh::flip23(triface* flipface, queue* flipqueue)
10063 {
10064  triface abcd, bace; // Old configuration.
10065  triface oldabd, oldbcd, oldcad;
10066  triface abdcasing, bcdcasing, cadcasing;
10067  triface oldbae, oldcbe, oldace;
10068  triface baecasing, cbecasing, acecasing;
10069  triface worktet;
10070  face abdsh, bcdsh, cadsh; // The six subfaces on the CH.
10071  face baesh, cbesh, acesh;
10072  face abseg, bcseg, caseg; // The nine segs on the CH.
10073  face adseg, bdseg, cdseg;
10074  face aeseg, beseg, ceseg;
10075  triface edab, edbc, edca; // New configuration.
10076  point pa, pb, pc, pd, pe;
10077  REAL attrib, volume;
10078  int i;
10079 
10080  abcd = *flipface;
10081  adjustedgering(abcd, CCW); // abcd represents edge ab.
10082  pa = org(abcd);
10083  pb = dest(abcd);
10084  pc = apex(abcd);
10085  pd = oppo(abcd);
10086  // sym(abcd, bace);
10087  // findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba.
10088  sym(abcd, bace);
10089  bace.ver = 0; // CCW.
10090  for (i = 0; (i < 3) && (org(bace) != pb); i++) {
10091  enextself(bace);
10092  }
10093  pe = oppo(bace);
10094 
10095  if (b->verbose > 2) {
10096  printf(" Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa),
10097  pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe));
10098  }
10099  flip23s++;
10100 
10101  // Storing the old configuration outside the convex hull.
10102  fnext(abcd, oldabd);
10103  enextfnext(abcd, oldbcd);
10104  enext2fnext(abcd, oldcad);
10105  fnext(bace, oldbae);
10106  enext2fnext(bace, oldcbe);
10107  enextfnext(bace, oldace);
10108  sym(oldabd, abdcasing);
10109  sym(oldbcd, bcdcasing);
10110  sym(oldcad, cadcasing);
10111  sym(oldbae, baecasing);
10112  sym(oldcbe, cbecasing);
10113  sym(oldace, acecasing);
10114  if (checksubfaces) {
10115  tspivot(oldabd, abdsh);
10116  tspivot(oldbcd, bcdsh);
10117  tspivot(oldcad, cadsh);
10118  tspivot(oldbae, baesh);
10119  tspivot(oldcbe, cbesh);
10120  tspivot(oldace, acesh);
10121  } else if (checksubsegs) {
10122  tsspivot1(abcd, abseg);
10123  enext(abcd, worktet);
10124  tsspivot1(worktet, bcseg);
10125  enext2(abcd, worktet);
10126  tsspivot1(worktet, caseg);
10127  enext2(oldabd, worktet);
10128  tsspivot1(worktet, adseg);
10129  enext2(oldbcd, worktet);
10130  tsspivot1(worktet, bdseg);
10131  enext2(oldcad, worktet);
10132  tsspivot1(worktet, cdseg);
10133  enext(oldbae, worktet);
10134  tsspivot1(worktet, aeseg);
10135  enext(oldcbe, worktet);
10136  tsspivot1(worktet, beseg);
10137  enext(oldace, worktet);
10138  tsspivot1(worktet, ceseg);
10139  }
10140 
10141  // Creating the new configuration inside the convex hull.
10142  edab.tet = abcd.tet; // Update abcd to be edab.
10143  setorg (edab, pe);
10144  setdest(edab, pd);
10145  setapex(edab, pa);
10146  setoppo(edab, pb);
10147  edbc.tet = bace.tet; // Update bace to be edbc.
10148  setorg (edbc, pe);
10149  setdest(edbc, pd);
10150  setapex(edbc, pb);
10151  setoppo(edbc, pc);
10152  maketetrahedron(&edca); // Create edca.
10153  setorg (edca, pe);
10154  setdest(edca, pd);
10155  setapex(edca, pc);
10156  setoppo(edca, pa);
10157  // Set the element attributes of the new tetrahedron 'edca'.
10158  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
10159  attrib = elemattribute(abcd.tet, i);
10160  setelemattribute(edca.tet, i, attrib);
10161  }
10162  // Set the volume constraint of the new tetrahedron 'edca' if the -ra
10163  // switches are not used together. In -ra case, the various volume
10164  // constraints can be spreaded very far.
10165  if (b->varvolume && !b->refine) {
10166  volume = volumebound(abcd.tet);
10167  setvolumebound(edca.tet, volume);
10168  }
10169 
10170  // Clear old bonds in edab(was abcd) and edbc(was bace).
10171  for (i = 0; i < 4; i ++) {
10172  edab.tet[i] = (tetrahedron) dummytet;
10173  }
10174  for (i = 0; i < 4; i ++) {
10175  edbc.tet[i] = (tetrahedron) dummytet;
10176  }
10177  // Bond the faces inside the convex hull.
10178  edab.loc = 0;
10179  edca.loc = 1;
10180  bond(edab, edca);
10181  edab.loc = 1;
10182  edbc.loc = 0;
10183  bond(edab, edbc);
10184  edbc.loc = 1;
10185  edca.loc = 0;
10186  bond(edbc, edca);
10187  // Bond the faces on the convex hull.
10188  edab.loc = 2;
10189  bond(edab, abdcasing);
10190  edab.loc = 3;
10191  bond(edab, baecasing);
10192  edbc.loc = 2;
10193  bond(edbc, bcdcasing);
10194  edbc.loc = 3;
10195  bond(edbc, cbecasing);
10196  edca.loc = 2;
10197  bond(edca, cadcasing);
10198  edca.loc = 3;
10199  bond(edca, acecasing);
10200  // There may exist subfaces that need to be bonded to new configuarton.
10201  if (checksubfaces) {
10202  // Clear old flags in edab(was abcd) and edbc(was bace).
10203  for (i = 0; i < 4; i ++) {
10204  edab.loc = i;
10205  tsdissolve(edab);
10206  edbc.loc = i;
10207  tsdissolve(edbc);
10208  }
10209  if (abdsh.sh != dummysh) {
10210  edab.loc = 2;
10211  tsbond(edab, abdsh);
10212  }
10213  if (baesh.sh != dummysh) {
10214  edab.loc = 3;
10215  tsbond(edab, baesh);
10216  }
10217  if (bcdsh.sh != dummysh) {
10218  edbc.loc = 2;
10219  tsbond(edbc, bcdsh);
10220  }
10221  if (cbesh.sh != dummysh) {
10222  edbc.loc = 3;
10223  tsbond(edbc, cbesh);
10224  }
10225  if (cadsh.sh != dummysh) {
10226  edca.loc = 2;
10227  tsbond(edca, cadsh);
10228  }
10229  if (acesh.sh != dummysh) {
10230  edca.loc = 3;
10231  tsbond(edca, acesh);
10232  }
10233  } else if (checksubsegs) {
10234  for (i = 0; i < 6; i++) {
10235  edab.tet[8 + i] = (tetrahedron) dummysh;
10236  }
10237  for (i = 0; i < 6; i++) {
10238  edbc.tet[8 + i] = (tetrahedron) dummysh;
10239  }
10240  edab.loc = edab.ver = 0;
10241  edbc.loc = edab.ver = 0;
10242  edca.loc = edab.ver = 0;
10243  // Operate in tet edab (5 edges).
10244  enext(edab, worktet);
10245  tssbond1(worktet, adseg);
10246  enext2(edab, worktet);
10247  tssbond1(worktet, aeseg);
10248  fnext(edab, worktet);
10249  enextself(worktet);
10250  tssbond1(worktet, bdseg);
10251  enextself(worktet);
10252  tssbond1(worktet, beseg);
10253  enextfnext(edab, worktet);
10254  enextself(worktet);
10255  tssbond1(worktet, abseg);
10256  // Operate in tet edbc (5 edges)
10257  enext(edbc, worktet);
10258  tssbond1(worktet, bdseg);
10259  enext2(edbc, worktet);
10260  tssbond1(worktet, beseg);
10261  fnext(edbc, worktet);
10262  enextself(worktet);
10263  tssbond1(worktet, cdseg);
10264  enextself(worktet);
10265  tssbond1(worktet, ceseg);
10266  enextfnext(edbc, worktet);
10267  enextself(worktet);
10268  tssbond1(worktet, bcseg);
10269  // Operate in tet edca (5 edges)
10270  enext(edca, worktet);
10271  tssbond1(worktet, cdseg);
10272  enext2(edca, worktet);
10273  tssbond1(worktet, ceseg);
10274  fnext(edca, worktet);
10275  enextself(worktet);
10276  tssbond1(worktet, adseg);
10277  enextself(worktet);
10278  tssbond1(worktet, aeseg);
10279  enextfnext(edca, worktet);
10280  enextself(worktet);
10281  tssbond1(worktet, caseg);
10282  }
10283 
10284  edab.loc = 0;
10285  edbc.loc = 0;
10286  edca.loc = 0;
10287  if (b->verbose > 3) {
10288  printf(" Updating edab ");
10289  printtet(&edab);
10290  printf(" Updating edbc ");
10291  printtet(&edbc);
10292  printf(" Creating edca ");
10293  printtet(&edca);
10294  }
10295 
10296  if (flipqueue != (queue *) NULL) {
10297  enextfnext(edab, abdcasing);
10298  enqueueflipface(abdcasing, flipqueue);
10299  enext2fnext(edab, baecasing);
10300  enqueueflipface(baecasing, flipqueue);
10301  enextfnext(edbc, bcdcasing);
10302  enqueueflipface(bcdcasing, flipqueue);
10303  enext2fnext(edbc, cbecasing);
10304  enqueueflipface(cbecasing, flipqueue);
10305  enextfnext(edca, cadcasing);
10306  enqueueflipface(cadcasing, flipqueue);
10307  enext2fnext(edca, acecasing);
10308  enqueueflipface(acecasing, flipqueue);
10309  }
10310 
10311  // Save a live handle in 'recenttet'.
10312  recenttet = edbc;
10313  // Set the return handle be edab.
10314  *flipface = edab;
10315 }
10316 
10318 // //
10319 // flip32() Perform a 3-to-2 flip. //
10320 // //
10321 // On input, 'flipface' represents the face will be flipped. Let it is eda, //
10322 // where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,//
10323 // edbc, and edca. ed is not a subsegment. //
10324 // //
10325 // A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into //
10326 // another two tetrahedra abcd and bace. As a result, the edge ed has been //
10327 // removed and the face abc has been created. //
10328 // //
10329 // On completion, 'flipface' returns abcd. If 'flipqueue' is not NULL, all //
10330 // possibly non-Delaunay faces are added into it. //
10331 // //
10333 
10334 void tetgenmesh::flip32(triface* flipface, queue* flipqueue)
10335 {
10336  triface edab, edbc, edca; // Old configuration.
10337  triface oldabd, oldbcd, oldcad;
10338  triface abdcasing, bcdcasing, cadcasing;
10339  triface oldbae, oldcbe, oldace;
10340  triface baecasing, cbecasing, acecasing;
10341  triface worktet;
10342  face abdsh, bcdsh, cadsh;
10343  face baesh, cbesh, acesh;
10344  face abseg, bcseg, caseg; // The nine segs on the CH.
10345  face adseg, bdseg, cdseg;
10346  face aeseg, beseg, ceseg;
10347  triface abcd, bace; // New configuration.
10348  point pa, pb, pc, pd, pe;
10349  int i;
10350 
10351  edab = *flipface;
10352  adjustedgering(edab, CCW);
10353  pa = apex(edab);
10354  pb = oppo(edab);
10355  pd = dest(edab);
10356  pe = org(edab);
10357  fnext(edab, edbc);
10358  symself(edbc);
10359  edbc.ver = 0;
10360  for (i = 0; (i < 3) && (org(edbc) != pe); i++) {
10361  enextself(edbc);
10362  }
10363  pc = oppo(edbc);
10364  fnext(edbc, edca);
10365  symself(edca);
10366  edca.ver = 0;
10367  for (i = 0; (i < 3) && (org(edca) != pe); i++) {
10368  enextself(edca);
10369  }
10370 
10371  if (b->verbose > 2) {
10372  printf(" Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe),
10373  pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc));
10374  }
10375  flip32s++;
10376 
10377  // Storing the old configuration outside the convex hull.
10378  enextfnext(edab, oldabd);
10379  enext2fnext(edab, oldbae);
10380  enextfnext(edbc, oldbcd);
10381  enext2fnext(edbc, oldcbe);
10382  enextfnext(edca, oldcad);
10383  enext2fnext(edca, oldace);
10384  sym(oldabd, abdcasing);
10385  sym(oldbcd, bcdcasing);
10386  sym(oldcad, cadcasing);
10387  sym(oldbae, baecasing);
10388  sym(oldcbe, cbecasing);
10389  sym(oldace, acecasing);
10390  if (checksubfaces) {
10391  tspivot(oldabd, abdsh);
10392  tspivot(oldbcd, bcdsh);
10393  tspivot(oldcad, cadsh);
10394  tspivot(oldbae, baesh);
10395  tspivot(oldcbe, cbesh);
10396  tspivot(oldace, acesh);
10397  } else if (checksubsegs) {
10398  enext(edab, worktet);
10399  tsspivot1(worktet, adseg);
10400  enext2(edab, worktet);
10401  tsspivot1(worktet, aeseg);
10402  enext(edbc, worktet);
10403  tsspivot1(worktet, bdseg);
10404  enext2(edbc, worktet);
10405  tsspivot1(worktet, beseg);
10406  enext(edca, worktet);
10407  tsspivot1(worktet, cdseg);
10408  enext2(edca, worktet);
10409  tsspivot1(worktet, ceseg);
10410  enextfnext(edab, worktet);
10411  enextself(worktet);
10412  tsspivot1(worktet, abseg);
10413  enextfnext(edbc, worktet);
10414  enextself(worktet);
10415  tsspivot1(worktet, bcseg);
10416  enextfnext(edca, worktet);
10417  enextself(worktet);
10418  tsspivot1(worktet, caseg);
10419  }
10420 
10421  // Creating the new configuration inside the convex hull.
10422  abcd.tet = edab.tet; // Update edab to be abcd.
10423  setorg (abcd, pa);
10424  setdest(abcd, pb);
10425  setapex(abcd, pc);
10426  setoppo(abcd, pd);
10427  bace.tet = edbc.tet; // Update edbc to be bace.
10428  setorg (bace, pb);
10429  setdest(bace, pa);
10430  setapex(bace, pc);
10431  setoppo(bace, pe);
10432  // Dealloc a redundant tetrahedron (edca).
10433  tetrahedrondealloc(edca.tet);
10434 
10435  // Clear the old bonds in abcd (was edab) and bace (was edbc).
10436  for (i = 0; i < 4; i ++) {
10437  abcd.tet[i] = (tetrahedron) dummytet;
10438  }
10439  for (i = 0; i < 4; i ++) {
10440  bace.tet[i] = (tetrahedron) dummytet;
10441  }
10442  // Bond the inside face of the convex hull.
10443  abcd.loc = 0;
10444  bace.loc = 0;
10445  bond(abcd, bace);
10446  // Bond the outside faces of the convex hull.
10447  abcd.loc = 1;
10448  bond(abcd, abdcasing);
10449  abcd.loc = 2;
10450  bond(abcd, bcdcasing);
10451  abcd.loc = 3;
10452  bond(abcd, cadcasing);
10453  bace.loc = 1;
10454  bond(bace, baecasing);
10455  bace.loc = 3;
10456  bond(bace, cbecasing);
10457  bace.loc = 2;
10458  bond(bace, acecasing);
10459  if (checksubfaces) {
10460  // Clear old bonds in abcd(was edab) and bace(was edbc).
10461  for (i = 0; i < 4; i ++) {
10462  abcd.tet[8 + i] = (tetrahedron) dummysh;
10463  }
10464  for (i = 0; i < 4; i ++) {
10465  bace.tet[8 + i] = (tetrahedron) dummysh;
10466  }
10467  if (abdsh.sh != dummysh) {
10468  abcd.loc = 1;
10469  tsbond(abcd, abdsh);
10470  }
10471  if (bcdsh.sh != dummysh) {
10472  abcd.loc = 2;
10473  tsbond(abcd, bcdsh);
10474  }
10475  if (cadsh.sh != dummysh) {
10476  abcd.loc = 3;
10477  tsbond(abcd, cadsh);
10478  }
10479  if (baesh.sh != dummysh) {
10480  bace.loc = 1;
10481  tsbond(bace, baesh);
10482  }
10483  if (cbesh.sh != dummysh) {
10484  bace.loc = 3;
10485  tsbond(bace, cbesh);
10486  }
10487  if (acesh.sh != dummysh) {
10488  bace.loc = 2;
10489  tsbond(bace, acesh);
10490  }
10491  } else if (checksubsegs) {
10492  for (i = 0; i < 6; i++) {
10493  abcd.tet[8 + i] = (tetrahedron) dummysh;
10494  }
10495  for (i = 0; i < 6; i++) {
10496  bace.tet[8 + i] = (tetrahedron) dummysh;
10497  }
10498  abcd.loc = abcd.ver = 0;
10499  bace.loc = bace.ver = 0;
10500  tssbond1(abcd, abseg); // 1
10501  enext(abcd, worktet);
10502  tssbond1(worktet, bcseg); // 2
10503  enext2(abcd, worktet);
10504  tssbond1(worktet, caseg); // 3
10505  fnext(abcd, worktet);
10506  enext2self(worktet);
10507  tssbond1(worktet, adseg); // 4
10508  enextfnext(abcd, worktet);
10509  enext2self(worktet);
10510  tssbond1(worktet, bdseg); // 5
10511  enext2fnext(abcd, worktet);
10512  enext2self(worktet);
10513  tssbond1(worktet, cdseg); // 6
10514  tssbond1(bace, abseg);
10515  enext2(bace, worktet);
10516  tssbond1(worktet, bcseg);
10517  enext(bace, worktet);
10518  tssbond1(worktet, caseg);
10519  fnext(bace, worktet);
10520  enextself(worktet);
10521  tssbond1(worktet, aeseg); // 7
10522  enext2fnext(bace, worktet);
10523  enextself(worktet);
10524  tssbond1(worktet, beseg); // 8
10525  enextfnext(bace, worktet);
10526  enextself(worktet);
10527  tssbond1(worktet, ceseg); // 9
10528  }
10529 
10530  abcd.loc = 0;
10531  bace.loc = 0;
10532  if (b->verbose > 3) {
10533  printf(" Updating abcd ");
10534  printtet(&abcd);
10535  printf(" Updating bace ");
10536  printtet(&bace);
10537  printf(" Deleting edca ");
10538  // printtet(&edca);
10539  }
10540 
10541  if (flipqueue != (queue *) NULL) {
10542  fnext(abcd, abdcasing);
10543  enqueueflipface(abdcasing, flipqueue);
10544  fnext(bace, baecasing);
10545  enqueueflipface(baecasing, flipqueue);
10546  enextfnext(abcd, bcdcasing);
10547  enqueueflipface(bcdcasing, flipqueue);
10548  enextfnext(bace, cbecasing);
10549  enqueueflipface(cbecasing, flipqueue);
10550  enext2fnext(abcd, cadcasing);
10551  enqueueflipface(cadcasing, flipqueue);
10552  enext2fnext(bace, acecasing);
10553  enqueueflipface(acecasing, flipqueue);
10554  }
10555 
10556  // Save a live handle in 'recenttet'.
10557  recenttet = abcd;
10558  // Set the return handle be abcd.
10559  *flipface = abcd;
10560 }
10561 
10563 // //
10564 // flip22() Perform a 2-to-2 (or 4-to-4) flip. //
10565 // //
10566 // On input, 'flipface' represents the face will be flipped. Let it is abe, //
10567 // ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,//
10568 // hence a, b, c and d are coplanar. If abc, bad are interior faces, the two //
10569 // tetrahedra opposite to e are bacf and abdf. ab is not a subsegment. //
10570 // //
10571 // A 2-to-2 flip is to change two tetrahedra abce and bade into another two //
10572 // tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf //
10573 // and dcbf, thus a 4-to-4 flip. As a result, two or four tetrahedra have //
10574 // rotated counterclockwise (using right-hand rule with thumb points to e): //
10575 // abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf. //
10576 // //
10577 // If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by //
10578 // calling routine flip22sub(), hence abc->dca, bad->cdb. The edge rings of //
10579 // the flipped subfaces dca and cdb have the same orientation as abc and bad.//
10580 // Hence, they have the same orientation as other subfaces of the facet with //
10581 // respect to the lift point of this facet. //
10582 // //
10583 // On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue' //
10584 // contains all possibly non-Delaunay faces if it is not NULL. //
10585 // //
10587 
10588 void tetgenmesh::flip22(triface* flipface, queue* flipqueue)
10589 {
10590  triface abce, bade;
10591  triface oldbce, oldcae, oldade, olddbe;
10592  triface bcecasing, caecasing, adecasing, dbecasing;
10593  face bcesh, caesh, adesh, dbesh;
10594  triface bacf, abdf;
10595  triface oldacf, oldcbf, oldbdf, olddaf;
10596  triface acfcasing, cbfcasing, bdfcasing, dafcasing;
10597  triface worktet;
10598  face acfsh, cbfsh, bdfsh, dafsh;
10599  face abc, bad;
10600  face adseg, dbseg, bcseg, caseg; // Coplanar segs.
10601  face aeseg, deseg, beseg, ceseg; // Above segs.
10602  face afseg, dfseg, bfseg, cfseg; // Below segs.
10603  point pa, pb, pc, pd;
10604 #ifdef SELF_CHECK
10605  point pe, pf;
10606 #endif
10607  int mirrorflag, i;
10608 
10609  adjustedgering(*flipface, CCW); // 'flipface' is bae.
10610  fnext(*flipface, abce);
10611  esymself(abce);
10612  adjustedgering(*flipface, CW); // 'flipface' is abe.
10613  fnext(*flipface, bade);
10614 #ifdef SELF_CHECK
10615  assert(bade.tet != dummytet);
10616 #endif
10617  esymself(bade);
10618  pa = org(abce);
10619  pb = dest(abce);
10620  pc = apex(abce);
10621  pd = apex(bade);
10622 #ifdef SELF_CHECK
10623  pe = oppo(bade);
10624  assert(oppo(abce) == pe);
10625 #endif
10626  sym(abce, bacf);
10627  mirrorflag = bacf.tet != dummytet;
10628  if (mirrorflag) {
10629  // findedge(&bacf, pb, pa);
10630  bacf.ver = 0;
10631  for (i = 0; (i < 3) && (org(bacf) != pb); i++) {
10632  enextself(bacf);
10633  }
10634  sym(bade, abdf);
10635 #ifdef SELF_CHECK
10636  assert(abdf.tet != dummytet);
10637 #endif
10638  // findedge(&abdf, pa, pb);
10639  abdf.ver = 0;
10640  for (i = 0; (i < 3) && (org(abdf) != pa); i++) {
10641  enextself(abdf);
10642  }
10643 
10644 #ifdef SELF_CHECK
10645  pf = oppo(bacf);
10646  assert(oppo(abdf) == pf);
10647 #endif
10648  }
10649 
10650  if (b->verbose > 2) {
10651  printf(" Do %s on edge (%d, %d).\n", mirrorflag ? "T44" : "T22",
10652  pointmark(pa), pointmark(pb));
10653  }
10654  mirrorflag ? flip44s++ : flip22s++;
10655 
10656  // Save the old configuration at the convex hull.
10657  enextfnext(abce, oldbce);
10658  enext2fnext(abce, oldcae);
10659  enextfnext(bade, oldade);
10660  enext2fnext(bade, olddbe);
10661  sym(oldbce, bcecasing);
10662  sym(oldcae, caecasing);
10663  sym(oldade, adecasing);
10664  sym(olddbe, dbecasing);
10665  if (checksubfaces) {
10666  tspivot(oldbce, bcesh);
10667  tspivot(oldcae, caesh);
10668  tspivot(oldade, adesh);
10669  tspivot(olddbe, dbesh);
10670  tspivot(abce, abc);
10671  tspivot(bade, bad);
10672  } else if (checksubsegs) {
10673  // Coplanar segs: a->d->b->c.
10674  enext(bade, worktet);
10675  tsspivot1(worktet, adseg);
10676  enext2(bade, worktet);
10677  tsspivot1(worktet, dbseg);
10678  enext(abce, worktet);
10679  tsspivot1(worktet, bcseg);
10680  enext2(abce, worktet);
10681  tsspivot1(worktet, caseg);
10682  // Above segs: a->e, d->e, b->e, c->e.
10683  fnext(bade, worktet);
10684  enextself(worktet);
10685  tsspivot1(worktet, aeseg);
10686  enextfnext(bade, worktet);
10687  enextself(worktet);
10688  tsspivot1(worktet, deseg);
10689  enext2fnext(bade, worktet);
10690  enextself(worktet);
10691  tsspivot1(worktet, beseg);
10692  enextfnext(abce, worktet);
10693  enextself(worktet);
10694  tsspivot1(worktet, ceseg);
10695  }
10696  if (mirrorflag) {
10697  enextfnext(bacf, oldacf);
10698  enext2fnext(bacf, oldcbf);
10699  enextfnext(abdf, oldbdf);
10700  enext2fnext(abdf, olddaf);
10701  sym(oldacf, acfcasing);
10702  sym(oldcbf, cbfcasing);
10703  sym(oldbdf, bdfcasing);
10704  sym(olddaf, dafcasing);
10705  if (checksubfaces) {
10706  tspivot(oldacf, acfsh);
10707  tspivot(oldcbf, cbfsh);
10708  tspivot(oldbdf, bdfsh);
10709  tspivot(olddaf, dafsh);
10710  } else if (checksubsegs) {
10711  // Below segs: a->f, d->f, b->f, c->f.
10712  fnext(abdf, worktet);
10713  enext2self(worktet);
10714  tsspivot1(worktet, afseg);
10715  enext2fnext(abdf, worktet);
10716  enext2self(worktet);
10717  tsspivot1(worktet, dfseg);
10718  enextfnext(abdf, worktet);
10719  enext2self(worktet);
10720  tsspivot1(worktet, bfseg);
10721  enextfnext(bacf, worktet);
10722  enextself(worktet);
10723  tsspivot1(worktet, cfseg);
10724  }
10725  }
10726 
10727  // Rotate abce, bade one-quarter turn counterclockwise.
10728  bond(oldbce, caecasing);
10729  bond(oldcae, adecasing);
10730  bond(oldade, dbecasing);
10731  bond(olddbe, bcecasing);
10732  if (checksubfaces) {
10733  // Check for subfaces and rebond them to the rotated tets.
10734  if (caesh.sh == dummysh) {
10735  tsdissolve(oldbce);
10736  } else {
10737  tsbond(oldbce, caesh);
10738  }
10739  if (adesh.sh == dummysh) {
10740  tsdissolve(oldcae);
10741  } else {
10742  tsbond(oldcae, adesh);
10743  }
10744  if (dbesh.sh == dummysh) {
10745  tsdissolve(oldade);
10746  } else {
10747  tsbond(oldade, dbesh);
10748  }
10749  if (bcesh.sh == dummysh) {
10750  tsdissolve(olddbe);
10751  } else {
10752  tsbond(olddbe, bcesh);
10753  }
10754  } else if (checksubsegs) {
10755  // 5 edges in abce are changed.
10756  enext(abce, worktet); // fit b->c into c->a.
10757  if (caseg.sh == dummysh) {
10758  tssdissolve1(worktet);
10759  } else {
10760  tssbond1(worktet, caseg);
10761  }
10762  enext2(abce, worktet); // fit c->a into a->d.
10763  if (adseg.sh == dummysh) {
10764  tssdissolve1(worktet);
10765  } else {
10766  tssbond1(worktet, adseg);
10767  }
10768  fnext(abce, worktet); // fit b->e into c->e.
10769  enextself(worktet);
10770  if (ceseg.sh == dummysh) {
10771  tssdissolve1(worktet);
10772  } else {
10773  tssbond1(worktet, ceseg);
10774  }
10775  enextfnext(abce, worktet); // fit c->e into a->e.
10776  enextself(worktet);
10777  if (aeseg.sh == dummysh) {
10778  tssdissolve1(worktet);
10779  } else {
10780  tssbond1(worktet, aeseg);
10781  }
10782  enext2fnext(abce, worktet); // fit a->e into d->e.
10783  enextself(worktet);
10784  if (deseg.sh == dummysh) {
10785  tssdissolve1(worktet);
10786  } else {
10787  tssbond1(worktet, deseg);
10788  }
10789  // 5 edges in bade are changed.
10790  enext(bade, worktet); // fit a->d into d->b.
10791  if (dbseg.sh == dummysh) {
10792  tssdissolve1(worktet);
10793  } else {
10794  tssbond1(worktet, dbseg);
10795  }
10796  enext2(bade, worktet); // fit d->b into b->c.
10797  if (bcseg.sh == dummysh) {
10798  tssdissolve1(worktet);
10799  } else {
10800  tssbond1(worktet, bcseg);
10801  }
10802  fnext(bade, worktet); // fit a->e into d->e.
10803  enextself(worktet);
10804  if (deseg.sh == dummysh) {
10805  tssdissolve1(worktet);
10806  } else {
10807  tssbond1(worktet, deseg);
10808  }
10809  enextfnext(bade, worktet); // fit d->e into b->e.
10810  enextself(worktet);
10811  if (beseg.sh == dummysh) {
10812  tssdissolve1(worktet);
10813  } else {
10814  tssbond1(worktet, beseg);
10815  }
10816  enext2fnext(bade, worktet); // fit b->e into c->e.
10817  enextself(worktet);
10818  if (ceseg.sh == dummysh) {
10819  tssdissolve1(worktet);
10820  } else {
10821  tssbond1(worktet, ceseg);
10822  }
10823  }
10824  if (mirrorflag) {
10825  // Rotate bacf, abdf one-quarter turn counterclockwise.
10826  bond(oldcbf, acfcasing);
10827  bond(oldacf, dafcasing);
10828  bond(olddaf, bdfcasing);
10829  bond(oldbdf, cbfcasing);
10830  if (checksubfaces) {
10831  // Check for subfaces and rebond them to the rotated tets.
10832  if (acfsh.sh == dummysh) {
10833  tsdissolve(oldcbf);
10834  } else {
10835  tsbond(oldcbf, acfsh);
10836  }
10837  if (dafsh.sh == dummysh) {
10838  tsdissolve(oldacf);
10839  } else {
10840  tsbond(oldacf, dafsh);
10841  }
10842  if (bdfsh.sh == dummysh) {
10843  tsdissolve(olddaf);
10844  } else {
10845  tsbond(olddaf, bdfsh);
10846  }
10847  if (cbfsh.sh == dummysh) {
10848  tsdissolve(oldbdf);
10849  } else {
10850  tsbond(oldbdf, cbfsh);
10851  }
10852  } else if (checksubsegs) {
10853  // 5 edges in bacf are changed.
10854  enext2(bacf, worktet); // fit b->c into c->a.
10855  if (caseg.sh == dummysh) {
10856  tssdissolve1(worktet);
10857  } else {
10858  tssbond1(worktet, caseg);
10859  }
10860  enext(bacf, worktet); // fit c->a into a->d.
10861  if (adseg.sh == dummysh) {
10862  tssdissolve1(worktet);
10863  } else {
10864  tssbond1(worktet, adseg);
10865  }
10866  fnext(bacf, worktet); // fit b->f into c->f.
10867  enext2self(worktet);
10868  if (cfseg.sh == dummysh) {
10869  tssdissolve1(worktet);
10870  } else {
10871  tssbond1(worktet, cfseg);
10872  }
10873  enext2fnext(bacf, worktet); // fit c->f into a->f.
10874  enext2self(worktet);
10875  if (afseg.sh == dummysh) {
10876  tssdissolve1(worktet);
10877  } else {
10878  tssbond1(worktet, afseg);
10879  }
10880  enextfnext(bacf, worktet); // fit a->f into d->f.
10881  enext2self(worktet);
10882  if (dfseg.sh == dummysh) {
10883  tssdissolve1(worktet);
10884  } else {
10885  tssbond1(worktet, dfseg);
10886  }
10887  // 5 edges in abdf are changed.
10888  enext2(abdf, worktet); // fit a->d into d->b.
10889  if (dbseg.sh == dummysh) {
10890  tssdissolve1(worktet);
10891  } else {
10892  tssbond1(worktet, dbseg);
10893  }
10894  enext(abdf, worktet); // fit d->b into b->c.
10895  if (bcseg.sh == dummysh) {
10896  tssdissolve1(worktet);
10897  } else {
10898  tssbond1(worktet, bcseg);
10899  }
10900  fnext(abdf, worktet); // fit a->f into d->f.
10901  enext2self(worktet);
10902  if (dfseg.sh == dummysh) {
10903  tssdissolve1(worktet);
10904  } else {
10905  tssbond1(worktet, dfseg);
10906  }
10907  enext2fnext(abdf, worktet); // fit d->f into b->f.
10908  enext2self(worktet);
10909  if (bfseg.sh == dummysh) {
10910  tssdissolve1(worktet);
10911  } else {
10912  tssbond1(worktet, bfseg);
10913  }
10914  enextfnext(abdf, worktet); // fit b->f into c->f.
10915  enext2self(worktet);
10916  if (cfseg.sh == dummysh) {
10917  tssdissolve1(worktet);
10918  } else {
10919  tssbond1(worktet, cfseg);
10920  }
10921  }
10922  }
10923 
10924  // New vertex assignments for the rotated tetrahedra.
10925  setorg(abce, pd); // Update abce to dcae
10926  setdest(abce, pc);
10927  setapex(abce, pa);
10928  setorg(bade, pc); // Update bade to cdbe
10929  setdest(bade, pd);
10930  setapex(bade, pb);
10931  if (mirrorflag) {
10932  setorg(bacf, pc); // Update bacf to cdaf
10933  setdest(bacf, pd);
10934  setapex(bacf, pa);
10935  setorg(abdf, pd); // Update abdf to dcbf
10936  setdest(abdf, pc);
10937  setapex(abdf, pb);
10938  }
10939 
10940  // Are there subfaces need to be flipped?
10941  if (checksubfaces && abc.sh != dummysh) {
10942 #ifdef SELF_CHECK
10943  assert(bad.sh != dummysh);
10944 #endif
10945  // Adjust the edge be ab, so the rotation of subfaces is according with
10946  // the rotation of tetrahedra.
10947  findedge(&abc, pa, pb);
10948  // Flip an edge of two subfaces, ignore non-Delaunay edges.
10949  flip22sub(&abc, NULL);
10950  }
10951 
10952  if (b->verbose > 3) {
10953  printf(" Updating abce ");
10954  printtet(&abce);
10955  printf(" Updating bade ");
10956  printtet(&bade);
10957  if (mirrorflag) {
10958  printf(" Updating bacf ");
10959  printtet(&bacf);
10960  printf(" Updating abdf ");
10961  printtet(&abdf);
10962  }
10963  }
10964 
10965  if (flipqueue != (queue *) NULL) {
10966  enextfnext(abce, bcecasing);
10967  enqueueflipface(bcecasing, flipqueue);
10968  enext2fnext(abce, caecasing);
10969  enqueueflipface(caecasing, flipqueue);
10970  enextfnext(bade, adecasing);
10971  enqueueflipface(adecasing, flipqueue);
10972  enext2fnext(bade, dbecasing);
10973  enqueueflipface(dbecasing, flipqueue);
10974  if (mirrorflag) {
10975  enextfnext(bacf, acfcasing);
10976  enqueueflipface(acfcasing, flipqueue);
10977  enext2fnext(bacf, cbfcasing);
10978  enqueueflipface(cbfcasing, flipqueue);
10979  enextfnext(abdf, bdfcasing);
10980  enqueueflipface(bdfcasing, flipqueue);
10981  enext2fnext(abdf, dafcasing);
10982  enqueueflipface(dafcasing, flipqueue);
10983  }
10984  // The two new faces dcae (abce), cdbe (bade) may still not be locally
10985  // Delaunay, and may need be flipped (flip23). On the other hand, in
10986  // conforming Delaunay algorithm, two new subfaces dca (abc), and cdb
10987  // (bad) may be non-conforming Delaunay, they need be queued if they
10988  // are locally Delaunay but non-conforming Delaunay.
10989  enqueueflipface(abce, flipqueue);
10990  enqueueflipface(bade, flipqueue);
10991  }
10992 
10993  // Save a live handle in 'recenttet'.
10994  recenttet = abce;
10995 }
10996 
10998 // //
10999 // flip22sub() Perform a 2-to-2 flip on a subface edge. //
11000 // //
11001 // The flip edge is given by subface 'flipedge'. Let it is abc, where ab is //
11002 // the flipping edge. The other subface is bad, where a, b, c, d form a //
11003 // convex quadrilateral. ab is not a subsegment. //
11004 // //
11005 // A 2-to-2 subface flip is to change two subfaces abc and bad to another //
11006 // two subfaces dca and cdb. Hence, edge ab has been removed and dc becomes //
11007 // an edge. If a point e is above abc, this flip is equal to rotate abc and //
11008 // bad counterclockwise using right-hand rule with thumb points to e. It is //
11009 // important to know that the edge rings of the flipped subfaces dca and cdb //
11010 // are keeping the same orientation as their original subfaces. So they have //
11011 // the same orientation with respect to the lift point of this facet. //
11012 // //
11013 // During rotating, the face rings of the four edges bc, ca, ad, and de need //
11014 // be re-connected. If the edge is not a subsegment, then its face ring has //
11015 // only two faces, a sbond() will bond them together. If it is a subsegment, //
11016 // one should use sbond1() twice to bond two different handles to the rotat- //
11017 // ing subface, one is predecssor (-casin), another is successor (-casout). //
11018 // //
11019 // If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which //
11020 // may be non-Delaunay. //
11021 // //
11023 
11024 void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue)
11025 {
11026  face abc, bad;
11027  face oldbc, oldca, oldad, olddb;
11028  face bccasin, bccasout, cacasin, cacasout;
11029  face adcasin, adcasout, dbcasin, dbcasout;
11030  face bc, ca, ad, db;
11031  face spinsh;
11032  point pa, pb, pc, pd;
11033 
11034  abc = *flipedge;
11035  spivot(abc, bad);
11036  if (sorg(bad) != sdest(abc)) {
11037  sesymself(bad);
11038  }
11039  pa = sorg(abc);
11040  pb = sdest(abc);
11041  pc = sapex(abc);
11042  pd = sapex(bad);
11043 
11044  if (b->verbose > 2) {
11045  printf(" Flip sub edge (%d, %d).\n", pointmark(pa), pointmark(pb));
11046  }
11047 
11048  // Save the old configuration outside the quadrilateral.
11049  senext(abc, oldbc);
11050  senext2(abc, oldca);
11051  senext(bad, oldad);
11052  senext2(bad, olddb);
11053  // Get the outside connection. Becareful if there is a subsegment on the
11054  // quadrilateral, two casings (casin and casout) are needed to save for
11055  // keeping the face link.
11056  spivot(oldbc, bccasout);
11057  sspivot(oldbc, bc);
11058  if (bc.sh != dummysh) {
11059  // 'bc' is a subsegment.
11060  if (bccasout.sh != dummysh) {
11061  if (oldbc.sh != bccasout.sh) {
11062  // 'oldbc' is not self-bonded.
11063  spinsh = bccasout;
11064  do {
11065  bccasin = spinsh;
11066  spivotself(spinsh);
11067  } while (spinsh.sh != oldbc.sh);
11068  } else {
11069  bccasout.sh = dummysh;
11070  }
11071  }
11072  ssdissolve(oldbc);
11073  }
11074  spivot(oldca, cacasout);
11075  sspivot(oldca, ca);
11076  if (ca.sh != dummysh) {
11077  // 'ca' is a subsegment.
11078  if (cacasout.sh != dummysh) {
11079  if (oldca.sh != cacasout.sh) {
11080  // 'oldca' is not self-bonded.
11081  spinsh = cacasout;
11082  do {
11083  cacasin = spinsh;
11084  spivotself(spinsh);
11085  } while (spinsh.sh != oldca.sh);
11086  } else {
11087  cacasout.sh = dummysh;
11088  }
11089  }
11090  ssdissolve(oldca);
11091  }
11092  spivot(oldad, adcasout);
11093  sspivot(oldad, ad);
11094  if (ad.sh != dummysh) {
11095  // 'ad' is a subsegment.
11096  if (adcasout.sh != dummysh) {
11097  if (oldad.sh != adcasout.sh) {
11098  // 'adcasout' is not self-bonded.
11099  spinsh = adcasout;
11100  do {
11101  adcasin = spinsh;
11102  spivotself(spinsh);
11103  } while (spinsh.sh != oldad.sh);
11104  } else {
11105  adcasout.sh = dummysh;
11106  }
11107  }
11108  ssdissolve(oldad);
11109  }
11110  spivot(olddb, dbcasout);
11111  sspivot(olddb, db);
11112  if (db.sh != dummysh) {
11113  // 'db' is a subsegment.
11114  if (dbcasout.sh != dummysh) {
11115  if (olddb.sh != dbcasout.sh) {
11116  // 'dbcasout' is not self-bonded.
11117  spinsh = dbcasout;
11118  do {
11119  dbcasin = spinsh;
11120  spivotself(spinsh);
11121  } while (spinsh.sh != olddb.sh);
11122  } else {
11123  dbcasout.sh = dummysh;
11124  }
11125  }
11126  ssdissolve(olddb);
11127  }
11128 
11129  // Rotate abc and bad one-quarter turn counterclockwise.
11130  if (ca.sh != dummysh) {
11131  if (cacasout.sh != dummysh) {
11132  sbond1(cacasin, oldbc);
11133  sbond1(oldbc, cacasout);
11134  } else {
11135  // Bond 'oldbc' to itself.
11136  sbond(oldbc, oldbc);
11137  // Make sure that dummysh always correctly bonded.
11138  dummysh[0] = sencode(oldbc);
11139  }
11140  ssbond(oldbc, ca);
11141  } else {
11142  sbond(oldbc, cacasout);
11143  }
11144  if (ad.sh != dummysh) {
11145  if (adcasout.sh != dummysh) {
11146  sbond1(adcasin, oldca);
11147  sbond1(oldca, adcasout);
11148  } else {
11149  // Bond 'oldca' to itself.
11150  sbond(oldca, oldca);
11151  // Make sure that dummysh always correctly bonded.
11152  dummysh[0] = sencode(oldca);
11153  }
11154  ssbond(oldca, ad);
11155  } else {
11156  sbond(oldca, adcasout);
11157  }
11158  if (db.sh != dummysh) {
11159  if (dbcasout.sh != dummysh) {
11160  sbond1(dbcasin, oldad);
11161  sbond1(oldad, dbcasout);
11162  } else {
11163  // Bond 'oldad' to itself.
11164  sbond(oldad, oldad);
11165  // Make sure that dummysh always correctly bonded.
11166  dummysh[0] = sencode(oldad);
11167  }
11168  ssbond(oldad, db);
11169  } else {
11170  sbond(oldad, dbcasout);
11171  }
11172  if (bc.sh != dummysh) {
11173  if (bccasout.sh != dummysh) {
11174  sbond1(bccasin, olddb);
11175  sbond1(olddb, bccasout);
11176  } else {
11177  // Bond 'olddb' to itself.
11178  sbond(olddb, olddb);
11179  // Make sure that dummysh always correctly bonded.
11180  dummysh[0] = sencode(olddb);
11181  }
11182  ssbond(olddb, bc);
11183  } else {
11184  sbond(olddb, bccasout);
11185  }
11186 
11187  // New vertex assignments for the rotated subfaces.
11188  setsorg(abc, pd); // Update abc to dca.
11189  setsdest(abc, pc);
11190  setsapex(abc, pa);
11191  setsorg(bad, pc); // Update bad to cdb.
11192  setsdest(bad, pd);
11193  setsapex(bad, pb);
11194 
11195  if (flipqueue != (queue *) NULL) {
11196  enqueueflipedge(bccasout, flipqueue);
11197  enqueueflipedge(cacasout, flipqueue);
11198  enqueueflipedge(adcasout, flipqueue);
11199  enqueueflipedge(dbcasout, flipqueue);
11200  }
11201 }
11202 
11204 // //
11205 // flip() Flips non-locally Delaunay faces in flipqueue until it is empty.//
11206 // //
11207 // Assumpation: Current tetrahedralization is non-Delaunay after inserting //
11208 // a point or performing a flip operation, all possibly non-Delaunay faces //
11209 // are in 'flipqueue'. //
11210 // //
11211 // If 'plastflip' is not NULL, it is used to return a stack of recently //
11212 // flipped faces. This stack will be used to reverse the flips done in this //
11213 // routine later for removing a newly inserted point because it encroaches //
11214 // any subfaces or subsegments. //
11215 // //
11216 // The return value is the total number of flips done during this invocation.//
11217 // //
11219 
11220 long tetgenmesh::flip(queue* flipqueue, badface **plastflip)
11221 {
11222  badface *qface, *newflip;
11223  triface flipface, symface;
11224  point pa, pb, pc, pd, pe;
11225  enum fliptype fc;
11226  REAL sign, bakepsilon;
11227  long flipcount; //, maxfaces; - commented out to get gcc4.6 working
11228  int epscount, fcount;
11229  int ia, ib, ic, id, ie;
11230 
11231  if (b->verbose > 1) {
11232  printf(" Do flipface queue: %ld faces.\n", flipqueue->len());
11233  }
11234 
11235  flipcount = flip23s + flip32s + flip22s + flip44s;
11236  if (checksubfaces) {
11237  //maxfaces = (4l * tetrahedrons->items + hullsize) / 2l; // commented out to get gcc 4.6 working
11238  fcount = 0;
11239  }
11240 
11241  if (plastflip != (badface **) NULL) {
11242  // Initialize the stack of the flip sequence.
11243  flipstackers->restart();
11244  *plastflip = (badface *) NULL;
11245  }
11246 
11247  // Loop until the queue is empty.
11248  while (!flipqueue->empty()) {
11249  qface = (badface *) flipqueue->pop();
11250  flipface = qface->tt;
11251  if (isdead(&flipface)) continue;
11252  sym(flipface, symface);
11253  // Only do check when the adjacent tet exists and it's not a "fake" tet.
11254  if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
11255  // For positive orientation that insphere() test requires.
11256  adjustedgering(flipface, CW);
11257  pa = org(flipface);
11258  pb = dest(flipface);
11259  pc = apex(flipface);
11260  pd = oppo(flipface);
11261  pe = oppo(symface);
11262  if (symbolic) {
11263  ia = pointmark(pa);
11264  ib = pointmark(pb);
11265  ic = pointmark(pc);
11266  id = pointmark(pd);
11267  ie = pointmark(pe);
11268  sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
11269  assert(sign != 0.0);
11270  } else {
11271  sign = insphere(pa, pb, pc, pd, pe);
11272  }
11273  } else {
11274  sign = -1.0; // A hull face is locally Delaunay.
11275  }
11276  if (sign > 0.0) {
11277  // 'flipface' is non-locally Delaunay, try to flip it.
11278  if (checksubfaces) {
11279  fcount++;
11280  bakepsilon = b->epsilon;
11281  epscount = 0;
11282  while (epscount < 32) {
11283  fc = categorizeface(flipface);
11284  if (fc == N40) {
11285  b->epsilon *= 1e-1;
11286  epscount++;
11287  continue;
11288  }
11289  break;
11290  }
11291  b->epsilon = bakepsilon;
11292  if (epscount >= 32) {
11293  if (b->verbose > 0) {
11294  printf("Warning: Can't flip a degenerate tetrahedron.\n");
11295  }
11296  fc = N40;
11297  }
11298  } else {
11299  fc = categorizeface(flipface);
11300 #ifdef SELF_CHECK
11301  assert(fc != N40);
11302 #endif
11303  }
11304  switch (fc) {
11305  // The following face types are flipable.
11306  case T44:
11307  case T22:
11308  flip22(&flipface, flipqueue);
11309  break;
11310  case T23:
11311  flip23(&flipface, flipqueue);
11312  break;
11313  case T32:
11314  flip32(&flipface, flipqueue);
11315  break;
11316  // The following face types are unflipable.
11317  case N32:
11318  break;
11319  case FORBIDDENFACE:
11320  break;
11321  case FORBIDDENEDGE:
11322  break;
11323  // This case is only possible when the domain is nonconvex.
11324  case N40:
11325  // assert(nonconvex);
11326  break;
11327  }
11328  if (plastflip != (badface **) NULL) {
11329  if ((fc == T44) || (fc == T22) || (fc == T23) || (fc == T32)) {
11330  // Push the flipped face into stack.
11331  newflip = (badface *) flipstackers->alloc();
11332  newflip->tt = flipface;
11333  newflip->key = (REAL) fc;
11334  newflip->forg = org(flipface);
11335  newflip->fdest = dest(flipface);
11336  newflip->fapex = apex(flipface);
11337  newflip->previtem = *plastflip;
11338  *plastflip = newflip;
11339  }
11340  }
11341  }
11342  }
11343 
11344  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
11345  if (b->verbose > 1) {
11346  printf(" %ld flips.\n", flipcount);
11347  }
11348 
11349  return flipcount;
11350 }
11351 
11353 // //
11354 // lawson() Flip locally non-Delaunay faces by Lawson's algorithm. //
11355 // //
11357 
11358 long tetgenmesh::lawson(list *misseglist, queue* flipqueue)
11359 {
11360  badface *qface, *misseg;
11361  triface flipface, symface;
11362  triface starttet, spintet;
11363  face checksh, checkseg;
11364  point pa, pb, pc, pd, pe;
11365  point swappt;
11366  REAL sign, ori;
11367  long flipcount;
11368  int ia, ib, ic, id, ie;
11369  int hitbdry, i;
11370 
11371  if (b->verbose > 1) {
11372  printf(" Do flipface queue: %ld faces.\n", flipqueue->len());
11373  }
11374  flipcount = flip23s + flip32s + flip22s + flip44s;
11375 
11376  // Go through the stack of possible flips and decide whether to do them.
11377  // Note that during the loop new possible flips will be pushed onto
11378  // this stack, while they popped in this loop.
11379  while (!flipqueue->empty()) {
11380  qface = (badface *) flipqueue->pop();
11381  flipface = qface->tt;
11382  // Check if tet has already been flipped out of existence.
11383  if (!isdead(&flipface)) {
11384  sym(flipface, symface);
11385  // Check if this tet is the same as the one which was stacked.
11386  if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) {
11387  flipface.ver = 0; // Select the CCW ring.
11388  pa = org(flipface);
11389  pb = dest(flipface);
11390  pc = apex(flipface);
11391  pd = oppo(flipface);
11392  pe = oppo(symface);
11393  if (symbolic) {
11394  ia = pointmark(pa);
11395  ib = pointmark(pb);
11396  ic = pointmark(pc);
11397  id = pointmark(pd);
11398  ie = pointmark(pe);
11399  sign = insphere_sos(pb, pa, pc, pd, pe, ib, ia, ic, id, ie);
11400  } else {
11401  sign = insphere(pb, pa, pc, pd, pe);
11402  }
11403  if (sign > 0.0) {
11404  for (i = 0; i < 3; i++) {
11405  ori = orient3d(pa, pb, pd, pe);
11406  if (ori > 0.0) {
11407  // Goto and check the next edge.
11408  swappt = pa;
11409  pa = pb;
11410  pb = pc;
11411  pc = swappt;
11412  enextself(flipface);
11413  } else {
11414  break; // either (ori < 0.0) or (ori == 0.0)
11415  }
11416  } // for (i = 0; ....)
11417  if (ori > 0.0) {
11418  // All three edges are convex, a 2-3 flip is possible.
11419  if (checksubfaces) {
11420  tspivot(flipface, checksh);
11421  if (checksh.sh != dummysh) {
11422  // A subface is not flipable.
11423  continue;
11424  }
11425  }
11426  flip23(&flipface, flipqueue);
11427  } else if (ori < 0.0) {
11428  // The edge (a, b) is non-convex, check for a 3-2 flip.
11429  fnext(flipface, symface);
11430  symself(symface);
11431  if (oppo(symface) == pe) {
11432  // Only three tets adjoining this edge.
11433  if (checksubfaces) {
11434  tsspivot(&flipface, &checkseg);
11435  if (checkseg.sh != dummysh) {
11436  // A subsegment is not flipable.
11437  continue;
11438  }
11439  } else if (checksubsegs) {
11440  tsspivot1(flipface, checkseg);
11441  if (checkseg.sh != dummysh) {
11442  if (b->verbose > 2) {
11443  printf(" Queuing missing segment (%d, %d).\n",
11444  pointmark(org(flipface)), pointmark(dest(flipface)));
11445  }
11446  misseg = (badface *) misseglist->append(NULL);
11447  misseg->ss = checkseg;
11448  misseg->forg = sorg(checkseg);
11449  misseg->fdest = sdest(checkseg);
11450  // Detach all tets having this seg.
11451  starttet = flipface;
11452  adjustedgering(starttet, CCW);
11453  fnextself(starttet);
11454  spintet = starttet;
11455  hitbdry = 0;
11456  do {
11457  tssdissolve1(spintet);
11458  if (!fnextself(spintet)) {
11459  hitbdry++;
11460  if (hitbdry < 2) {
11461  esym(starttet, spintet);
11462  if (!fnextself(spintet)) {
11463  hitbdry++;
11464  }
11465  }
11466  }
11467  } while ((apex(spintet) != apex(starttet)) && (hitbdry < 2));
11468  }
11469  } // if (checksubfaces)
11470  flip32(&flipface, flipqueue);
11471  }
11472  } else {
11473  // Four points (a, b, d, e) are coplanar.
11474  fnext(flipface, symface);
11475  if (fnextself(symface)) {
11476  // Check for a 4-4 flip.
11477  fnextself(symface);
11478  if (apex(symface) == pe) {
11479  if (checksubfaces) {
11480  tsspivot(&flipface, &checkseg);
11481  if (checkseg.sh != dummysh) {
11482  // A subsegment is not flippable.
11483  continue;
11484  }
11485  } else if (checksubsegs) {
11486  tsspivot1(flipface, checkseg);
11487  if (checkseg.sh != dummysh) {
11488  if (b->verbose > 2) {
11489  printf(" Queuing missing segment (%d, %d).\n",
11490  pointmark(org(flipface)), pointmark(dest(flipface)));
11491  }
11492  misseg = (badface *) misseglist->append(NULL);
11493  misseg->ss = checkseg;
11494  misseg->forg = sorg(checkseg);
11495  misseg->fdest = sdest(checkseg);
11496  // Detach all tets having this seg.
11497  starttet = flipface;
11498  adjustedgering(starttet, CCW);
11499  fnextself(starttet);
11500  spintet = starttet;
11501  hitbdry = 0;
11502  do {
11503  tssdissolve1(spintet);
11504  if (!fnextself(spintet)) {
11505  hitbdry++;
11506  if (hitbdry < 2) {
11507  esym(starttet, spintet);
11508  if (!fnextself(spintet)) {
11509  hitbdry++;
11510  }
11511  }
11512  }
11513  } while ((apex(spintet) != apex(starttet)) &&
11514  (hitbdry < 2));
11515  }
11516  } // if (checksubfaces)
11517  flip22(&flipface, flipqueue);
11518  }
11519  } else {
11520  // Check for a 2-2 flip.
11521  esym(flipface, symface);
11522  fnextself(symface);
11523  symself(symface);
11524  if (symface.tet == dummytet) {
11525  if (checksubfaces) {
11526  tsspivot(&flipface, &checkseg);
11527  if (checkseg.sh != dummysh) {
11528  // A subsegment is not flipable.
11529  continue;
11530  }
11531  } else if (checksubsegs) {
11532  tsspivot1(flipface, checkseg);
11533  if (checkseg.sh != dummysh) {
11534  if (b->verbose > 2) {
11535  printf(" Queuing missing segment (%d, %d).\n",
11536  pointmark(org(flipface)), pointmark(dest(flipface)));
11537  }
11538  misseg = (badface *) misseglist->append(NULL);
11539  misseg->ss = checkseg;
11540  misseg->forg = sorg(checkseg);
11541  misseg->fdest = sdest(checkseg);
11542  // Detach all tets having this seg.
11543  starttet = flipface;
11544  adjustedgering(starttet, CCW);
11545  fnextself(starttet);
11546  spintet = starttet;
11547  hitbdry = 0;
11548  do {
11549  tssdissolve1(spintet);
11550  if (!fnextself(spintet)) {
11551  hitbdry++;
11552  if (hitbdry < 2) {
11553  esym(starttet, spintet);
11554  if (!fnextself(spintet)) {
11555  hitbdry++;
11556  }
11557  }
11558  }
11559  } while ((apex(spintet) != apex(starttet)) &&
11560  (hitbdry < 2));
11561  }
11562  } // if (checksubfaces)
11563  flip22(&flipface, flipqueue);
11564  }
11565  }
11566  } // if (ori > 0.0)
11567  } // if (sign > 0.0)
11568  }
11569  } // !isdead(&qface->tt)
11570  } // while (!flipqueue->empty())
11571 
11572  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
11573  if (b->verbose > 1) {
11574  printf(" %ld flips.\n", flipcount);
11575  }
11576  return flipcount;
11577 }
11578 
11580 // //
11581 // undoflip() Undo the most recent flip sequence induced by flip(). //
11582 // //
11583 // 'lastflip' is the stack of recently flipped faces. Walks through the list //
11584 // of flips, in the reverse of the order in which they were done, and undoes //
11585 // them. //
11586 // //
11588 
11589 void tetgenmesh::undoflip(badface *lastflip)
11590 {
11591  enum fliptype fc;
11592 
11593  while (lastflip != (badface *) NULL) {
11594  // Get the right flipped face.
11595  findface(&lastflip->tt, lastflip->forg, lastflip->fdest, lastflip->fapex);
11596  fc = (enum fliptype) (int) lastflip->key;
11597  switch (fc) {
11598  case T23:
11599  // The reverse operation of T23 is T32.
11600  flip32(&lastflip->tt, NULL);
11601  break;
11602  case T32:
11603  // The reverse operation of T32 is T23.
11604  flip23(&lastflip->tt, NULL);
11605  break;
11606  case T22:
11607  case T44:
11608  // The reverse operation of T22 or T44 is again T22 or T44.
11609  flip22(&lastflip->tt, NULL);
11610  break;
11611  default: // To omit compile warnings.
11612  break;
11613  }
11614  // Go on and process the next transformation.
11615  lastflip = lastflip->previtem;
11616  }
11617 }
11618 
11620 // //
11621 // flipsub() Flip non-Delaunay edges in a queue of (coplanar) subfaces. //
11622 // //
11623 // Assumpation: Current triangulation T contains non-Delaunay edges (after //
11624 // inserting a point or performing a flip). Non-Delaunay edges are queued in //
11625 // 'facequeue'. Returns the total number of flips done during this call. //
11626 // //
11628 
11629 long tetgenmesh::flipsub(queue* flipqueue)
11630 {
11631  badface *qedge;
11632  face flipedge, symedge;
11633  face checkseg;
11634  point pa, pb, pc, pd;
11635  REAL vab[3], vac[3], vad[3];
11636  REAL dot1, dot2, lac, lad;
11637  REAL sign, ori;
11638  int edgeflips;
11639  int i;
11640 
11641  if (b->verbose > 1) {
11642  printf(" Start do edge queue: %ld edges.\n", flipqueue->len());
11643  }
11644 
11645  edgeflips = 0;
11646 
11647  while (!flipqueue->empty()) {
11648  qedge = (badface *) flipqueue->pop();
11649  flipedge = qedge->ss;
11650  if (flipedge.sh == dummysh) continue;
11651  if ((sorg(flipedge) != qedge->forg) ||
11652  (sdest(flipedge) != qedge->fdest)) continue;
11653  sspivot(flipedge, checkseg);
11654  if (checkseg.sh != dummysh) continue; // Can't flip a subsegment.
11655  spivot(flipedge, symedge);
11656  if (symedge.sh == dummysh) continue; // Can't flip a hull edge.
11657  pa = sorg(flipedge);
11658  pb = sdest(flipedge);
11659  pc = sapex(flipedge);
11660  pd = sapex(symedge);
11661  // Choose the triangle abc or abd as the base depending on the angle1
11662  // (Vac, Vab) and angle2 (Vad, Vab).
11663  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
11664  for (i = 0; i < 3; i++) vac[i] = pc[i] - pa[i];
11665  for (i = 0; i < 3; i++) vad[i] = pd[i] - pa[i];
11666  dot1 = dot(vac, vab);
11667  dot2 = dot(vad, vab);
11668  dot1 *= dot1;
11669  dot2 *= dot2;
11670  lac = dot(vac, vac);
11671  lad = dot(vad, vad);
11672  if (lad * dot1 <= lac * dot2) {
11673  // angle1 is closer to 90 than angle2, choose abc (flipedge).
11674  abovepoint = facetabovepointarray[shellmark(flipedge)];
11675  if (abovepoint == (point) NULL) {
11676  getfacetabovepoint(&flipedge);
11677  }
11678  sign = insphere(pa, pb, pc, abovepoint, pd);
11679  ori = orient3d(pa, pb, pc, abovepoint);
11680  } else {
11681  // angle2 is closer to 90 than angle1, choose abd (symedge).
11682  abovepoint = facetabovepointarray[shellmark(symedge)];
11683  if (abovepoint == (point) NULL) {
11684  getfacetabovepoint(&symedge);
11685  }
11686  sign = insphere(pa, pb, pd, abovepoint, pc);
11687  ori = orient3d(pa, pb, pd, abovepoint);
11688  }
11689  // Correct the sign.
11690  sign = ori > 0.0 ? sign : -sign;
11691  if (sign > 0.0) {
11692  // Flip the non-Delaunay edge.
11693  flip22sub(&flipedge, flipqueue);
11694  edgeflips++;
11695  }
11696  }
11697 
11698  if (b->verbose > 1) {
11699  printf(" Total %d flips.\n", edgeflips);
11700  }
11701 
11702  return edgeflips;
11703 }
11704 
11706 // //
11707 // removetetbypeeloff() Remove a boundary tet by peeling it off. //
11708 // //
11709 // 'striptet' (abcd) is on boundary and can be removed by stripping it off. //
11710 // Let abc and bad are the external boundary faces. //
11711 // //
11712 // To strip 'abcd' from the mesh is to detach its two interal faces (dca and //
11713 // cdb) from their adjoining tets together with a 2-to-2 flip to transform //
11714 // two subfaces (abc and bad) into another two (dca and cdb). //
11715 // //
11716 // In mesh optimization. It is possible that ab is a segment and abcd is a //
11717 // sliver on the hull. Strip abcd will also delete the segment ab. //
11718 // //
11720 
11721 bool tetgenmesh::removetetbypeeloff(triface *striptet)
11722 {
11723  triface abcd, badc;
11724  triface dcacasing, cdbcasing;
11725  face abc, bad;
11726  face abseg;
11727  REAL ang;
11728 
11729  abcd = *striptet;
11730  adjustedgering(abcd, CCW);
11731  // Get the casing tets at the internal sides.
11732  enextfnext(abcd, cdbcasing);
11733  enext2fnext(abcd, dcacasing);
11734  symself(cdbcasing);
11735  symself(dcacasing);
11736  // Do the neighboring tets exist? During optimization. It is possible
11737  // that the neighboring tets are already dead.
11738  if ((cdbcasing.tet == dummytet) || (dcacasing.tet == dummytet)) {
11739  // Do not strip this tet.
11740  return false;
11741  }
11742 
11743  // Are there subfaces?
11744  if (checksubfaces) {
11745  // Get the external subfaces abc, bad.
11746  fnext(abcd, badc);
11747  esymself(badc);
11748  tspivot(abcd, abc);
11749  tspivot(badc, bad);
11750  if (abc.sh != dummysh) {
11751  assert(bad.sh != dummysh);
11752  findedge(&abc, org(abcd), dest(abcd));
11753  findedge(&bad, org(badc), dest(badc));
11754  // Is ab a segment?
11755  sspivot(abc, abseg);
11756  if (abseg.sh != dummysh) {
11757  // Does a segment allow to be removed?
11758  if ((b->optlevel > 3) && (b->nobisect == 0)) {
11759  // Only remove this segment if the dihedal angle at ab is between
11760  // [b->maxdihedral-9, 180] (deg). This avoids mistakely fliping
11761  // ab when it has actually no big dihedral angle while cd has.
11762  ang = facedihedral(org(abcd), dest(abcd), apex(abcd), oppo(abcd));
11763  ang = ang * 180.0 / PI;
11764  if ((ang + 9.0) > b->maxdihedral) {
11765  if (b->verbose > 1) {
11766  printf(" Remove a segment during peeling.\n");
11767  }
11768  face prevseg, nextseg;
11769  // It is only shared by abc and bad (abcd is a tet).
11770  ssdissolve(abc);
11771  ssdissolve(bad);
11772  abseg.shver = 0;
11773  senext(abseg, nextseg);
11774  spivotself(nextseg);
11775  if (nextseg.sh != dummysh) {
11776  ssdissolve(nextseg);
11777  }
11778  senext2(abseg, prevseg);
11779  spivotself(prevseg);
11780  if (prevseg.sh != dummysh) {
11781  ssdissolve(prevseg);
11782  }
11783  shellfacedealloc(subsegs, abseg.sh);
11784  optcount[1]++;
11785  } else {
11786  return false;
11787  }
11788  } else {
11789  return false;
11790  }
11791  }
11792  // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb.
11793  flip22sub(&abc, NULL);
11794  // The two internal faces become boundary faces.
11795  tsbond(cdbcasing, bad);
11796  tsbond(dcacasing, abc);
11797  }
11798  }
11799 
11800  // Detach abcd from the two internal faces.
11801  dissolve(cdbcasing);
11802  dissolve(dcacasing);
11803  // Delete abcd.
11804  tetrahedrondealloc(abcd.tet);
11805  return true;
11806 }
11807 
11809 // //
11810 // removeedgebyflip22() Remove an edge by a 2-to-2 (or 4-to-4) flip. //
11811 // //
11812 // 'abtetlist' contains n tets (n is 2 or 4) sharing edge ab, abtetlist[0] //
11813 // and abtetlist[1] are tets abec and abde, respectively (NOTE, both are in //
11814 // CW edge ring), where a, b, c, and d are coplanar. If n = 4, abtetlist[2] //
11815 // and abtetlist[3] are tets abfd and abcf, respectively. This routine uses //
11816 // flip22() to replace edge ab with cd, the surrounding tets are rotated. //
11817 // //
11818 // If 'key' != NULL. The old tets are replaced by the new tets only if the //
11819 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
11820 // is the maximum dihedral angle in the old tets. //
11821 // //
11823 
11824 bool tetgenmesh::removeedgebyflip22(REAL *key, int n, triface *abtetlist,
11825  queue *flipque)
11826 {
11827  point pa, pb, pc, pd, pe, pf;
11828  REAL cosmaxd, d1, d2, d3;
11829  bool doflip;
11830 
11831  cosmaxd = 0.0;
11832  pf = apex(abtetlist[2]);
11833  doflip = true;
11834  adjustedgering(abtetlist[0], CW);
11835  pa = org(abtetlist[0]);
11836  pb = dest(abtetlist[0]);
11837  pe = apex(abtetlist[0]);
11838  pc = oppo(abtetlist[0]);
11839  pd = apex(abtetlist[1]);
11840  if (n == 4) {
11841  pf = apex(abtetlist[2]);
11842  }
11843  if (key && (*key > -1.0)) {
11844  tetalldihedral(pc, pd, pe, pa, NULL, &d1, NULL);
11845  tetalldihedral(pd, pc, pe, pb, NULL, &d2, NULL);
11846  cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11847  if (n == 4) {
11848  tetalldihedral(pd, pc, pf, pa, NULL, &d1, NULL);
11849  tetalldihedral(pc, pd, pf, pb, NULL, &d2, NULL);
11850  d3 = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11851  cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
11852  }
11853  doflip = (*key < cosmaxd); // Can local quality be improved?
11854  }
11855 
11856  if (doflip) {
11857  flip22(&abtetlist[0], NULL);
11858  // Return the improved quality value.
11859  if (key) *key = cosmaxd;
11860  }
11861 
11862  return doflip;
11863 }
11864 
11866 // //
11867 // removefacebyflip23() Remove a face by a 2-to-3 flip. //
11868 // //
11869 // 'abctetlist' contains 2 tets sharing abc, which are [0]abcd and [1]bace. //
11870 // This routine forms three new tets that abc is not a face anymore. Save //
11871 // them in 'newtetlist': [0]edab, [1]edbc, and [2]edca. Note that the new //
11872 // tets may not valid if one of them get inverted. return false if so. //
11873 // //
11874 // If 'key' != NULL. The old tets are replaced by the new tets only if the //
11875 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
11876 // is the maximum dihedral angle in the old tets. //
11877 // //
11878 // If the face is flipped, 'newtetlist' returns the three new tets. The two //
11879 // tets in 'abctetlist' are NOT deleted. The caller has the right to either //
11880 // delete them or reverse the operation. //
11881 // //
11883 
11884 bool tetgenmesh::removefacebyflip23(REAL *key, triface *abctetlist,
11885  triface *newtetlist, queue *flipque)
11886 {
11887  triface edab, edbc, edca; // new configuration.
11888  triface newfront, oldfront, adjfront;
11889  face checksh;
11890  point pa, pb, pc, pd, pe;
11891  REAL ori, cosmaxd, d1, d2, d3;
11892  REAL attrib, volume;
11893  bool doflip;
11894  int i;
11895 
11896  cosmaxd = 0.0;
11897 
11898  adjustedgering(abctetlist[0], CCW);
11899  pa = org(abctetlist[0]);
11900  pb = dest(abctetlist[0]);
11901  pc = apex(abctetlist[0]);
11902  pd = oppo(abctetlist[0]);
11903  pe = oppo(abctetlist[1]);
11904 
11905  // Check if the flip creates valid new tets.
11906  ori = orient3d(pe, pd, pa, pb);
11907  if (ori < 0.0) {
11908  ori = orient3d(pe, pd, pb, pc);
11909  if (ori < 0.0) {
11910  ori = orient3d(pe, pd, pc, pa);
11911  }
11912  }
11913  doflip = (ori < 0.0); // Can abc be flipped away?
11914  if (doflip && (key != (REAL *) NULL)) {
11915  if (*key > -1.0) {
11916  // Test if the new tets reduce the maximal dihedral angle.
11917  tetalldihedral(pe, pd, pa, pb, NULL, &d1, NULL);
11918  tetalldihedral(pe, pd, pb, pc, NULL, &d2, NULL);
11919  tetalldihedral(pe, pd, pc, pa, NULL, &d3, NULL);
11920  cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
11921  cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle.
11922  doflip = (*key < cosmaxd); // Can local quality be improved?
11923  }
11924  }
11925 
11926  if (doflip) {
11927  // A valid (2-to-3) flip is found.
11928  flip23s++;
11929  // Create the new tets.
11930  maketetrahedron(&edab);
11931  setorg(edab, pe);
11932  setdest(edab, pd);
11933  setapex(edab, pa);
11934  setoppo(edab, pb);
11935  maketetrahedron(&edbc);
11936  setorg(edbc, pe);
11937  setdest(edbc, pd);
11938  setapex(edbc, pb);
11939  setoppo(edbc, pc);
11940  maketetrahedron(&edca);
11941  setorg(edca, pe);
11942  setdest(edca, pd);
11943  setapex(edca, pc);
11944  setoppo(edca, pa);
11945  // Transfer the element attributes.
11946  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
11947  attrib = elemattribute(abctetlist[0].tet, i);
11948  setelemattribute(edab.tet, i, attrib);
11949  setelemattribute(edbc.tet, i, attrib);
11950  setelemattribute(edca.tet, i, attrib);
11951  }
11952  // Transfer the volume constraints.
11953  if (b->varvolume && !b->refine) {
11954  volume = volumebound(abctetlist[0].tet);
11955  setvolumebound(edab.tet, volume);
11956  setvolumebound(edbc.tet, volume);
11957  setvolumebound(edca.tet, volume);
11958  }
11959  // Return two new tets.
11960  newtetlist[0] = edab;
11961  newtetlist[1] = edbc;
11962  newtetlist[2] = edca;
11963  // Glue the three new tets.
11964  for (i = 0; i < 3; i++) {
11965  fnext(newtetlist[i], newfront);
11966  bond(newfront, newtetlist[(i + 1) % 3]);
11967  }
11968  // Substitute the three new tets into the old cavity.
11969  for (i = 0; i < 3; i++) {
11970  fnext(abctetlist[0], oldfront);
11971  sym(oldfront, adjfront); // may be outside.
11972  enextfnext(newtetlist[i], newfront);
11973  bond(newfront, adjfront);
11974  if (checksubfaces) {
11975  tspivot(oldfront, checksh);
11976  if (checksh.sh != dummysh) {
11977  tsbond(newfront, checksh);
11978  }
11979  }
11980  if (flipque != (queue *) NULL) {
11981  enqueueflipface(newfront, flipque);
11982  }
11983  enextself(abctetlist[0]);
11984  }
11985  findedge(&(abctetlist[1]), pb, pa);
11986  for (i = 0; i < 3; i++) {
11987  fnext(abctetlist[1], oldfront);
11988  sym(oldfront, adjfront); // may be outside.
11989  enext2fnext(newtetlist[i], newfront);
11990  bond(newfront, adjfront);
11991  if (checksubfaces) {
11992  tspivot(oldfront, checksh);
11993  if (checksh.sh != dummysh) {
11994  tsbond(newfront, checksh);
11995  }
11996  }
11997  if (flipque != (queue *) NULL) {
11998  enqueueflipface(newfront, flipque);
11999  }
12000  enext2self(abctetlist[1]);
12001  }
12002  // Do not delete the old tets.
12003  // for (i = 0; i < 2; i++) {
12004  // tetrahedrondealloc(abctetlist[i].tet);
12005  // }
12006  // Return the improved quality value.
12007  if (key != (REAL *) NULL) *key = cosmaxd;
12008  return true;
12009  }
12010 
12011  return false;
12012 }
12013 
12015 // //
12016 // removeedgebyflip32() Remove an edge by a 3-to-2 flip. //
12017 // //
12018 // 'abtetlist' contains 3 tets sharing ab. Imaging that ab is perpendicular //
12019 // to the screen, where a lies in front of and b lies behind it. The 3 tets //
12020 // of the list are: [0]abce, [1]abdc, and [2]abed, respectively. //
12021 // //
12022 // This routine forms two new tets that ab is not an edge of them. Save them //
12023 // in 'newtetlist', [0]dcea, [1]cdeb. Note that the new tets may not valid //
12024 // if one of them get inverted. return false if so. //
12025 // //
12026 // If 'key' != NULL. The old tets are replaced by the new tets only if the //
12027 // local mesh quality is improved. Current 'key' = cos(\theta), where \theta //
12028 // is the maximum dihedral angle in the old tets. //
12029 // //
12030 // If the edge is flipped, 'newtetlist' returns the two new tets. The three //
12031 // tets in 'abtetlist' are NOT deleted. The caller has the right to either //
12032 // delete them or reverse the operation. //
12033 // //
12035 
12036 bool tetgenmesh::removeedgebyflip32(REAL *key, triface *abtetlist,
12037  triface *newtetlist, queue *flipque)
12038 {
12039  triface dcea, cdeb; // new configuration.
12040  triface newfront, oldfront, adjfront;
12041  face checksh;
12042  point pa, pb, pc, pd, pe;
12043  REAL ori, cosmaxd, d1, d2;
12044  REAL attrib, volume;
12045  bool doflip;
12046  int i;
12047 
12048  pa = org(abtetlist[0]);
12049  pb = dest(abtetlist[0]);
12050  pc = apex(abtetlist[0]);
12051  pd = apex(abtetlist[1]);
12052  pe = apex(abtetlist[2]);
12053 
12054  ori = orient3d(pd, pc, pe, pa);
12055  if (ori < 0.0) {
12056  ori = orient3d(pc, pd, pe, pb);
12057  }
12058  doflip = (ori < 0.0); // Can ab be flipped away?
12059 
12060  // Does the caller ensure a valid configuration?
12061  if (doflip && (key != (REAL *) NULL)) {
12062  if (*key > -1.0) {
12063  // Test if the new tets reduce the maximal dihedral angle.
12064  tetalldihedral(pd, pc, pe, pa, NULL, &d1, NULL);
12065  tetalldihedral(pc, pd, pe, pb, NULL, &d2, NULL);
12066  cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
12067  doflip = (*key < cosmaxd); // Can local quality be improved?
12068  // Return the key
12069  *key = cosmaxd;
12070  }
12071  }
12072 
12073  if (doflip) {
12074  // Create the new tets.
12075  maketetrahedron(&dcea);
12076  setorg(dcea, pd);
12077  setdest(dcea, pc);
12078  setapex(dcea, pe);
12079  setoppo(dcea, pa);
12080  maketetrahedron(&cdeb);
12081  setorg(cdeb, pc);
12082  setdest(cdeb, pd);
12083  setapex(cdeb, pe);
12084  setoppo(cdeb, pb);
12085  // Transfer the element attributes.
12086  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
12087  attrib = elemattribute(abtetlist[0].tet, i);
12088  setelemattribute(dcea.tet, i, attrib);
12089  setelemattribute(cdeb.tet, i, attrib);
12090  }
12091  // Transfer the volume constraints.
12092  if (b->varvolume && !b->refine) {
12093  volume = volumebound(abtetlist[0].tet);
12094  setvolumebound(dcea.tet, volume);
12095  setvolumebound(cdeb.tet, volume);
12096  }
12097  // Return two new tets.
12098  newtetlist[0] = dcea;
12099  newtetlist[1] = cdeb;
12100  // Glue the two new tets.
12101  bond(dcea, cdeb);
12102  // Substitute the two new tets into the old three-tets cavity.
12103  for (i = 0; i < 3; i++) {
12104  fnext(dcea, newfront); // face dca, cea, eda.
12105  esym(abtetlist[(i + 1) % 3], oldfront);
12106  enextfnextself(oldfront);
12107  // Get the adjacent tet at the face (may be a dummytet).
12108  sym(oldfront, adjfront);
12109  bond(newfront, adjfront);
12110  if (checksubfaces) {
12111  tspivot(oldfront, checksh);
12112  if (checksh.sh != dummysh) {
12113  tsbond(newfront, checksh);
12114  }
12115  }
12116  if (flipque != (queue *) NULL) {
12117  enqueueflipface(newfront, flipque);
12118  }
12119  enext2self(dcea);
12120  }
12121  for (i = 0; i < 3; i++) {
12122  fnext(cdeb, newfront); // face cdb, deb, ecb.
12123  esym(abtetlist[(i + 1) % 3], oldfront);
12124  enext2fnextself(oldfront);
12125  // Get the adjacent tet at the face (may be a dummytet).
12126  sym(oldfront, adjfront);
12127  bond(newfront, adjfront);
12128  if (checksubfaces) {
12129  tspivot(oldfront, checksh);
12130  if (checksh.sh != dummysh) {
12131  tsbond(newfront, checksh);
12132  }
12133  }
12134  if (flipque != (queue *) NULL) {
12135  enqueueflipface(newfront, flipque);
12136  }
12137  enextself(cdeb);
12138  }
12139  // Do not delete the old tets.
12140  // for (i = 0; i < 3; i++) {
12141  // tetrahedrondealloc(abtetlist[i].tet);
12142  // }
12143  return true;
12144  } // if (doflip)
12145 
12146  return false;
12147 }
12148 
12150 // //
12151 // removeedgebytranNM() Remove an edge by transforming n-to-m tets. //
12152 // //
12153 // This routine attempts to remove a given edge (ab) by transforming the set //
12154 // T of tets surrounding ab into another set T' of tets. T and T' have the //
12155 // same outer faces and ab is not an edge of T' anymore. Let |T|=n, and |T'| //
12156 // =m, it is actually a n-to-m flip for n > 3. The relation between n and m //
12157 // depends on the method, ours is found below. //
12158 // //
12159 // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
12160 // to the screen, where a lies in front of and b lies behind it. Let the //
12161 // projections of the n apexes onto screen in clockwise order are: p_0, ... //
12162 // p_n-1, respectively. The tets in the list are: [0]abp_0p_n-1,[1]abp_1p_0, //
12163 // ..., [n-1]abp_n-1p_n-2, respectively. //
12164 // //
12165 // The principle of the approach is: Recursively reduce the link of ab by //
12166 // using flip23 until only three faces remain, hence a flip32 can be applied //
12167 // to remove ab. For a given face a.b.p_0, check a flip23 can be applied on //
12168 // it, i.e, edge p_1.p_n-1 crosses it. NOTE*** We do the flip even p_1.p_n-1 //
12169 // intersects with a.b (they are coplanar). If so, a degenerate tet (a.b.p_1.//
12170 // p_n-1) is temporarily created, but it will be eventually removed by the //
12171 // final flip32. This relaxation splits a flip44 into flip23 + flip32. *NOTE //
12172 // Now suppose a.b.p_0 gets flipped, p_0 is not on the link of ab anymore. //
12173 // The link is then reduced (by 1). 2 of the 3 new tets, p_n-1.p_1.p_0.a and //
12174 // p_1.p_n-1.p_0.b, will be part of the new configuration. The left new tet,//
12175 // a.b.p_1.p_n-1, goes into the new link of ab. A recurrence can be applied. //
12176 // //
12177 // If 'e1' and 'e2' are not NULLs, they specify an wanted edge to appear in //
12178 // the new tet configuration. In such case, only do flip23 if edge e1<->e2 //
12179 // can be recovered. It is used in removeedgebycombNM(). //
12180 // //
12181 // If ab gets removed. 'newtetlist' contains m new tets. By using the above //
12182 // approach, the pairs (n, m) can be easily enumerated. For example, (3, 2),//
12183 // (4, 4), (5, 6), (6, 8), (7, 10), (8, 12), (9, 14), (10, 16), and so on. //
12184 // It is easy to deduce, that m = (n - 2) * 2, when n >= 3. The n tets in //
12185 // 'abtetlist' are NOT deleted in this routine. The caller has the right to //
12186 // either delete them or reverse this operation. //
12187 // //
12189 
12190 bool tetgenmesh::removeedgebytranNM(REAL *key, int n, triface *abtetlist,
12191  triface *newtetlist, point e1, point e2, queue *flipque)
12192 {
12193  triface tmpabtetlist[9]; // Temporary max 9 tets configuration.
12194  triface newfront, oldfront, adjfront;
12195  face checksh;
12196  point pa, pb, p[10];
12197  REAL ori, cosmaxd, d1, d2;
12198  REAL tmpkey;
12199  REAL attrib, volume;
12200  bool doflip, copflag, success;
12201  int i, j, k;
12202 
12203  cosmaxd = 0.0;
12204  // Maximum 10 tets.
12205  assert(n <= 10);
12206  // Two points a and b are fixed.
12207  pa = org(abtetlist[0]);
12208  pb = dest(abtetlist[0]);
12209  // The points p_0, p_1, ..., p_n-1 are permuted in each new configuration.
12210  // These permutations can be easily done in the following loop.
12211  // Loop through all the possible new tets configurations. Stop on finding
12212  // a valid new tet configuration which also immproves the quality value.
12213  for (i = 0; i < n; i++) {
12214  // Get other n points for the current configuration.
12215  for (j = 0; j < n; j++) {
12216  p[j] = apex(abtetlist[(i + j) % n]);
12217  }
12218  // Is there a wanted edge?
12219  if ((e1 != (point) NULL) && (e2 != (point) NULL)) {
12220  // Yes. Skip this face if p[1]<->p[n-1] is not the edge.
12221  if (!(((p[1] == e1) && (p[n - 1] == e2)) ||
12222  ((p[1] == e2) && (p[n - 1] == e1)))) continue;
12223  }
12224  // Test if face a.b.p_0 can be flipped (by flip23), ie, to check if the
12225  // edge p_n-1.p_1 crosses face a.b.p_0 properly.
12226  // Note. It is possible that face a.b.p_0 has type flip44, ie, a,b,p_1,
12227  // and p_n-1 are coplanar. A trick is to split the flip44 into two
12228  // steps: frist a flip23, then a flip32. The first step creates a
12229  // degenerate tet (vol=0) which will be removed by the second flip.
12230  ori = orient3d(pa, pb, p[1], p[n - 1]);
12231  copflag = (ori == 0.0); // Are they coplanar?
12232  if (ori >= 0.0) {
12233  // Accept the coplanar case which supports flip44.
12234  ori = orient3d(pb, p[0], p[1], p[n - 1]);
12235  if (ori > 0.0) {
12236  ori = orient3d(p[0], pa, p[1], p[n - 1]);
12237  }
12238  }
12239  // Is face abc flipable?
12240  if (ori > 0.0) {
12241  // A valid (2-to-3) flip (or 4-to-4 flip) is found.
12242  copflag ? flip44s++ : flip23s++;
12243  doflip = true;
12244  if (key != (REAL *) NULL) {
12245  if (*key > -1.0) {
12246  // Test if the new tets reduce the maximal dihedral angle. Only 2
12247  // tets, p_n-1.p_1.p_0.a and p_1.p_n-1.p_0.b, need to be tested
12248  // The left one a.b.p_n-1.p_1 goes into the new link of ab.
12249  tetalldihedral(p[n - 1], p[1], p[0], pa, NULL, &d1, NULL);
12250  tetalldihedral(p[1], p[n - 1], p[0], pb, NULL, &d2, NULL);
12251  cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle.
12252  doflip = *key < cosmaxd; // Can the local quality be improved?
12253  }
12254  }
12255  if (doflip) {
12256  tmpkey = key != NULL ? *key : -1.0;
12257  // Create the two new tets.
12258  maketetrahedron(&(newtetlist[0]));
12259  setorg(newtetlist[0], p[n - 1]);
12260  setdest(newtetlist[0], p[1]);
12261  setapex(newtetlist[0], p[0]);
12262  setoppo(newtetlist[0], pa);
12263  maketetrahedron(&(newtetlist[1]));
12264  setorg(newtetlist[1], p[1]);
12265  setdest(newtetlist[1], p[n - 1]);
12266  setapex(newtetlist[1], p[0]);
12267  setoppo(newtetlist[1], pb);
12268  // Create the n - 1 temporary new tets (the new Star(ab)).
12269  maketetrahedron(&(tmpabtetlist[0]));
12270  setorg(tmpabtetlist[0], pa);
12271  setdest(tmpabtetlist[0], pb);
12272  setapex(tmpabtetlist[0], p[n - 1]);
12273  setoppo(tmpabtetlist[0], p[1]);
12274  for (j = 1; j < n - 1; j++) {
12275  maketetrahedron(&(tmpabtetlist[j]));
12276  setorg(tmpabtetlist[j], pa);
12277  setdest(tmpabtetlist[j], pb);
12278  setapex(tmpabtetlist[j], p[j]);
12279  setoppo(tmpabtetlist[j], p[j + 1]);
12280  }
12281  // Transfer the element attributes.
12282  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
12283  attrib = elemattribute(abtetlist[0].tet, j);
12284  setelemattribute(newtetlist[0].tet, j, attrib);
12285  setelemattribute(newtetlist[1].tet, j, attrib);
12286  for (k = 0; k < n - 1; k++) {
12287  setelemattribute(tmpabtetlist[k].tet, j, attrib);
12288  }
12289  }
12290  // Transfer the volume constraints.
12291  if (b->varvolume && !b->refine) {
12292  volume = volumebound(abtetlist[0].tet);
12293  setvolumebound(newtetlist[0].tet, volume);
12294  setvolumebound(newtetlist[1].tet, volume);
12295  for (k = 0; k < n - 1; k++) {
12296  setvolumebound(tmpabtetlist[k].tet, volume);
12297  }
12298  }
12299  // Glue the new tets at their internal faces: 2 + (n - 1).
12300  bond(newtetlist[0], newtetlist[1]); // p_n-1.p_1.p_0.
12301  fnext(newtetlist[0], newfront);
12302  enext2fnext(tmpabtetlist[0], adjfront);
12303  bond(newfront, adjfront); // p_n-1.p_1.a.
12304  fnext(newtetlist[1], newfront);
12305  enextfnext(tmpabtetlist[0], adjfront);
12306  bond(newfront, adjfront); // p_n-1.p_1.b.
12307  // Glue n - 1 internal faces around ab.
12308  for (j = 0; j < n - 1; j++) {
12309  fnext(tmpabtetlist[j], newfront);
12310  bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
12311  }
12312  // Substitute the old tets with the new tets by connecting the new
12313  // tets to the adjacent tets in the mesh. There are n * 2 (outer)
12314  // faces of the new tets need to be operated.
12315  // Note, after the substitution, the old tets still have pointers to
12316  // their adjacent tets in the mesh. These pointers can be re-used
12317  // to inverse the substitution.
12318  for (j = 0; j < n; j++) {
12319  // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
12320  oldfront = abtetlist[(i + j) % n];
12321  esymself(oldfront);
12322  enextfnextself(oldfront);
12323  // Get an adjacent tet at face: [0]a.p_0.p_n-1 or [j]a.p_j.p_j-1.
12324  sym(oldfront, adjfront); // adjfront may be dummy.
12325  // Get the corresponding face from the new tets.
12326  if (j == 0) {
12327  enext2fnext(newtetlist[0], newfront); // a.p_0.n_n-1
12328  } else if (j == 1) {
12329  enextfnext(newtetlist[0], newfront); // a.p_1.p_0
12330  } else { // j >= 2.
12331  enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
12332  }
12333  bond(newfront, adjfront);
12334  if (checksubfaces) {
12335  tspivot(oldfront, checksh);
12336  if (checksh.sh != dummysh) {
12337  tsbond(newfront, checksh);
12338  }
12339  }
12340  if (flipque != (queue *) NULL) {
12341  // Only queue the faces of the two new tets.
12342  if (j < 2) enqueueflipface(newfront, flipque);
12343  }
12344  }
12345  for (j = 0; j < n; j++) {
12346  // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0).
12347  oldfront = abtetlist[(i + j) % n];
12348  esymself(oldfront);
12349  enext2fnextself(oldfront);
12350  // Get an adjacent tet at face: [0]b.p_0.p_n-1 or [j]b.p_j.p_j-1.
12351  sym(oldfront, adjfront); // adjfront may be dummy.
12352  // Get the corresponding face from the new tets.
12353  if (j == 0) {
12354  enextfnext(newtetlist[1], newfront); // b.p_0.n_n-1
12355  } else if (j == 1) {
12356  enext2fnext(newtetlist[1], newfront); // b.p_1.p_0
12357  } else { // j >= 2.
12358  enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
12359  }
12360  bond(newfront, adjfront);
12361  if (checksubfaces) {
12362  tspivot(oldfront, checksh);
12363  if (checksh.sh != dummysh) {
12364  tsbond(newfront, checksh);
12365  }
12366  }
12367  if (flipque != (queue *) NULL) {
12368  // Only queue the faces of the two new tets.
12369  if (j < 2) enqueueflipface(newfront, flipque);
12370  }
12371  }
12372  // Adjust the faces in the temporary new tets at ab for recursively
12373  // processing on the n-1 tets.(See the description at beginning)
12374  for (j = 0; j < n - 1; j++) {
12375  fnextself(tmpabtetlist[j]);
12376  }
12377  if (n > 4) {
12378  success = removeedgebytranNM(&tmpkey, n-1, tmpabtetlist,
12379  &(newtetlist[2]), NULL, NULL, flipque);
12380  } else { // assert(n == 4);
12381  success = removeedgebyflip32(&tmpkey, tmpabtetlist,
12382  &(newtetlist[2]), flipque);
12383  }
12384  // No matter it was success or not, delete the temporary tets.
12385  for (j = 0; j < n - 1; j++) {
12386  tetrahedrondealloc(tmpabtetlist[j].tet);
12387  }
12388  if (success) {
12389  // The new configuration is good.
12390  // Do not delete the old tets.
12391  // for (j = 0; j < n; j++) {
12392  // tetrahedrondealloc(abtetlist[j].tet);
12393  // }
12394  // Save the minimal improved quality value.
12395  if (key != (REAL *) NULL) {
12396  *key = (tmpkey < cosmaxd ? tmpkey : cosmaxd);
12397  }
12398  return true;
12399  } else {
12400  // The new configuration is bad, substitue back the old tets.
12401  for (j = 0; j < n; j++) {
12402  oldfront = abtetlist[(i + j) % n];
12403  esymself(oldfront);
12404  enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
12405  sym(oldfront, adjfront); // adjfront may be dummy.
12406  bond(oldfront, adjfront);
12407  if (checksubfaces) {
12408  tspivot(oldfront, checksh);
12409  if (checksh.sh != dummysh) {
12410  tsbond(oldfront, checksh);
12411  }
12412  }
12413  }
12414  for (j = 0; j < n; j++) {
12415  oldfront = abtetlist[(i + j) % n];
12416  esymself(oldfront);
12417  enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12418  sym(oldfront, adjfront); // adjfront may be dummy
12419  bond(oldfront, adjfront);
12420  if (checksubfaces) {
12421  tspivot(oldfront, checksh);
12422  if (checksh.sh != dummysh) {
12423  tsbond(oldfront, checksh);
12424  }
12425  }
12426  }
12427  // Delete the new tets.
12428  tetrahedrondealloc(newtetlist[0].tet);
12429  tetrahedrondealloc(newtetlist[1].tet);
12430  // If tmpkey has been modified, then the failure was not due to
12431  // unflipable configuration, but the non-improvement.
12432  if (key && (tmpkey < *key)) {
12433  *key = tmpkey;
12434  return false;
12435  }
12436  } // if (success)
12437  } // if (doflip)
12438  } // if (ori > 0.0)
12439  } // for (i = 0; i < n; i++)
12440 
12441  return false;
12442 }
12443 
12445 // //
12446 // removeedgebycombNM() Remove an edge by combining two flipNMs. //
12447 // //
12448 // Given a set T of tets surrounding edge ab. The premise is that ab can not //
12449 // be removed by a flipNM. This routine attempts to remove ab by two flipNMs,//
12450 // i.e., first find and flip an edge af (or bf) by flipNM, then flip ab by //
12451 // flipNM. If it succeeds, two sets T(ab) and T(af) of tets are replaced by //
12452 // a new set T' and both ab and af are not edges in T' anymore. //
12453 // //
12454 // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular //
12455 // to the screen, such that a lies in front of and b lies behind it. Let the //
12456 // projections of the n apexes on the screen in clockwise order are: p_0,...,//
12457 // p_n-1, respectively. So the list of tets are: [0]abp_0p_n-1, [1]abp_1p_0, //
12458 // ..., [n-1]abp_n-1p_n-2, respectively. //
12459 // //
12460 // The principle of the approach is: for a face a.b.p_0, check if edge b.p_0 //
12461 // is of type N32 (or N44). If it is, then try to do a flipNM on it. If the //
12462 // flip is successful, then try to do another flipNM on a.b. If one of the //
12463 // two flipNMs fails, restore the old tets as they have never been flipped. //
12464 // Then try the next face a.b.p_1. The process can be looped for all faces //
12465 // having ab. Stop if ab is removed or all faces have been visited. Note in //
12466 // the above description only b.p_0 is considered, a.p_0 is done by swapping //
12467 // the position of a and b. //
12468 // //
12469 // Similar operations have been described in [Joe,1995]. My approach checks //
12470 // more cases for finding flips than Joe's. For instance, the cases (1)-(7) //
12471 // of Joe only consider abf for finding a flip (T23/T32). My approach looks //
12472 // all faces at ab for finding flips. Moreover, the flipNM can flip an edge //
12473 // whose star may have more than 3 tets while Joe's only works on 3-tet case.//
12474 // //
12475 // If ab is removed, 'newtetlist' contains the new tets. Two sets 'abtetlist'//
12476 // (n tets) and 'bftetlist' (n1 tets) have been replaced. The number of new //
12477 // tets can be calculated by follows: the 1st flip transforms n1 tets into //
12478 // (n1 - 2) * 2 new tets, however,one of the new tets goes into the new link //
12479 // of ab, i.e., the reduced tet number in Star(ab) is n - 1; the 2nd flip //
12480 // transforms n - 1 tets into (n - 3) * 2 new tets. Hence the number of new //
12481 // tets are: m = ((n1 - 2) * 2 - 1) + (n - 3) * 2. The old tets are NOT del-//
12482 // eted. The caller has the right to delete them or reverse the operation. //
12483 // //
12485 
12486 bool tetgenmesh::removeedgebycombNM(REAL *key, int n, triface *abtetlist,
12487  int *n1, triface *bftetlist, triface *newtetlist, queue *flipque)
12488 {
12489  triface tmpabtetlist[11];
12490  triface newfront, oldfront, adjfront;
12491  face checksh;
12492  point pa, pb, p[10];
12493  REAL ori, tmpkey, tmpkey2;
12494  REAL attrib, volume;
12495  bool doflip, success;
12496  int twice, count;
12497  int i, j, k, m;
12498 
12499  // Maximal 10 tets in Star(ab).
12500  assert(n <= 10);
12501 
12502  // Do the following procedure twice, one for flipping edge b.p_0 and the
12503  // other for p_0.a which is symmetric to the first.
12504  twice = 0;
12505  do {
12506  // Two points a and b are fixed.
12507  pa = org(abtetlist[0]);
12508  pb = dest(abtetlist[0]);
12509  // The points p_0, ..., p_n-1 are permuted in the following loop.
12510  for (i = 0; i < n; i++) {
12511  // Get the n points for the current configuration.
12512  for (j = 0; j < n; j++) {
12513  p[j] = apex(abtetlist[(i + j) % n]);
12514  }
12515  // Check if b.p_0 is of type N32 or N44.
12516  ori = orient3d(pb, p[0], p[1], p[n - 1]);
12517  if ((ori > 0) && (key != (REAL *) NULL)) {
12518  // b.p_0 is not N32. However, it is possible that the tet b.p_0.p_1.
12519  // p_n-1 has worse quality value than the key. In such case, also
12520  // try to flip b.p_0.
12521  tetalldihedral(pb, p[0], p[n - 1], p[1], NULL, &tmpkey, NULL);
12522  if (tmpkey < *key) ori = 0.0;
12523  }
12524  if (ori <= 0.0) {
12525  // b.p_0 is either N32 or N44. Try the 1st flipNM.
12526  bftetlist[0] = abtetlist[i];
12527  enextself(bftetlist[0]);// go to edge b.p_0.
12528  adjustedgering(bftetlist[0], CW); // edge p_0.b.
12529  assert(apex(bftetlist[0]) == pa);
12530  // Form Star(b.p_0).
12531  doflip = true;
12532  *n1 = 0;
12533  do {
12534  // Is the list full?
12535  if (*n1 == 10) break;
12536  if (checksubfaces) {
12537  // Stop if a subface appears.
12538  tspivot(bftetlist[*n1], checksh);
12539  if (checksh.sh != dummysh) {
12540  doflip = false; break;
12541  }
12542  }
12543  // Get the next tet at p_0.b.
12544  fnext(bftetlist[*n1], bftetlist[(*n1) + 1]);
12545  (*n1)++;
12546  } while (apex(bftetlist[*n1]) != pa);
12547  // 2 <= n1 <= 10.
12548  if (doflip) {
12549  success = false;
12550  tmpkey = -1.0; // = acos(pi).
12551  if (key != (REAL *) NULL) tmpkey = *key;
12552  m = 0;
12553  if (*n1 == 3) {
12554  // Three tets case. Try flip32.
12555  success = removeedgebyflip32(&tmpkey,bftetlist,newtetlist,flipque);
12556  m = 2;
12557  } else if ((*n1 > 3) && (*n1 < 7)) {
12558  // Four or more tets case. Try flipNM.
12559  success = removeedgebytranNM(&tmpkey, *n1, bftetlist, newtetlist,
12560  p[1], p[n - 1], flipque);
12561  // If success, the number of new tets.
12562  m = ((*n1) - 2) * 2;
12563  } else {
12564  if (b->verbose > 1) {
12565  printf(" !! Unhandled case: n1 = %d.\n", *n1);
12566  }
12567  }
12568  if (success) {
12569  // b.p_0 is flipped. The link of ab is reduced (by 1), i.e., p_0
12570  // is not on the link of ab. Two old tets a.b.p_0.p_n-1 and
12571  // a.b.p_1.p_0 have been removed from the Star(ab) and one new
12572  // tet t = a.b.p_1.p_n-1 belongs to Star(ab).
12573  // Find t in the 'newtetlist' and remove it from the list.
12574  setpointmark(pa, -pointmark(pa) - 1);
12575  setpointmark(pb, -pointmark(pb) - 1);
12576  assert(m > 0);
12577  for (j = 0; j < m; j++) {
12578  tmpabtetlist[0] = newtetlist[j];
12579  // Does it has ab?
12580  count = 0;
12581  for (k = 0; k < 4; k++) {
12582  if (pointmark((point)(tmpabtetlist[0].tet[4+k])) < 0) count++;
12583  }
12584  if (count == 2) {
12585  // It is. Adjust t to be the edge ab.
12586  for (tmpabtetlist[0].loc = 0; tmpabtetlist[0].loc < 4;
12587  tmpabtetlist[0].loc++) {
12588  if ((oppo(tmpabtetlist[0]) != pa) &&
12589  (oppo(tmpabtetlist[0]) != pb)) break;
12590  }
12591  // The face of t must contain ab.
12592  assert(tmpabtetlist[0].loc < 4);
12593  findedge(&(tmpabtetlist[0]), pa, pb);
12594  break;
12595  }
12596  }
12597  assert(j < m); // The tet must exist.
12598  // Remove t from list. Fill t's position by the last tet.
12599  newtetlist[j] = newtetlist[m - 1];
12600  setpointmark(pa, -(pointmark(pa) + 1));
12601  setpointmark(pb, -(pointmark(pb) + 1));
12602  // Create the temporary Star(ab) for the next flipNM.
12603  adjustedgering(tmpabtetlist[0], CCW);
12604  if (org(tmpabtetlist[0]) != pa) {
12605  fnextself(tmpabtetlist[0]);
12606  esymself(tmpabtetlist[0]);
12607  }
12608 #ifdef SELF_CHECK
12609  // Make sure current edge is a->b.
12610  assert(org(tmpabtetlist[0]) == pa);
12611  assert(dest(tmpabtetlist[0]) == pb);
12612  assert(apex(tmpabtetlist[0]) == p[n - 1]);
12613  assert(oppo(tmpabtetlist[0]) == p[1]);
12614 #endif // SELF_CHECK
12615  // There are n - 2 left temporary tets.
12616  for (j = 1; j < n - 1; j++) {
12617  maketetrahedron(&(tmpabtetlist[j]));
12618  setorg(tmpabtetlist[j], pa);
12619  setdest(tmpabtetlist[j], pb);
12620  setapex(tmpabtetlist[j], p[j]);
12621  setoppo(tmpabtetlist[j], p[j + 1]);
12622  }
12623  // Transfer the element attributes.
12624  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
12625  attrib = elemattribute(abtetlist[0].tet, j);
12626  for (k = 0; k < n - 1; k++) {
12627  setelemattribute(tmpabtetlist[k].tet, j, attrib);
12628  }
12629  }
12630  // Transfer the volume constraints.
12631  if (b->varvolume && !b->refine) {
12632  volume = volumebound(abtetlist[0].tet);
12633  for (k = 0; k < n - 1; k++) {
12634  setvolumebound(tmpabtetlist[k].tet, volume);
12635  }
12636  }
12637  // Glue n - 1 internal faces of Star(ab).
12638  for (j = 0; j < n - 1; j++) {
12639  fnext(tmpabtetlist[j], newfront);
12640  bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1
12641  }
12642  // Substitute the old tets with the new tets by connecting the
12643  // new tets to the adjacent tets in the mesh. There are (n-2)
12644  // * 2 (outer) faces of the new tets need to be operated.
12645  // Note that the old tets still have the pointers to their
12646  // adjacent tets in the mesh. These pointers can be re-used
12647  // to inverse the substitution.
12648  for (j = 2; j < n; j++) {
12649  // Get an old tet: [j]a.b.p_j.p_j-1, (j > 1).
12650  oldfront = abtetlist[(i + j) % n];
12651  esymself(oldfront);
12652  enextfnextself(oldfront);
12653  // Get an adjacent tet at face: [j]a.p_j.p_j-1.
12654  sym(oldfront, adjfront); // adjfront may be dummy.
12655  // Get the corresponding face from the new tets.
12656  // j >= 2.
12657  enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1
12658  bond(newfront, adjfront);
12659  if (checksubfaces) {
12660  tspivot(oldfront, checksh);
12661  if (checksh.sh != dummysh) {
12662  tsbond(newfront, checksh);
12663  }
12664  }
12665  }
12666  for (j = 2; j < n; j++) {
12667  // Get an old tet: [j]a.b.p_j.p_j-1, (j > 2).
12668  oldfront = abtetlist[(i + j) % n];
12669  esymself(oldfront);
12670  enext2fnextself(oldfront);
12671  // Get an adjacent tet at face: [j]b.p_j.p_j-1.
12672  sym(oldfront, adjfront); // adjfront may be dummy.
12673  // Get the corresponding face from the new tets.
12674  // j >= 2.
12675  enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1
12676  bond(newfront, adjfront);
12677  if (checksubfaces) {
12678  tspivot(oldfront, checksh);
12679  if (checksh.sh != dummysh) {
12680  tsbond(newfront, checksh);
12681  }
12682  }
12683  }
12684  // Adjust the faces in the temporary new tets at ab for
12685  // recursively processing on the n-1 tets.
12686  for (j = 0; j < n - 1; j++) {
12687  fnextself(tmpabtetlist[j]);
12688  }
12689  tmpkey2 = -1;
12690  if (key) tmpkey2 = *key;
12691  if ((n - 1) == 3) {
12692  success = removeedgebyflip32(&tmpkey2, tmpabtetlist,
12693  &(newtetlist[m - 1]), flipque);
12694  } else { // assert((n - 1) >= 4);
12695  success = removeedgebytranNM(&tmpkey2, n - 1, tmpabtetlist,
12696  &(newtetlist[m - 1]), NULL, NULL, flipque);
12697  }
12698  // No matter it was success or not, delete the temporary tets.
12699  for (j = 0; j < n - 1; j++) {
12700  tetrahedrondealloc(tmpabtetlist[j].tet);
12701  }
12702  if (success) {
12703  // The new configuration is good.
12704  // Do not delete the old tets.
12705  // for (j = 0; j < n; j++) {
12706  // tetrahedrondealloc(abtetlist[j].tet);
12707  // }
12708  // Return the bigger dihedral in the two sets of new tets.
12709  if (key != (REAL *) NULL) {
12710  *key = tmpkey2 < tmpkey ? tmpkey2 : tmpkey;
12711  }
12712  return true;
12713  } else {
12714  // The new configuration is bad, substitue back the old tets.
12715  for (j = 0; j < n; j++) {
12716  oldfront = abtetlist[(i + j) % n];
12717  esymself(oldfront);
12718  enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1.
12719  sym(oldfront, adjfront); // adjfront may be dummy.
12720  bond(oldfront, adjfront);
12721  if (checksubfaces) {
12722  tspivot(oldfront, checksh);
12723  if (checksh.sh != dummysh) {
12724  tsbond(oldfront, checksh);
12725  }
12726  }
12727  }
12728  for (j = 0; j < n; j++) {
12729  oldfront = abtetlist[(i + j) % n];
12730  esymself(oldfront);
12731  enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12732  sym(oldfront, adjfront); // adjfront may be dummy
12733  bond(oldfront, adjfront);
12734  if (checksubfaces) {
12735  tspivot(oldfront, checksh);
12736  if (checksh.sh != dummysh) {
12737  tsbond(oldfront, checksh);
12738  }
12739  }
12740  }
12741  // Substitute back the old tets of the first flip.
12742  for (j = 0; j < *n1; j++) {
12743  oldfront = bftetlist[j];
12744  esymself(oldfront);
12745  enextfnextself(oldfront);
12746  sym(oldfront, adjfront); // adjfront may be dummy.
12747  bond(oldfront, adjfront);
12748  if (checksubfaces) {
12749  tspivot(oldfront, checksh);
12750  if (checksh.sh != dummysh) {
12751  tsbond(oldfront, checksh);
12752  }
12753  }
12754  }
12755  for (j = 0; j < *n1; j++) {
12756  oldfront = bftetlist[j];
12757  esymself(oldfront);
12758  enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1.
12759  sym(oldfront, adjfront); // adjfront may be dummy
12760  bond(oldfront, adjfront);
12761  if (checksubfaces) {
12762  tspivot(oldfront, checksh);
12763  if (checksh.sh != dummysh) {
12764  tsbond(oldfront, checksh);
12765  }
12766  }
12767  }
12768  // Delete the new tets of the first flip. Note that one new
12769  // tet has already been removed from the list.
12770  for (j = 0; j < m - 1; j++) {
12771  tetrahedrondealloc(newtetlist[j].tet);
12772  }
12773  } // if (success)
12774  } // if (success)
12775  } // if (doflip)
12776  } // if (ori <= 0.0)
12777  } // for (i = 0; i < n; i++)
12778  // Inverse a and b and the tets configuration.
12779  for (i = 0; i < n; i++) newtetlist[i] = abtetlist[i];
12780  for (i = 0; i < n; i++) {
12781  oldfront = newtetlist[n - i - 1];
12782  esymself(oldfront);
12783  fnextself(oldfront);
12784  abtetlist[i] = oldfront;
12785  }
12786  twice++;
12787  } while (twice < 2);
12788 
12789  return false;
12790 }
12791 
12793 // //
12794 // splittetrahedron() Insert a point into a tetrahedron, split it into //
12795 // four tetrahedra. //
12796 // //
12797 // The tetrahedron is given by 'splittet'. Let it is abcd. The inserting //
12798 // point 'newpoint' v should lie strictly inside abcd. //
12799 // //
12800 // Splitting a tetrahedron is to shrink abcd to abcv, and create three new //
12801 // tetrahedra badv, cbdv, and acdv. //
12802 // //
12803 // On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it //
12804 // contains all possibly non-locally Delaunay faces. //
12805 // //
12807 
12808 void tetgenmesh::splittetrahedron(point newpoint, triface* splittet,
12809  queue* flipqueue)
12810 {
12811  triface oldabd, oldbcd, oldcad; // Old configuration.
12812  triface abdcasing, bcdcasing, cadcasing;
12813  face abdsh, bcdsh, cadsh;
12814  triface abcv, badv, cbdv, acdv; // New configuration.
12815  triface worktet;
12816  face abseg, bcseg, caseg;
12817  face adseg, bdseg, cdseg;
12818  point pa, pb, pc, pd;
12819  REAL attrib, volume;
12820  int i;
12821 
12822  abcv = *splittet;
12823  abcv.ver = 0;
12824  // Set the changed vertices and new tetrahedron.
12825  pa = org(abcv);
12826  pb = dest(abcv);
12827  pc = apex(abcv);
12828  pd = oppo(abcv);
12829 
12830  if (b->verbose > 1) {
12831  printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n",
12832  pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc),
12833  pointmark(pd));
12834  }
12835 
12836  fnext(abcv, oldabd);
12837  enextfnext(abcv, oldbcd);
12838  enext2fnext(abcv, oldcad);
12839  sym(oldabd, abdcasing);
12840  sym(oldbcd, bcdcasing);
12841  sym(oldcad, cadcasing);
12842  maketetrahedron(&badv);
12843  maketetrahedron(&cbdv);
12844  maketetrahedron(&acdv);
12845 
12846  // Set 'badv' vertices.
12847  setorg (badv, pb);
12848  setdest(badv, pa);
12849  setapex(badv, pd);
12850  setoppo(badv, newpoint);
12851  // Set 'cbdv' vertices.
12852  setorg (cbdv, pc);
12853  setdest(cbdv, pb);
12854  setapex(cbdv, pd);
12855  setoppo(cbdv, newpoint);
12856  // Set 'acdv' vertices.
12857  setorg (acdv, pa);
12858  setdest(acdv, pc);
12859  setapex(acdv, pd);
12860  setoppo(acdv, newpoint);
12861  // Set 'abcv' vertices
12862  setoppo(abcv, newpoint);
12863 
12864  // Set the element attributes of the new tetrahedra.
12865  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
12866  attrib = elemattribute(abcv.tet, i);
12867  setelemattribute(badv.tet, i, attrib);
12868  setelemattribute(cbdv.tet, i, attrib);
12869  setelemattribute(acdv.tet, i, attrib);
12870  }
12871  // Set the volume constraint of the new tetrahedra.
12872  if (b->varvolume) {
12873  volume = volumebound(abcv.tet);
12874  setvolumebound(badv.tet, volume);
12875  setvolumebound(cbdv.tet, volume);
12876  setvolumebound(acdv.tet, volume);
12877  }
12878 
12879  // Bond the new triangles to the surrounding tetrahedron.
12880  bond(badv, abdcasing);
12881  bond(cbdv, bcdcasing);
12882  bond(acdv, cadcasing);
12883  // There may exist subfaces need to be bonded to the new tetrahedra.
12884  if (checksubfaces) {
12885  tspivot(oldabd, abdsh);
12886  if (abdsh.sh != dummysh) {
12887  tsdissolve(oldabd);
12888  tsbond(badv, abdsh);
12889  }
12890  tspivot(oldbcd, bcdsh);
12891  if (bcdsh.sh != dummysh) {
12892  tsdissolve(oldbcd);
12893  tsbond(cbdv, bcdsh);
12894  }
12895  tspivot(oldcad, cadsh);
12896  if (cadsh.sh != dummysh) {
12897  tsdissolve(oldcad);
12898  tsbond(acdv, cadsh);
12899  }
12900  } else if (checksubsegs) {
12901  tsspivot1(abcv, abseg);
12902  if (abseg.sh != dummysh) {
12903  tssbond1(badv, abseg);
12904  }
12905  enext(abcv, worktet);
12906  tsspivot1(worktet, bcseg);
12907  if (bcseg.sh != dummysh) {
12908  tssbond1(cbdv, bcseg);
12909  }
12910  enext2(abcv, worktet);
12911  tsspivot1(worktet, caseg);
12912  if (caseg.sh != dummysh) {
12913  tssbond1(acdv, caseg);
12914  }
12915  fnext(abcv, worktet);
12916  enext2self(worktet);
12917  tsspivot1(worktet, adseg);
12918  if (adseg.sh != dummysh) {
12919  tssdissolve1(worktet);
12920  enext(badv, worktet);
12921  tssbond1(worktet, adseg);
12922  enext2(acdv, worktet);
12923  tssbond1(worktet, adseg);
12924  }
12925  enextfnext(abcv, worktet);
12926  enext2self(worktet);
12927  tsspivot1(worktet, bdseg);
12928  if (bdseg.sh != dummysh) {
12929  tssdissolve1(worktet);
12930  enext(cbdv, worktet);
12931  tssbond1(worktet, bdseg);
12932  enext2(badv, worktet);
12933  tssbond1(worktet, bdseg);
12934  }
12935  enext2fnext(abcv, worktet);
12936  enext2self(worktet);
12937  tsspivot1(worktet, cdseg);
12938  if (cdseg.sh != dummysh) {
12939  tssdissolve1(worktet);
12940  enext(acdv, worktet);
12941  tssbond1(worktet, cdseg);
12942  enext2(cbdv, worktet);
12943  tssbond1(worktet, cdseg);
12944  }
12945  }
12946  badv.loc = 3;
12947  cbdv.loc = 2;
12948  bond(badv, cbdv);
12949  cbdv.loc = 3;
12950  acdv.loc = 2;
12951  bond(cbdv, acdv);
12952  acdv.loc = 3;
12953  badv.loc = 2;
12954  bond(acdv, badv);
12955  badv.loc = 1;
12956  bond(badv, oldabd);
12957  cbdv.loc = 1;
12958  bond(cbdv, oldbcd);
12959  acdv.loc = 1;
12960  bond(acdv, oldcad);
12961 
12962  badv.loc = 0;
12963  cbdv.loc = 0;
12964  acdv.loc = 0;
12965  if (b->verbose > 3) {
12966  printf(" Updating abcv ");
12967  printtet(&abcv);
12968  printf(" Creating badv ");
12969  printtet(&badv);
12970  printf(" Creating cbdv ");
12971  printtet(&cbdv);
12972  printf(" Creating acdv ");
12973  printtet(&acdv);
12974  }
12975 
12976  if (flipqueue != (queue *) NULL) {
12977  enqueueflipface(abcv, flipqueue);
12978  enqueueflipface(badv, flipqueue);
12979  enqueueflipface(cbdv, flipqueue);
12980  enqueueflipface(acdv, flipqueue);
12981  }
12982 
12983  // Save a handle for quick point location.
12984  recenttet = abcv;
12985  // Set the return handle be abcv.
12986  *splittet = abcv;
12987 }
12988 
12990 // //
12991 // unsplittetrahedron() Reverse the operation of inserting a point into a //
12992 // tetrahedron, so as to remove the newly inserted //
12993 // point from the mesh. //
12994 // //
12995 // Assume the origional tetrahedron is abcd, it was split by v into four //
12996 // tetrahedra abcv, badv, cbdv, and acdv. 'splittet' represents face abc of //
12997 // abcv (i.e., its opposite is v). //
12998 // //
12999 // Point v is removed by expanding abcv to abcd, deleting three tetrahedra //
13000 // badv, cbdv and acdv. On return, point v is not deleted in this routine. //
13001 // //
13003 
13004 void tetgenmesh::unsplittetrahedron(triface* splittet)
13005 {
13006  triface abcv, badv, cbdv, acdv;
13007  triface oldabv, oldbcv, oldcav;
13008  triface badcasing, cbdcasing, acdcasing;
13009  face badsh, cbdsh, acdsh;
13010 
13011  abcv = *splittet;
13012  adjustedgering(abcv, CCW); // for sure.
13013  fnext(abcv, oldabv);
13014  fnext(oldabv, badv);
13015  esymself(badv);
13016  enextfnext(abcv, oldbcv);
13017  fnext(oldbcv, cbdv);
13018  esymself(cbdv);
13019  enext2fnext(abcv, oldcav);
13020  fnext(oldcav, acdv);
13021  esymself(acdv);
13022 
13023  if (b->verbose > 1) {
13024  printf(" Removing point %d in tetrahedron (%d, %d, %d, %d).\n",
13025  pointmark(oppo(abcv)), pointmark(org(abcv)), pointmark(dest(abcv)),
13026  pointmark(apex(abcv)), pointmark(apex(badv)));
13027  }
13028 
13029  sym(badv, badcasing);
13030  tspivot(badv, badsh);
13031  sym(cbdv, cbdcasing);
13032  tspivot(cbdv, cbdsh);
13033  sym(acdv, acdcasing);
13034  tspivot(acdv, acdsh);
13035 
13036  // Expanding abcv to abcd.
13037  setoppo(abcv, apex(badv));
13038  bond(oldabv, badcasing);
13039  if (badsh.sh != dummysh) {
13040  tsbond(oldabv, badsh);
13041  }
13042  bond(oldbcv, cbdcasing);
13043  if (cbdsh.sh != dummysh) {
13044  tsbond(oldbcv, cbdsh);
13045  }
13046  bond(oldcav, acdcasing);
13047  if (acdsh.sh != dummysh) {
13048  tsbond(oldcav, acdsh);
13049  }
13050 
13051  // Delete the three split-out tetrahedra.
13052  tetrahedrondealloc(badv.tet);
13053  tetrahedrondealloc(cbdv.tet);
13054  tetrahedrondealloc(acdv.tet);
13055 }
13056 
13058 // //
13059 // splittetface() Insert a point on a face of a mesh. //
13060 // //
13061 // 'splittet' is the splitting face. Let it is abcd, where abc is the face //
13062 // will be split. If abc is not a hull face, abce is the tetrahedron at the //
13063 // opposite of d. //
13064 // //
13065 // To split face abc by a point v is to shrink the tetrahedra abcd to abvd, //
13066 // create two new tetrahedra bcvd, cavd. If abc is not a hull face, shrink //
13067 // the tetrahedra bace to bave, create two new tetrahedra cbve, acve. //
13068 // //
13069 // If abc is a subface, it is split into three subfaces simultaneously by //
13070 // calling routine splitsubface(), hence, abv, bcv, cav. The edge rings of //
13071 // the split subfaces have the same orientation as abc's. //
13072 // //
13073 // On completion, 'splittet' returns abvd. If 'flipqueue' is not NULL, it //
13074 // contains all possibly non-locally Delaunay faces. //
13075 // //
13077 
13078 void tetgenmesh::splittetface(point newpoint, triface* splittet,
13079  queue* flipqueue)
13080 {
13081  triface abcd, bace; // Old configuration.
13082  triface oldbcd, oldcad, oldace, oldcbe;
13083  triface bcdcasing, cadcasing, acecasing, cbecasing;
13084  face abcsh, bcdsh, cadsh, acesh, cbesh;
13085  triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration.
13086  triface worktet;
13087  face bcseg, caseg;
13088  face adseg, bdseg, cdseg;
13089  face aeseg, beseg, ceseg;
13090  point pa, pb, pc, pd, pe;
13091  REAL attrib, volume;
13092  bool mirrorflag;
13093  int i;
13094 
13095  abcd = *splittet;
13096  // abcd.ver = 0; // Adjust to be CCW edge ring.
13097  adjustedgering(abcd, CCW);
13098  pa = org(abcd);
13099  pb = dest(abcd);
13100  pc = apex(abcd);
13101  pd = oppo(abcd);
13102  pe = (point) NULL; // avoid a compile warning.
13103  // Is there a second tetrahderon?
13104  mirrorflag = issymexist(&abcd);
13105  if (mirrorflag) {
13106  // This is an interior face.
13107  sym(abcd, bace);
13108  findedge(&bace, dest(abcd), org(abcd));
13109  pe = oppo(bace);
13110  }
13111  if (checksubfaces) {
13112  // Is there a subface need to be split together?
13113  tspivot(abcd, abcsh);
13114  if (abcsh.sh != dummysh) {
13115  // Exists! Keep the edge ab of both handles be the same.
13116  findedge(&abcsh, org(abcd), dest(abcd));
13117  }
13118  }
13119 
13120  if (b->verbose > 1) {
13121  printf(" Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint),
13122  pointmark(pa), pointmark(pb), pointmark(pc));
13123  }
13124 
13125  // Save the old configuration at faces bcd and cad.
13126  enextfnext(abcd, oldbcd);
13127  enext2fnext(abcd, oldcad);
13128  sym(oldbcd, bcdcasing);
13129  sym(oldcad, cadcasing);
13130  // Create two new tetrahedra.
13131  maketetrahedron(&bcvd);
13132  maketetrahedron(&cavd);
13133  if (mirrorflag) {
13134  // Save the old configuration at faces bce and cae.
13135  enextfnext(bace, oldace);
13136  enext2fnext(bace, oldcbe);
13137  sym(oldace, acecasing);
13138  sym(oldcbe, cbecasing);
13139  // Create two new tetrahedra.
13140  maketetrahedron(&acve);
13141  maketetrahedron(&cbve);
13142  } else {
13143  // Splitting a boundary face increases the number of boundary faces.
13144  hullsize += 2;
13145  }
13146 
13147  // Set vertices to the changed tetrahedron and new tetrahedra.
13148  abvd = abcd; // Update 'abcd' to 'abvd'.
13149  setapex(abvd, newpoint);
13150  setorg (bcvd, pb); // Set 'bcvd'.
13151  setdest(bcvd, pc);
13152  setapex(bcvd, newpoint);
13153  setoppo(bcvd, pd);
13154  setorg (cavd, pc); // Set 'cavd'.
13155  setdest(cavd, pa);
13156  setapex(cavd, newpoint);
13157  setoppo(cavd, pd);
13158  // Set the element attributes of the new tetrahedra.
13159  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
13160  attrib = elemattribute(abvd.tet, i);
13161  setelemattribute(bcvd.tet, i, attrib);
13162  setelemattribute(cavd.tet, i, attrib);
13163  }
13164  if (b->varvolume) {
13165  // Set the area constraint of the new tetrahedra.
13166  volume = volumebound(abvd.tet);
13167  setvolumebound(bcvd.tet, volume);
13168  setvolumebound(cavd.tet, volume);
13169  }
13170  if (mirrorflag) {
13171  bave = bace; // Update 'bace' to 'bave'.
13172  setapex(bave, newpoint);
13173  setorg (acve, pa); // Set 'acve'.
13174  setdest(acve, pc);
13175  setapex(acve, newpoint);
13176  setoppo(acve, pe);
13177  setorg (cbve, pc); // Set 'cbve'.
13178  setdest(cbve, pb);
13179  setapex(cbve, newpoint);
13180  setoppo(cbve, pe);
13181  // Set the element attributes of the new tetrahedra.
13182  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
13183  attrib = elemattribute(bave.tet, i);
13184  setelemattribute(acve.tet, i, attrib);
13185  setelemattribute(cbve.tet, i, attrib);
13186  }
13187  if (b->varvolume) {
13188  // Set the area constraint of the new tetrahedra.
13189  volume = volumebound(bave.tet);
13190  setvolumebound(acve.tet, volume);
13191  setvolumebound(cbve.tet, volume);
13192  }
13193  }
13194 
13195  // Bond the new tetrahedra to the surrounding tetrahedra.
13196  bcvd.loc = 1;
13197  bond(bcvd, bcdcasing);
13198  cavd.loc = 1;
13199  bond(cavd, cadcasing);
13200  bcvd.loc = 3;
13201  bond(bcvd, oldbcd);
13202  cavd.loc = 2;
13203  bond(cavd, oldcad);
13204  bcvd.loc = 2;
13205  cavd.loc = 3;
13206  bond(bcvd, cavd);
13207  if (mirrorflag) {
13208  acve.loc = 1;
13209  bond(acve, acecasing);
13210  cbve.loc = 1;
13211  bond(cbve, cbecasing);
13212  acve.loc = 3;
13213  bond(acve, oldace);
13214  cbve.loc = 2;
13215  bond(cbve, oldcbe);
13216  acve.loc = 2;
13217  cbve.loc = 3;
13218  bond(acve, cbve);
13219  // Bond two new coplanar facets.
13220  bcvd.loc = 0;
13221  cbve.loc = 0;
13222  bond(bcvd, cbve);
13223  cavd.loc = 0;
13224  acve.loc = 0;
13225  bond(cavd, acve);
13226  }
13227 
13228  // There may exist subface needed to be bonded to the new tetrahedra.
13229  if (checksubfaces) {
13230  tspivot(oldbcd, bcdsh);
13231  if (bcdsh.sh != dummysh) {
13232  tsdissolve(oldbcd);
13233  bcvd.loc = 1;
13234  tsbond(bcvd, bcdsh);
13235  }
13236  tspivot(oldcad, cadsh);
13237  if (cadsh.sh != dummysh) {
13238  tsdissolve(oldcad);
13239  cavd.loc = 1;
13240  tsbond(cavd, cadsh);
13241  }
13242  if (mirrorflag) {
13243  tspivot(oldace, acesh);
13244  if (acesh.sh != dummysh) {
13245  tsdissolve(oldace);
13246  acve.loc = 1;
13247  tsbond(acve, acesh);
13248  }
13249  tspivot(oldcbe, cbesh);
13250  if (cbesh.sh != dummysh) {
13251  tsdissolve(oldcbe);
13252  cbve.loc = 1;
13253  tsbond(cbve, cbesh);
13254  }
13255  }
13256  // Is there a subface needs to be split together?
13257  if (abcsh.sh != dummysh) {
13258  // Split this subface 'abc' into three i.e, abv, bcv, cav.
13259  splitsubface(newpoint, &abcsh, (queue *) NULL);
13260  }
13261  } else if (checksubsegs) {
13262  // abvd.loc = abvd.ver = 0;
13263  bcvd.loc = bcvd.ver = 0;
13264  cavd.loc = cavd.ver = 0;
13265  if (mirrorflag) {
13266  // bave.loc = bave.ver = 0;
13267  cbve.loc = cbve.ver = 0;
13268  acve.loc = acve.ver = 0;
13269  }
13270  enext(abvd, worktet);
13271  tsspivot1(worktet, bcseg);
13272  if (bcseg.sh != dummysh) {
13273  tssdissolve1(worktet);
13274  tssbond1(bcvd, bcseg);
13275  if (mirrorflag) {
13276  enext2(bave, worktet);
13277  tssdissolve1(worktet);
13278  tssbond1(cbve, bcseg);
13279  }
13280  }
13281  enext2(abvd, worktet);
13282  tsspivot1(worktet, caseg);
13283  if (caseg.sh != dummysh) {
13284  tssdissolve1(worktet);
13285  tssbond1(cavd, caseg);
13286  if (mirrorflag) {
13287  enext(bave, worktet);
13288  tssdissolve1(worktet);
13289  tssbond1(acve, caseg);
13290  }
13291  }
13292  fnext(abvd, worktet);
13293  enext2self(worktet);
13294  tsspivot1(worktet, adseg);
13295  if (adseg.sh != dummysh) {
13296  fnext(cavd, worktet);
13297  enextself(worktet);
13298  tssbond1(worktet, adseg);
13299  }
13300  fnext(abvd, worktet);
13301  enextself(worktet);
13302  tsspivot1(worktet, bdseg);
13303  if (bdseg.sh != dummysh) {
13304  fnext(bcvd, worktet);
13305  enext2self(worktet);
13306  tssbond1(worktet, bdseg);
13307  }
13308  enextfnext(abvd, worktet);
13309  enextself(worktet);
13310  tsspivot1(worktet, cdseg);
13311  if (cdseg.sh != dummysh) {
13312  tssdissolve1(worktet);
13313  fnext(bcvd, worktet);
13314  enextself(worktet);
13315  tssbond1(worktet, cdseg);
13316  fnext(cavd, worktet);
13317  enext2self(worktet);
13318  tssbond1(worktet, cdseg);
13319  }
13320  if (mirrorflag) {
13321  fnext(bave, worktet);
13322  enextself(worktet);
13323  tsspivot1(worktet, aeseg);
13324  if (aeseg.sh != dummysh) {
13325  fnext(acve, worktet);
13326  enext2self(worktet);
13327  tssbond1(worktet, aeseg);
13328  }
13329  fnext(bave, worktet);
13330  enext2self(worktet);
13331  tsspivot1(worktet, beseg);
13332  if (beseg.sh != dummysh) {
13333  fnext(cbve, worktet);
13334  enextself(worktet);
13335  tssbond1(worktet, beseg);
13336  }
13337  enextfnext(bave, worktet);
13338  enextself(worktet);
13339  tsspivot1(worktet, ceseg);
13340  if (ceseg.sh != dummysh) {
13341  tssdissolve1(worktet);
13342  fnext(cbve, worktet);
13343  enext2self(worktet);
13344  tssbond1(worktet, ceseg);
13345  fnext(acve, worktet);
13346  enextself(worktet);
13347  tssbond1(worktet, ceseg);
13348  }
13349  }
13350  }
13351 
13352  // Save a handle for quick point location.
13353  recenttet = abvd;
13354  // Set the return handle be abvd.
13355  *splittet = abvd;
13356 
13357  bcvd.loc = 0;
13358  cavd.loc = 0;
13359  if (mirrorflag) {
13360  cbve.loc = 0;
13361  acve.loc = 0;
13362  }
13363  if (b->verbose > 3) {
13364  printf(" Updating abvd ");
13365  printtet(&abvd);
13366  printf(" Creating bcvd ");
13367  printtet(&bcvd);
13368  printf(" Creating cavd ");
13369  printtet(&cavd);
13370  if (mirrorflag) {
13371  printf(" Updating bave ");
13372  printtet(&bave);
13373  printf(" Creating cbve ");
13374  printtet(&cbve);
13375  printf(" Creating acve ");
13376  printtet(&acve);
13377  }
13378  }
13379 
13380  if (flipqueue != (queue *) NULL) {
13381  fnextself(abvd);
13382  enqueueflipface(abvd, flipqueue);
13383  fnextself(bcvd);
13384  enqueueflipface(bcvd, flipqueue);
13385  fnextself(cavd);
13386  enqueueflipface(cavd, flipqueue);
13387  if (mirrorflag) {
13388  fnextself(bave);
13389  enqueueflipface(bave, flipqueue);
13390  fnextself(cbve);
13391  enqueueflipface(cbve, flipqueue);
13392  fnextself(acve);
13393  enqueueflipface(acve, flipqueue);
13394  }
13395  }
13396 }
13397 
13399 // //
13400 // unsplittetface() Reverse the operation of inserting a point on a face, //
13401 // so as to remove the newly inserted point. //
13402 // //
13403 // Assume the original face is abc, the tetrahedron containing abc is abcd. //
13404 // If abc is not a hull face, bace is the tetrahedron at the opposite of d. //
13405 // After face abc was split by a point v, tetrahedron abcd had been split //
13406 // into three tetrahedra, abvd, bcvd, cavd, and bace (if it exists) had been //
13407 // split into bave, cbve, acve. 'splittet' represents abvd (its apex is v). //
13408 // //
13409 // Point v is removed by expanding abvd to abcd, deleting two tetrahedra //
13410 // bcvd, cavd. Expanding bave(if it exists) to bace, deleting two tetrahedra //
13411 // cbve, acve. If abv is a subface, routine unsplitsubface() will be called //
13412 // to reverse the operation of splitting a subface. On completion, point v //
13413 // is not deleted in this routine. //
13414 // //
13416 
13417 void tetgenmesh::unsplittetface(triface* splittet)
13418 {
13419  triface abvd, bcvd, cavd, bave, cbve, acve;
13420  triface oldbvd, oldvad, oldvbe, oldave;
13421  triface bcdcasing, cadcasing, cbecasing, acecasing;
13422  face bcdsh, cadsh, cbesh, acesh;
13423  face abvsh;
13424  bool mirrorflag;
13425 
13426  abvd = *splittet;
13427  adjustedgering(abvd, CCW); // for sure.
13428  enextfnext(abvd, oldbvd);
13429  fnext(oldbvd, bcvd);
13430  esymself(bcvd);
13431  enextself(bcvd);
13432  enext2fnext(abvd, oldvad);
13433  fnext(oldvad, cavd);
13434  esymself(cavd);
13435  enext2self(cavd);
13436  // Is there a second tetrahedron?
13437  sym(abvd, bave);
13438  mirrorflag = bave.tet != dummytet;
13439  if (mirrorflag) {
13440  findedge(&bave, dest(abvd), org(abvd));
13441  enextfnext(bave, oldave);
13442  fnext(oldave, acve);
13443  esymself(acve);
13444  enextself(acve);
13445  enext2fnext(bave, oldvbe);
13446  fnext(oldvbe, cbve);
13447  esymself(cbve);
13448  enext2self(cbve);
13449  } else {
13450  // Unsplit a hull face decrease the number of boundary faces.
13451  hullsize -= 2;
13452  }
13453  // Is there a subface at abv.
13454  tspivot(abvd, abvsh);
13455  if (abvsh.sh != dummysh) {
13456  // Exists! Keep the edge ab of both handles be the same.
13457  findedge(&abvsh, org(abvd), dest(abvd));
13458  }
13459 
13460  if (b->verbose > 1) {
13461  printf(" Removing point %d on face (%d, %d, %d).\n",
13462  pointmark(apex(abvd)), pointmark(org(abvd)), pointmark(dest(abvd)),
13463  pointmark(dest(bcvd)));
13464  }
13465 
13466  fnextself(bcvd); // bcvd has changed to bcdv.
13467  sym(bcvd, bcdcasing);
13468  tspivot(bcvd, bcdsh);
13469  fnextself(cavd); // cavd has changed to cadv.
13470  sym(cavd, cadcasing);
13471  tspivot(cavd, cadsh);
13472  if (mirrorflag) {
13473  fnextself(acve); // acve has changed to acev.
13474  sym(acve, acecasing);
13475  tspivot(acve, acesh);
13476  fnextself(cbve); // cbve has changed to cbev.
13477  sym(cbve, cbecasing);
13478  tspivot(cbve, cbesh);
13479  }
13480 
13481  // Expand abvd to abcd.
13482  setapex(abvd, dest(bcvd));
13483  bond(oldbvd, bcdcasing);
13484  if (bcdsh.sh != dummysh) {
13485  tsbond(oldbvd, bcdsh);
13486  }
13487  bond(oldvad, cadcasing);
13488  if (cadsh.sh != dummysh) {
13489  tsbond(oldvad, cadsh);
13490  }
13491  if (mirrorflag) {
13492  // Expanding bave to bace.
13493  setapex(bave, dest(acve));
13494  bond(oldave, acecasing);
13495  if (acesh.sh != dummysh) {
13496  tsbond(oldave, acesh);
13497  }
13498  bond(oldvbe, cbecasing);
13499  if (cbesh.sh != dummysh) {
13500  tsbond(oldvbe, cbesh);
13501  }
13502  }
13503 
13504  // Unsplit a subface if there exists.
13505  if (abvsh.sh != dummysh) {
13506  unsplitsubface(&abvsh);
13507  }
13508 
13509  // Delete the split-out tetrahedra.
13510  tetrahedrondealloc(bcvd.tet);
13511  tetrahedrondealloc(cavd.tet);
13512  if (mirrorflag) {
13513  tetrahedrondealloc(acve.tet);
13514  tetrahedrondealloc(cbve.tet);
13515  }
13516 }
13517 
13519 // //
13520 // splitsubface() Insert a point on a subface, split it into three. //
13521 // //
13522 // The subface is 'splitface'. Let it is abc. The inserting point 'newpoint'//
13523 // v should lie inside abc. If the neighbor tetrahedra of abc exist, i.e., //
13524 // abcd and bace, they should have been split by routine splittetface() //
13525 // before calling this routine, so the connection between the new tetrahedra //
13526 // and new subfaces can be correctly set. //
13527 // //
13528 // To split subface abc by point v is to shrink abc to abv, create two new //
13529 // subfaces bcv and cav. Set the connection between updated and new created //
13530 // subfaces. If there is a subsegment at edge bc or ca, connection of new //
13531 // subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is //
13532 // the predecessor and 'casingout' is the successor. It is important to keep //
13533 // the orientations of the edge rings of the updated and created subfaces be //
13534 // the same as abc's. So they have the same orientation as other subfaces of //
13535 // this facet with respect to the lift point of this facet. //
13536 // //
13537 // On completion, 'splitface' returns abv. If 'flipqueue' is not NULL, it //
13538 // returns all possibly non-Delaunay edges. //
13539 // //
13541 
13542 void tetgenmesh::splitsubface(point newpoint, face* splitface,
13543  queue* flipqueue)
13544 {
13545  triface abvd, bcvd, cavd, bave, cbve, acve;
13546  face abc, oldbc, oldca, bc, ca, spinsh;
13547  face bccasin, bccasout, cacasin, cacasout;
13548  face abv, bcv, cav;
13549  point pa, pb, pc;
13550 
13551  abc = *splitface;
13552  // The newly created subfaces will have the same edge ring as abc.
13553  adjustedgering(abc, CCW);
13554  pa = sorg(abc);
13555  pb = sdest(abc);
13556  pc = sapex(abc);
13557 
13558  if (b->verbose > 1) {
13559  printf(" Inserting point %d on subface (%d, %d, %d).\n",
13560  pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc));
13561  }
13562 
13563  // Save the old configuration at edge bc and ca. Subsegments may appear
13564  // at both sides, save the face links and dissolve them.
13565  senext(abc, oldbc);
13566  senext2(abc, oldca);
13567  spivot(oldbc, bccasout);
13568  sspivot(oldbc, bc);
13569  if (bc.sh != dummysh) {
13570  if (oldbc.sh != bccasout.sh) {
13571  // 'oldbc' is not self-bonded.
13572  spinsh = bccasout;
13573  do {
13574  bccasin = spinsh;
13575  spivotself(spinsh);
13576  } while (spinsh.sh != oldbc.sh);
13577  } else {
13578  bccasout.sh = dummysh;
13579  }
13580  ssdissolve(oldbc);
13581  }
13582  spivot(oldca, cacasout);
13583  sspivot(oldca, ca);
13584  if (ca.sh != dummysh) {
13585  if (oldca.sh != cacasout.sh) {
13586  // 'oldca' is not self-bonded.
13587  spinsh = cacasout;
13588  do {
13589  cacasin = spinsh;
13590  spivotself(spinsh);
13591  } while (spinsh.sh != oldca.sh);
13592  } else {
13593  cacasout.sh = dummysh;
13594  }
13595  ssdissolve(oldca);
13596  }
13597  // Create two new subfaces.
13598  makeshellface(subfaces, &bcv);
13599  makeshellface(subfaces, &cav);
13600 
13601  // Set the vertices of changed and new subfaces.
13602  abv = abc; // Update 'abc' to 'abv'.
13603  setsapex(abv, newpoint);
13604  setsorg(bcv, pb); // Set 'bcv'.
13605  setsdest(bcv, pc);
13606  setsapex(bcv, newpoint);
13607  setsorg(cav, pc); // Set 'cav'.
13608  setsdest(cav, pa);
13609  setsapex(cav, newpoint);
13610  if (b->quality && varconstraint) {
13611  // Copy yhr area bound into the new subfaces.
13612  setareabound(bcv, areabound(abv));
13613  setareabound(cav, areabound(abv));
13614  }
13615  // Copy the boundary mark into the new subfaces.
13616  setshellmark(bcv, shellmark(abv));
13617  setshellmark(cav, shellmark(abv));
13618  // Copy the subface type into the new subfaces.
13619  setshelltype(bcv, shelltype(abv));
13620  setshelltype(cav, shelltype(abv));
13621  if (checkpbcs) {
13622  // Copy the pbcgroup into the new subfaces.
13623  setshellpbcgroup(bcv, shellpbcgroup(abv));
13624  setshellpbcgroup(cav, shellpbcgroup(abv));
13625  }
13626  // Bond the new subfaces to the surrounding subfaces.
13627  if (bc.sh != dummysh) {
13628  if (bccasout.sh != dummysh) {
13629  sbond1(bccasin, bcv);
13630  sbond1(bcv, bccasout);
13631  } else {
13632  // Bond 'bcv' to itsself.
13633  sbond(bcv, bcv);
13634  }
13635  ssbond(bcv, bc);
13636  } else {
13637  sbond(bcv, bccasout);
13638  }
13639  if (ca.sh != dummysh) {
13640  if (cacasout.sh != dummysh) {
13641  sbond1(cacasin, cav);
13642  sbond1(cav, cacasout);
13643  } else {
13644  // Bond 'cav' to itself.
13645  sbond(cav, cav);
13646  }
13647  ssbond(cav, ca);
13648  } else {
13649  sbond(cav, cacasout);
13650  }
13651  senext2self(bcv);
13652  sbond(bcv, oldbc);
13653  senextself(cav);
13654  sbond(cav, oldca);
13655  senext2self(bcv);
13656  senextself(cav);
13657  sbond(bcv, cav);
13658 
13659  // Bond the new subfaces to the new tetrahedra if they exist.
13660  stpivot(abv, abvd);
13661  if (abvd.tet != dummytet) {
13662  // Get two new tetrahedra and their syms.
13663  findedge(&abvd, sorg(abv), sdest(abv));
13664  enextfnext(abvd, bcvd);
13665 #ifdef SELF_CHECK
13666  assert(bcvd.tet != dummytet);
13667 #endif
13668  fnextself(bcvd);
13669  enext2fnext(abvd, cavd);
13670 #ifdef SELF_CHECK
13671  assert(cavd.tet != dummytet);
13672 #endif
13673  fnextself(cavd);
13674  // Bond two new subfaces to the two new tetrahedra.
13675  tsbond(bcvd, bcv);
13676  tsbond(cavd, cav);
13677  }
13678  // Set the connection at the other sides if the tetrahedra exist.
13679  sesymself(abv); // bav
13680  stpivot(abv, bave);
13681  if (bave.tet != dummytet) {
13682  sesymself(bcv); // cbv
13683  sesymself(cav); // acv
13684  // Get two new tetrahedra and their syms.
13685  findedge(&bave, sorg(abv), sdest(abv));
13686  enextfnext(bave, acve);
13687 #ifdef SELF_CHECK
13688  assert(acve.tet != dummytet);
13689 #endif
13690  fnextself(acve);
13691  enext2fnext(bave, cbve);
13692 #ifdef SELF_CHECK
13693  assert(cbve.tet != dummytet);
13694 #endif
13695  fnextself(cbve);
13696  // Bond two new subfaces to the two new tetrahedra.
13697  tsbond(acve, cav);
13698  tsbond(cbve, bcv);
13699  }
13700 
13701  bcv.shver = 0;
13702  cav.shver = 0;
13703  if (b->verbose > 3) {
13704  printf(" Updating abv ");
13705  printsh(&abv);
13706  printf(" Creating bcv ");
13707  printsh(&bcv);
13708  printf(" Creating cav ");
13709  printsh(&cav);
13710  }
13711 
13712  if (flipqueue != (queue *) NULL) {
13713  enqueueflipedge(abv, flipqueue);
13714  enqueueflipedge(bcv, flipqueue);
13715  enqueueflipedge(cav, flipqueue);
13716  }
13717 
13718  // Set the return handle be abv.
13719  *splitface = abv;
13720 }
13721 
13723 // //
13724 // unsplitsubface() Reverse the operation of inserting a point on a //
13725 // subface, so as to remove the newly inserted point. //
13726 // //
13727 // Assume the original subface is abc, it was split by a point v into three //
13728 // subfaces abv, bcv and cav. 'splitsh' represents abv. //
13729 // //
13730 // To remove point v is to expand abv to abc, delete bcv and cav. If edge bc //
13731 // or ca is a subsegment, the connection at a subsegment is a subface link, //
13732 // '-casin' and '-casout' are used to save the predecessor and successor of //
13733 // bcv or cav. On completion, point v is not deleted in this routine. //
13734 // //
13736 
13737 void tetgenmesh::unsplitsubface(face* splitsh)
13738 {
13739  face abv, bcv, cav;
13740  face oldbv, oldva, bc, ca, spinsh;
13741  face bccasin, bccasout, cacasin, cacasout;
13742 
13743  abv = *splitsh;
13744  senext(abv, oldbv);
13745  spivot(oldbv, bcv);
13746  if (sorg(bcv) != sdest(oldbv)) {
13747  sesymself(bcv);
13748  }
13749  senextself(bcv);
13750  senext2(abv, oldva);
13751  spivot(oldva, cav);
13752  if (sorg(cav) != sdest(oldva)) {
13753  sesymself(cav);
13754  }
13755  senext2self(cav);
13756 
13757  if (b->verbose > 1) {
13758  printf(" Removing point %d on subface (%d, %d, %d).\n",
13759  pointmark(sapex(abv)), pointmark(sorg(abv)), pointmark(sdest(abv)),
13760  pointmark(sdest(bcv)));
13761  }
13762 
13763  spivot(bcv, bccasout);
13764  sspivot(bcv, bc);
13765  if (bc.sh != dummysh) {
13766  if (bcv.sh != bccasout.sh) {
13767  // 'bcv' is not self-bonded.
13768  spinsh = bccasout;
13769  do {
13770  bccasin = spinsh;
13771  spivotself(spinsh);
13772  } while (spinsh.sh != bcv.sh);
13773  } else {
13774  bccasout.sh = dummysh;
13775  }
13776  }
13777  spivot(cav, cacasout);
13778  sspivot(cav, ca);
13779  if (ca.sh != dummysh) {
13780  if (cav.sh != cacasout.sh) {
13781  // 'cav' is not self-bonded.
13782  spinsh = cacasout;
13783  do {
13784  cacasin = spinsh;
13785  spivotself(spinsh);
13786  } while (spinsh.sh != cav.sh);
13787  } else {
13788  cacasout.sh = dummysh;
13789  }
13790  }
13791 
13792  // Expand abv to abc.
13793  setsapex(abv, sdest(bcv));
13794  if (bc.sh != dummysh) {
13795  if (bccasout.sh != dummysh) {
13796  sbond1(bccasin, oldbv);
13797  sbond1(oldbv, bccasout);
13798  } else {
13799  // Bond 'oldbv' to itself.
13800  sbond(oldbv, oldbv);
13801  }
13802  ssbond(oldbv, bc);
13803  } else {
13804  sbond(oldbv, bccasout);
13805  }
13806  if (ca.sh != dummysh) {
13807  if (cacasout.sh != dummysh) {
13808  sbond1(cacasin, oldva);
13809  sbond1(oldva, cacasout);
13810  } else {
13811  // Bond 'oldva' to itself.
13812  sbond(oldva, oldva);
13813  }
13814  ssbond(oldva, ca);
13815  } else {
13816  sbond(oldva, cacasout);
13817  }
13818 
13819  // Delete two split-out subfaces.
13820  shellfacedealloc(subfaces, bcv.sh);
13821  shellfacedealloc(subfaces, cav.sh);
13822 }
13823 
13825 // //
13826 // splittetedge() Insert a point on an edge of the mesh. //
13827 // //
13828 // The edge is given by 'splittet'. Assume its four corners are a, b, n1 and //
13829 // n2, where ab is the edge will be split. Around ab may exist any number of //
13830 // tetrahedra. For convenience, they're ordered in a sequence following the //
13831 // right-hand rule with your thumb points from a to b. Let the vertex set of //
13832 // these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around //
13833 // ab may not connect to each other (can only happen when ab is a subsegment,//
13834 // hence some faces abn(i) are subfaces). If ab is a subsegment, abn1 must //
13835 // be a subface. //
13836 // //
13837 // To split edge ab by a point v is to split all tetrahedra containing ab by //
13838 // v. More specifically, for each such tetrahedron, an1n2b, it is shrunk to //
13839 // an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or //
13840 // some faces of the splitting tetrahedra are subfaces, they must be split //
13841 // either by calling routine 'splitsubedge()'. //
13842 // //
13843 // On completion, 'splittet' returns avn1n2. If 'flipqueue' is not NULL, it //
13844 // returns all faces which may become non-Delaunay after this operation. //
13845 // //
13847 
13848 void tetgenmesh::splittetedge(point newpoint, triface* splittet,
13849  queue* flipqueue)
13850 {
13851  triface *bots, *newtops;
13852  triface oldtop, topcasing;
13853  triface spintet, tmpbond0, tmpbond1;
13854  face abseg, splitsh, topsh, spinsh;
13855  triface worktet;
13856  face n1n2seg, n2vseg, n1vseg;
13857  point pa, pb, n1, n2;
13858  REAL attrib, volume;
13859  int wrapcount, hitbdry;
13860  int i, j;
13861 
13862  if (checksubfaces) {
13863  // Is there a subsegment need to be split together?
13864  tsspivot(splittet, &abseg);
13865  if (abseg.sh != dummysh) {
13866  abseg.shver = 0;
13867  // Orient the edge direction of 'splittet' be abseg.
13868  if (org(*splittet) != sorg(abseg)) {
13869  esymself(*splittet);
13870  }
13871  }
13872  }
13873  spintet = *splittet;
13874  pa = org(spintet);
13875  pb = dest(spintet);
13876 
13877  if (b->verbose > 1) {
13878  printf(" Inserting point %d on edge (%d, %d).\n",
13879  pointmark(newpoint), pointmark(pa), pointmark(pb));
13880  }
13881 
13882  // Collect the tetrahedra containing the splitting edge (ab).
13883  n1 = apex(spintet);
13884  hitbdry = 0;
13885  wrapcount = 1;
13886  if (checksubfaces && abseg.sh != dummysh) {
13887  // It may happen that some tetrahedra containing ab (a subsegment) are
13888  // completely disconnected with others. If it happens, use the face
13889  // link of ab to cross the boundary.
13890  while (true) {
13891  if (!fnextself(spintet)) {
13892  // Meet a boundary, walk through it.
13893  hitbdry ++;
13894  tspivot(spintet, spinsh);
13895 #ifdef SELF_CHECK
13896  assert(spinsh.sh != dummysh);
13897 #endif
13898  findedge(&spinsh, pa, pb);
13899  sfnextself(spinsh);
13900  stpivot(spinsh, spintet);
13901 #ifdef SELF_CHECK
13902  assert(spintet.tet != dummytet);
13903 #endif
13904  findedge(&spintet, pa, pb);
13905  // Remember this position (hull face) in 'splittet'.
13906  *splittet = spintet;
13907  // Split two hull faces increase the hull size;
13908  hullsize += 2;
13909  }
13910  if (apex(spintet) == n1) break;
13911  wrapcount ++;
13912  }
13913  if (hitbdry > 0) {
13914  wrapcount -= hitbdry;
13915  }
13916  } else {
13917  // All the tetrahedra containing ab are connected together. If there
13918  // are subfaces, 'splitsh' keeps one of them.
13919  splitsh.sh = dummysh;
13920  while (hitbdry < 2) {
13921  if (checksubfaces && splitsh.sh == dummysh) {
13922  tspivot(spintet, splitsh);
13923  }
13924  if (fnextself(spintet)) {
13925  if (apex(spintet) == n1) break;
13926  wrapcount++;
13927  } else {
13928  hitbdry ++;
13929  if (hitbdry < 2) {
13930  esym(*splittet, spintet);
13931  }
13932  }
13933  }
13934  if (hitbdry > 0) {
13935  // ab is on the hull.
13936  wrapcount -= 1;
13937  // 'spintet' now is a hull face, inverse its edge direction.
13938  esym(spintet, *splittet);
13939  // Split two hull faces increases the number of hull faces.
13940  hullsize += 2;
13941  }
13942  }
13943 
13944  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
13945  bots = new triface[wrapcount];
13946  newtops = new triface[wrapcount];
13947  // Spin around ab, gather tetrahedra and set up new tetrahedra.
13948  spintet = *splittet;
13949  for (i = 0; i < wrapcount; i++) {
13950  // Get 'bots[i] = an1n2b'.
13951  enext2fnext(spintet, bots[i]);
13952  esymself(bots[i]);
13953  // Create 'newtops[i]'.
13954  maketetrahedron(&(newtops[i]));
13955  // Go to the next.
13956  fnextself(spintet);
13957  if (checksubfaces && abseg.sh != dummysh) {
13958  if (!issymexist(&spintet)) {
13959  // We meet a hull face, walk through it.
13960  tspivot(spintet, spinsh);
13961 #ifdef SELF_CHECK
13962  assert(spinsh.sh != dummysh);
13963 #endif
13964  findedge(&spinsh, pa, pb);
13965  sfnextself(spinsh);
13966  stpivot(spinsh, spintet);
13967 #ifdef SELF_CHECK
13968  assert(spintet.tet != dummytet);
13969 #endif
13970  findedge(&spintet, pa, pb);
13971  }
13972  }
13973  }
13974 
13975  // Set the vertices of updated and new tetrahedra.
13976  for (i = 0; i < wrapcount; i++) {
13977  // Update 'bots[i] = an1n2v'.
13978  setoppo(bots[i], newpoint);
13979  // Set 'newtops[i] = bn2n1v'.
13980  n1 = dest(bots[i]);
13981  n2 = apex(bots[i]);
13982  // Set 'newtops[i]'.
13983  setorg(newtops[i], pb);
13984  setdest(newtops[i], n2);
13985  setapex(newtops[i], n1);
13986  setoppo(newtops[i], newpoint);
13987  // Set the element attributes of a new tetrahedron.
13988  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
13989  attrib = elemattribute(bots[i].tet, j);
13990  setelemattribute(newtops[i].tet, j, attrib);
13991  }
13992  if (b->varvolume) {
13993  // Set the area constraint of a new tetrahedron.
13994  volume = volumebound(bots[i].tet);
13995  setvolumebound(newtops[i].tet, volume);
13996  }
13997 #ifdef SELF_CHECK
13998  // Make sure no inversed tetrahedron has been created.
13999  // volume = orient3d(pa, n1, n2, newpoint);
14000  // if (volume >= 0.0) {
14001  // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
14002  // }
14003  // volume = orient3d(pb, n2, n1, newpoint);
14004  // if (volume >= 0.0) {
14005  // printf("Internal error in splittetedge(): volume = %.12g.\n", volume);
14006  // }
14007 #endif
14008  }
14009 
14010  // Bond newtops to topcasings and bots.
14011  for (i = 0; i < wrapcount; i++) {
14012  // Get 'oldtop = n1n2va' from 'bots[i]'.
14013  enextfnext(bots[i], oldtop);
14014  sym(oldtop, topcasing);
14015  bond(newtops[i], topcasing);
14016  if (checksubfaces) {
14017  tspivot(oldtop, topsh);
14018  if (topsh.sh != dummysh) {
14019  tsdissolve(oldtop);
14020  tsbond(newtops[i], topsh);
14021  }
14022  }
14023  enextfnext(newtops[i], tmpbond0);
14024  bond(oldtop, tmpbond0);
14025  }
14026  // Bond between newtops.
14027  fnext(newtops[0], tmpbond0);
14028  enext2fnext(bots[0], spintet);
14029  for (i = 1; i < wrapcount; i ++) {
14030  if (issymexist(&spintet)) {
14031  enext2fnext(newtops[i], tmpbond1);
14032  bond(tmpbond0, tmpbond1);
14033  }
14034  fnext(newtops[i], tmpbond0);
14035  enext2fnext(bots[i], spintet);
14036  }
14037  // Bond the last to the first if no boundary.
14038  if (issymexist(&spintet)) {
14039  enext2fnext(newtops[0], tmpbond1);
14040  bond(tmpbond0, tmpbond1);
14041  }
14042  if (checksubsegs) {
14043  for (i = 0; i < wrapcount; i++) {
14044  enextfnext(bots[i], worktet); // edge n1->n2.
14045  tsspivot1(worktet, n1n2seg);
14046  if (n1n2seg.sh != dummysh) {
14047  enext(newtops[i], tmpbond0);
14048  tssbond1(tmpbond0, n1n2seg);
14049  }
14050  enextself(worktet); // edge n2->v ==> n2->b
14051  tsspivot1(worktet, n2vseg);
14052  if (n2vseg.sh != dummysh) {
14053  tssdissolve1(worktet);
14054  tssbond1(newtops[i], n2vseg);
14055  }
14056  enextself(worktet); // edge v->n1 ==> b->n1
14057  tsspivot1(worktet, n1vseg);
14058  if (n1vseg.sh != dummysh) {
14059  tssdissolve1(worktet);
14060  enext2(newtops[i], tmpbond0);
14061  tssbond1(tmpbond0, n1vseg);
14062  }
14063  }
14064  }
14065 
14066  // Is there exist subfaces and subsegment need to be split?
14067  if (checksubfaces) {
14068  if (abseg.sh != dummysh) {
14069  // A subsegment needs be split.
14070  spivot(abseg, splitsh);
14071 #ifdef SELF_CHECK
14072  assert(splitsh.sh != dummysh);
14073 #endif
14074  }
14075  if (splitsh.sh != dummysh) {
14076  // Split subfaces (and subsegment).
14077  findedge(&splitsh, pa, pb);
14078  splitsubedge(newpoint, &splitsh, (queue *) NULL);
14079  }
14080  }
14081 
14082  if (b->verbose > 3) {
14083  for (i = 0; i < wrapcount; i++) {
14084  printf(" Updating bots[%i] ", i);
14085  printtet(&(bots[i]));
14086  printf(" Creating newtops[%i] ", i);
14087  printtet(&(newtops[i]));
14088  }
14089  }
14090 
14091  if (flipqueue != (queue *) NULL) {
14092  for (i = 0; i < wrapcount; i++) {
14093  enqueueflipface(bots[i], flipqueue);
14094  enqueueflipface(newtops[i], flipqueue);
14095  }
14096  }
14097 
14098  // Set the return handle be avn1n2. It is got by transforming from
14099  // 'bots[0]' (which is an1n2v).
14100  fnext(bots[0], spintet); // spintet is an1vn2.
14101  esymself(spintet); // spintet is n1avn2.
14102  enextself(spintet); // spintet is avn1n2.
14103  *splittet = spintet;
14104 
14105  delete [] bots;
14106  delete [] newtops;
14107 }
14108 
14110 // //
14111 // unsplittetedge() Reverse the operation of splitting an edge, so as to //
14112 // remove the newly inserted point. //
14113 // //
14114 // Assume the original edge is ab, the tetrahedron containing ab is abn1n2. //
14115 // After ab was split by a point v, every tetrahedron containing ab (e.g., //
14116 // abn1n2) has been split into two (e.g., an1n2v and bn2n1v). 'splittet' //
14117 // represents avn1n2 (i.e., its destination is v). //
14118 // //
14119 // To remove point v is to expand each split tetrahedron containing ab (e.g.,//
14120 // (avn1n2 to abn1n2), then delete the redundant one(e.g., vbn1n2). If there //
14121 // exists any subface around ab, routine unsplitsubedge() will be called to //
14122 // reverse the operation of splitting a edge (or a subsegment) of subfaces. //
14123 // On completion, point v is not deleted in this routine. //
14124 // //
14126 
14127 void tetgenmesh::unsplittetedge(triface* splittet)
14128 {
14129  triface *bots, *newtops;
14130  triface oldtop, topcasing;
14131  triface spintet;
14132  face avseg, splitsh, topsh, spinsh;
14133  point pa, pv, n1;
14134  int wrapcount, hitbdry;
14135  int i;
14136 
14137  spintet = *splittet;
14138  pa = org(spintet);
14139  pv = dest(spintet);
14140  if (checksubfaces) {
14141  // Is there a subsegment need to be unsplit together?
14142  tsspivot(splittet, &avseg);
14143  if (avseg.sh != dummysh) {
14144  // The subsegment's direction should conform to 'splittet'.
14145  if (sorg(avseg) != pa) {
14146  sesymself(avseg);
14147  }
14148  }
14149  }
14150 
14151  n1 = apex(spintet);
14152  hitbdry = 0;
14153  wrapcount = 1;
14154  if (checksubfaces && avseg.sh != dummysh) {
14155  // It may happen that some tetrahedra containing ab (a subsegment) are
14156  // completely disconnected with others. If it happens, use the face
14157  // link of ab to cross the boundary.
14158  while (true) {
14159  if (!fnextself(spintet)) {
14160  // Meet a boundary, walk through it.
14161  hitbdry ++;
14162  tspivot(spintet, spinsh);
14163 #ifdef SELF_CHECK
14164  assert(spinsh.sh != dummysh);
14165 #endif
14166  findedge(&spinsh, pa, pv);
14167  sfnextself(spinsh);
14168  stpivot(spinsh, spintet);
14169 #ifdef SELF_CHECK
14170  assert(spintet.tet != dummytet);
14171 #endif
14172  findedge(&spintet, pa, pv);
14173  // Remember this position (hull face) in 'splittet'.
14174  *splittet = spintet;
14175  // Split two hull faces increase the hull size;
14176  hullsize += 2;
14177  }
14178  if (apex(spintet) == n1) break;
14179  wrapcount ++;
14180  }
14181  if (hitbdry > 0) {
14182  wrapcount -= hitbdry;
14183  }
14184  } else {
14185  // All the tetrahedra containing ab are connected together. If there
14186  // are subfaces, 'splitsh' keeps one of them.
14187  splitsh.sh = dummysh;
14188  while (hitbdry < 2) {
14189  if (checksubfaces && splitsh.sh == dummysh) {
14190  tspivot(spintet, splitsh);
14191  }
14192  if (fnextself(spintet)) {
14193  if (apex(spintet) == n1) break;
14194  wrapcount++;
14195  } else {
14196  hitbdry ++;
14197  if (hitbdry < 2) {
14198  esym(*splittet, spintet);
14199  }
14200  }
14201  }
14202  if (hitbdry > 0) {
14203  // ab is on the hull.
14204  wrapcount -= 1;
14205  // 'spintet' now is a hull face, inverse its edge direction.
14206  esym(spintet, *splittet);
14207  // Split two hull faces increases the number of hull faces.
14208  hullsize += 2;
14209  }
14210  }
14211 
14212  // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra.
14213  bots = new triface[wrapcount];
14214  newtops = new triface[wrapcount];
14215  // Spin around av, gather tetrahedra and set up new tetrahedra.
14216  spintet = *splittet;
14217  for (i = 0; i < wrapcount; i++) {
14218  // Get 'bots[i] = an1n2v'.
14219  enext2fnext(spintet, bots[i]);
14220  esymself(bots[i]);
14221  // Get 'oldtop = n1n2va'.
14222  enextfnext(bots[i], oldtop);
14223  // Get 'newtops[i] = 'bn1n2v'
14224  fnext(oldtop, newtops[i]); // newtop = n1n2bv
14225  esymself(newtops[i]); // newtop = n2n1bv
14226  enext2self(newtops[i]); // newtop = bn2n1v
14227  // Go to the next.
14228  fnextself(spintet);
14229  if (checksubfaces && avseg.sh != dummysh) {
14230  if (!issymexist(&spintet)) {
14231  // We meet a hull face, walk through it.
14232  tspivot(spintet, spinsh);
14233 #ifdef SELF_CHECK
14234  assert(spinsh.sh != dummysh);
14235 #endif
14236  findedge(&spinsh, pa, pv);
14237  sfnextself(spinsh);
14238  stpivot(spinsh, spintet);
14239 #ifdef SELF_CHECK
14240  assert(spintet.tet != dummytet);
14241 #endif
14242  findedge(&spintet, pa, pv);
14243  }
14244  }
14245  }
14246 
14247  if (b->verbose > 1) {
14248  printf(" Removing point %d from edge (%d, %d).\n",
14249  pointmark(oppo(bots[0])), pointmark(org(bots[0])),
14250  pointmark(org(newtops[0])));
14251  }
14252 
14253  for (i = 0; i < wrapcount; i++) {
14254  // Expand an1n2v to an1n2b.
14255  setoppo(bots[i], org(newtops[i]));
14256  // Get 'oldtop = n1n2va' from 'bot[i]'.
14257  enextfnext(bots[i], oldtop);
14258  // Get 'topcasing' from 'newtop[i]'
14259  sym(newtops[i], topcasing);
14260  // Bond them.
14261  bond(oldtop, topcasing);
14262  if (checksubfaces) {
14263  tspivot(newtops[i], topsh);
14264  if (topsh.sh != dummysh) {
14265  tsbond(oldtop, topsh);
14266  }
14267  }
14268  // Delete the tetrahedron above an1n2v.
14269  tetrahedrondealloc(newtops[i].tet);
14270  }
14271 
14272  // If there exists any subface, unsplit them.
14273  if (checksubfaces) {
14274  if (avseg.sh != dummysh) {
14275  spivot(avseg, splitsh);
14276 #ifdef SELF_CHECK
14277  assert(splitsh.sh != dummysh);
14278 #endif
14279  }
14280  if (splitsh.sh != dummysh) {
14281  findedge(&splitsh, pa, pv);
14282  unsplitsubedge(&splitsh);
14283  }
14284  }
14285 
14286  delete [] bots;
14287  delete [] newtops;
14288 }
14289 
14291 // //
14292 // splitsubedge() Insert a point on an edge of the surface mesh. //
14293 // //
14294 // The splitting edge is given by 'splitsh'. Assume its three corners are a, //
14295 // b, c, where ab is the edge will be split. ab may be a subsegment. //
14296 // //
14297 // To split edge ab is to split all subfaces conatining ab. If ab is not a //
14298 // subsegment, there are only two subfaces need be split, otherwise, there //
14299 // may have any number of subfaces need be split. Each splitting subface abc //
14300 // is shrunk to avc, a new subface vbc is created. It is important to keep //
14301 // the orientations of edge rings of avc and vbc be the same as abc's. If ab //
14302 // is a subsegment, it is shrunk to av and a new subsegment vb is created. //
14303 // //
14304 // If there are tetrahedra adjoining to the splitting subfaces, they should //
14305 // be split before calling this routine, so the connection between the new //
14306 // tetrahedra and the new subfaces can be correctly set. //
14307 // //
14308 // On completion, 'splitsh' returns avc. If 'flipqueue' is not NULL, it //
14309 // returns all edges which may be non-Delaunay. //
14310 // //
14312 
14313 void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue)
14314 {
14315  triface abcd, bace, vbcd, bvce;
14316  face startabc, spinabc, spinsh;
14317  face oldbc, bccasin, bccasout;
14318  face ab, bc;
14319  face avc, vbc, vbc1;
14320  face av, vb;
14321  point pa, pb;
14322 
14323  startabc = *splitsh;
14324  // Is there a subsegment?
14325  sspivot(startabc, ab);
14326  if (ab.sh != dummysh) {
14327  ab.shver = 0;
14328  if (sorg(startabc) != sorg(ab)) {
14329  sesymself(startabc);
14330  }
14331  }
14332  pa = sorg(startabc);
14333  pb = sdest(startabc);
14334 
14335  if (b->verbose > 1) {
14336  printf(" Inserting point %d on subedge (%d, %d) %s.\n",
14337  pointmark(newpoint), pointmark(pa), pointmark(pb),
14338  (ab.sh != dummysh ? "(seg)" : " "));
14339  }
14340 
14341  // Spin arround ab, split every subface containing ab.
14342  spinabc = startabc;
14343  do {
14344  // Adjust spinabc be edge ab.
14345  if (sorg(spinabc) != pa) {
14346  sesymself(spinabc);
14347  }
14348  // Save old configuration at edge bc, if bc has a subsegment, save the
14349  // face link of it and dissolve it from bc.
14350  senext(spinabc, oldbc);
14351  spivot(oldbc, bccasout);
14352  sspivot(oldbc, bc);
14353  if (bc.sh != dummysh) {
14354  if (spinabc.sh != bccasout.sh) {
14355  // 'spinabc' is not self-bonded.
14356  spinsh = bccasout;
14357  do {
14358  bccasin = spinsh;
14359  spivotself(spinsh);
14360  } while (spinsh.sh != oldbc.sh);
14361  } else {
14362  bccasout.sh = dummysh;
14363  }
14364  ssdissolve(oldbc);
14365  }
14366  // Create a new subface.
14367  makeshellface(subfaces, &vbc);
14368  // Split abc.
14369  avc = spinabc; // Update 'abc' to 'avc'.
14370  setsdest(avc, newpoint);
14371  // Make 'vbc' be in the same edge ring as 'avc'.
14372  vbc.shver = avc.shver;
14373  setsorg(vbc, newpoint); // Set 'vbc'.
14374  setsdest(vbc, pb);
14375  setsapex(vbc, sapex(avc));
14376  if (b->quality && varconstraint) {
14377  // Copy the area bound into the new subface.
14378  setareabound(vbc, areabound(avc));
14379  }
14380  // Copy the shell marker and shell type into the new subface.
14381  setshellmark(vbc, shellmark(avc));
14382  setshelltype(vbc, shelltype(avc));
14383  if (checkpbcs) {
14384  // Copy the pbcgroup into the new subface.
14385  setshellpbcgroup(vbc, shellpbcgroup(avc));
14386  }
14387  // Set the connection between updated and new subfaces.
14388  senext2self(vbc);
14389  sbond(vbc, oldbc);
14390  // Set the connection between new subface and casings.
14391  senext2self(vbc);
14392  if (bc.sh != dummysh) {
14393  if (bccasout.sh != dummysh) {
14394  // Insert 'vbc' into face link.
14395  sbond1(bccasin, vbc);
14396  sbond1(vbc, bccasout);
14397  } else {
14398  // Bond 'vbc' to itself.
14399  sbond(vbc, vbc);
14400  }
14401  ssbond(vbc, bc);
14402  } else {
14403  sbond(vbc, bccasout);
14404  }
14405  // Go to next subface at edge ab.
14406  spivotself(spinabc);
14407  if (spinabc.sh == dummysh) {
14408  break; // 'ab' is a hull edge.
14409  }
14410  } while (spinabc.sh != startabc.sh);
14411 
14412  // Get the new subface vbc above the updated subface avc (= startabc).
14413  senext(startabc, oldbc);
14414  spivot(oldbc, vbc);
14415  if (sorg(vbc) == newpoint) {
14416  sesymself(vbc);
14417  }
14418 #ifdef SELF_CHECK
14419  assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc));
14420 #endif
14421  senextself(vbc);
14422  // Set the face link for the new created subfaces around edge vb.
14423  spinabc = startabc;
14424  do {
14425  // Go to the next subface at edge av.
14426  spivotself(spinabc);
14427  if (spinabc.sh == dummysh) {
14428  break; // 'ab' is a hull edge.
14429  }
14430  if (sorg(spinabc) != pa) {
14431  sesymself(spinabc);
14432  }
14433  // Get the new subface vbc1 above the updated subface avc (= spinabc).
14434  senext(spinabc, oldbc);
14435  spivot(oldbc, vbc1);
14436  if (sorg(vbc1) == newpoint) {
14437  sesymself(vbc1);
14438  }
14439 #ifdef SELF_CHECK
14440  assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc));
14441 #endif
14442  senextself(vbc1);
14443  // Set the connection: vbc->vbc1.
14444  sbond1(vbc, vbc1);
14445  // For the next connection.
14446  vbc = vbc1;
14447  } while (spinabc.sh != startabc.sh);
14448 
14449  // Split ab if it is a subsegment.
14450  if (ab.sh != dummysh) {
14451  // Update subsegment ab to av.
14452  av = ab;
14453  setsdest(av, newpoint);
14454  // Create a new subsegment vb.
14455  makeshellface(subsegs, &vb);
14456  setsorg(vb, newpoint);
14457  setsdest(vb, pb);
14458  // vb gets the same mark and segment type as av.
14459  setshellmark(vb, shellmark(av));
14460  setshelltype(vb, shelltype(av));
14461  if (b->quality && varconstraint) {
14462  // Copy the area bound into the new subsegment.
14463  setareabound(vb, areabound(av));
14464  }
14465  // Save the old connection at ab (re-use the handles oldbc, bccasout).
14466  senext(av, oldbc);
14467  spivot(oldbc, bccasout);
14468  // Bond av and vb (bonded at their "fake" edges).
14469  senext2(vb, bccasin);
14470  sbond(bccasin, oldbc);
14471  if (bccasout.sh != dummysh) {
14472  // There is a subsegment connecting with ab at b. It will connect
14473  // to vb at b after splitting.
14474  bccasout.shver = 0;
14475  if (sorg(bccasout) != pb) sesymself(bccasout);
14476 #ifdef SELF_CHECK
14477  assert(sorg(bccasout) == pb);
14478 #endif
14479  senext2self(bccasout);
14480  senext(vb, bccasin);
14481  sbond(bccasin, bccasout);
14482  }
14483  // Bond all new subfaces (vbc) to vb.
14484  spinabc = startabc;
14485  do {
14486  // Adjust spinabc be edge av.
14487  if (sorg(spinabc) != pa) {
14488  sesymself(spinabc);
14489  }
14490  // Get new subface vbc above the updated subface avc (= spinabc).
14491  senext(spinabc, oldbc);
14492  spivot(oldbc, vbc);
14493  if (sorg(vbc) == newpoint) {
14494  sesymself(vbc);
14495  }
14496  senextself(vbc);
14497  // Bond the new subface and the new subsegment.
14498  ssbond(vbc, vb);
14499  // Go to the next.
14500  spivotself(spinabc);
14501 #ifdef SELF_CHECK
14502  assert(spinabc.sh != dummysh);
14503 #endif
14504  } while (spinabc.sh != startabc.sh);
14505  }
14506 
14507  // Bond the new subfaces to new tetrahedra if they exist. New tetrahedra
14508  // should have been created before calling this routine.
14509  spinabc = startabc;
14510  do {
14511  // Adjust spinabc be edge av.
14512  if (sorg(spinabc) != pa) {
14513  sesymself(spinabc);
14514  }
14515  // Get new subface vbc above the updated subface avc (= spinabc).
14516  senext(spinabc, oldbc);
14517  spivot(oldbc, vbc);
14518  if (sorg(vbc) == newpoint) {
14519  sesymself(vbc);
14520  }
14521  senextself(vbc);
14522  // Get the adjacent tetrahedra at 'spinabc'.
14523  stpivot(spinabc, abcd);
14524  if (abcd.tet != dummytet) {
14525  findedge(&abcd, sorg(spinabc), sdest(spinabc));
14526  enextfnext(abcd, vbcd);
14527  fnextself(vbcd);
14528 #ifdef SELF_CHECK
14529  assert(vbcd.tet != dummytet);
14530 #endif
14531  tsbond(vbcd, vbc);
14532  sym(vbcd, bvce);
14533  sesymself(vbc);
14534  tsbond(bvce, vbc);
14535  } else {
14536  // One side is empty, check the other side.
14537  sesymself(spinabc);
14538  stpivot(spinabc, bace);
14539  if (bace.tet != dummytet) {
14540  findedge(&bace, sorg(spinabc), sdest(spinabc));
14541  enext2fnext(bace, bvce);
14542  fnextself(bvce);
14543 #ifdef SELF_CHECK
14544  assert(bvce.tet != dummytet);
14545 #endif
14546  sesymself(vbc);
14547  tsbond(bvce, vbc);
14548  }
14549  }
14550  // Go to the next.
14551  spivotself(spinabc);
14552  if (spinabc.sh == dummysh) {
14553  break; // 'ab' is a hull edge.
14554  }
14555  } while (spinabc.sh != startabc.sh);
14556 
14557  if (b->verbose > 3) {
14558  spinabc = startabc;
14559  do {
14560  // Adjust spinabc be edge av.
14561  if (sorg(spinabc) != pa) {
14562  sesymself(spinabc);
14563  }
14564  printf(" Updating abc:\n");
14565  printsh(&spinabc);
14566  // Get new subface vbc above the updated subface avc (= spinabc).
14567  senext(spinabc, oldbc);
14568  spivot(oldbc, vbc);
14569  if (sorg(vbc) == newpoint) {
14570  sesymself(vbc);
14571  }
14572  senextself(vbc);
14573  printf(" Creating vbc:\n");
14574  printsh(&vbc);
14575  // Go to the next.
14576  spivotself(spinabc);
14577  if (spinabc.sh == dummysh) {
14578  break; // 'ab' is a hull edge.
14579  }
14580  } while (spinabc.sh != startabc.sh);
14581  }
14582 
14583  if (flipqueue != (queue *) NULL) {
14584  spinabc = startabc;
14585  do {
14586  // Adjust spinabc be edge av.
14587  if (sorg(spinabc) != pa) {
14588  sesymself(spinabc);
14589  }
14590  senext2(spinabc, oldbc); // Re-use oldbc.
14591  enqueueflipedge(oldbc, flipqueue);
14592  // Get new subface vbc above the updated subface avc (= spinabc).
14593  senext(spinabc, oldbc);
14594  spivot(oldbc, vbc);
14595  if (sorg(vbc) == newpoint) {
14596  sesymself(vbc);
14597  }
14598  senextself(vbc);
14599  senext(vbc, oldbc); // Re-use oldbc.
14600  enqueueflipedge(oldbc, flipqueue);
14601  // Go to the next.
14602  spivotself(spinabc);
14603  if (spinabc.sh == dummysh) {
14604  break; // 'ab' is a hull edge.
14605  }
14606  } while (spinabc.sh != startabc.sh);
14607  }
14608 }
14609 
14611 // //
14612 // unsplitsubedge() Reverse the operation of splitting an edge of subface,//
14613 // so as to remove a point from the edge. //
14614 // //
14615 // Assume the original edge is ab, the subface containing it is abc. It was //
14616 // split by a point v into avc, and vbc. 'splitsh' represents avc, further- //
14617 // more, if av is a subsegment, av should be the zero version of the split //
14618 // subsegment (i.e., av.shver = 0), so we are sure that the destination (v) //
14619 // of both avc and av is the deleting point. //
14620 // //
14621 // To remove point v is to expand avc to abc, delete vbc, do the same for //
14622 // other subfaces containing av and vb. If av and vb are subsegments, expand //
14623 // av to ab, delete vb. On completion, point v is not deleted. //
14624 // //
14626 
14627 void tetgenmesh::unsplitsubedge(face* splitsh)
14628 {
14629  face startavc, spinavc, spinbcv;
14630  face oldvc, bccasin, bccasout, spinsh;
14631  face av, vb, bc;
14632  point pa, pv, pb;
14633 
14634  startavc = *splitsh;
14635  sspivot(startavc, av);
14636  if (av.sh != dummysh) {
14637  // Orient the direction of subsegment to conform the subface.
14638  if (sorg(av) != sorg(startavc)) {
14639  sesymself(av);
14640  }
14641 #ifdef SELF_CHECK
14642  assert(av.shver == 0);
14643 #endif
14644  }
14645  senext(startavc, oldvc);
14646  spivot(oldvc, vb); // vb is subface vbc
14647  if (sorg(vb) != sdest(oldvc)) {
14648  sesymself(vb);
14649  }
14650  senextself(vb);
14651  pa = sorg(startavc);
14652  pv = sdest(startavc);
14653  pb = sdest(vb);
14654 
14655  if (b->verbose > 1) {
14656  printf(" Removing point %d from subedge (%d, %d).\n",
14657  pointmark(pv), pointmark(pa), pointmark(pb));
14658  }
14659 
14660  // Spin arround av, unsplit every subface containing av.
14661  spinavc = startavc;
14662  do {
14663  // Adjust spinavc be edge av.
14664  if (sorg(spinavc) != pa) {
14665  sesymself(spinavc);
14666  }
14667  // Save old configuration at edge bc, if bc has a subsegment, save the
14668  // face link of it.
14669  senext(spinavc, oldvc);
14670  spivot(oldvc, spinbcv);
14671  if (sorg(spinbcv) != sdest(oldvc)) {
14672  sesymself(spinbcv);
14673  }
14674  senext2self(spinbcv);
14675  spivot(spinbcv, bccasout);
14676  sspivot(spinbcv, bc);
14677  if (bc.sh != dummysh) {
14678  if (spinbcv.sh != bccasout.sh) {
14679  // 'spinbcv' is not self-bonded.
14680  spinsh = bccasout;
14681  do {
14682  bccasin = spinsh;
14683  spivotself(spinsh);
14684  } while (spinsh.sh != spinbcv.sh);
14685  } else {
14686  bccasout.sh = dummysh;
14687  }
14688  }
14689  // Expand avc to abc.
14690  setsdest(spinavc, pb);
14691  if (bc.sh != dummysh) {
14692  if (bccasout.sh != dummysh) {
14693  sbond1(bccasin, oldvc);
14694  sbond1(oldvc, bccasout);
14695  } else {
14696  // Bond 'oldbc' to itself.
14697  sbond(oldvc, oldvc);
14698  }
14699  ssbond(oldvc, bc);
14700  } else {
14701  sbond(oldvc, bccasout);
14702  }
14703  // Delete bcv.
14704  shellfacedealloc(subfaces, spinbcv.sh);
14705  // Go to next subface at edge av.
14706  spivotself(spinavc);
14707  if (spinavc.sh == dummysh) {
14708  break; // 'av' is a hull edge.
14709  }
14710  } while (spinavc.sh != startavc.sh);
14711 
14712  // Is there a subsegment need to be unsplit?
14713  if (av.sh != dummysh) {
14714  senext(av, oldvc); // Re-use oldvc.
14715  spivot(oldvc, vb);
14716  vb.shver = 0;
14717 #ifdef SELF_CHECK
14718  assert(sdest(av) == sorg(vb));
14719 #endif
14720  senext(vb, spinbcv); // Re-use spinbcv.
14721  spivot(spinbcv, bccasout);
14722  // Expand av to ab.
14723  setsdest(av, pb);
14724  sbond(oldvc, bccasout);
14725  // Delete vb.
14726  shellfacedealloc(subsegs, vb.sh);
14727  }
14728 }
14729 
14731 // //
14732 // insertsite() Insert a point into the mesh. //
14733 // //
14734 // The 'newpoint' is located. If 'searchtet->tet' is not NULL, the search //
14735 // for the containing tetrahedron begins from 'searchtet', otherwise, a full //
14736 // point location procedure is called. If 'newpoint' is found inside a //
14737 // tetrahedron, the tetrahedron is split into four (by splittetrahedron()); //
14738 // if 'newpoint' lies on a face, the face is split into three, thereby //
14739 // splitting the two adjacent tetrahedra into six (by splittetface()); if //
14740 // 'newpoint' lies on an edge, the edge is split into two, thereby, every //
14741 // tetrahedron containing this edge is split into two. If 'newpoint' lies on //
14742 // an existing vertex, no action is taken, and the value DUPLICATEPOINT is //
14743 // returned and 'searchtet' is set to a handle whose origin is the vertex. //
14744 // //
14745 // If 'flipqueue' is not NULL, after 'newpoint' is inserted, it returns all //
14746 // faces which may become non-Delaunay due to the newly inserted point. Flip //
14747 // operations can be performed as necessary on them to maintain the Delaunay //
14748 // property. //
14749 // //
14751 
14752 enum tetgenmesh::insertsiteresult tetgenmesh::insertsite(point newpoint,
14753  triface* searchtet, bool approx, queue* flipqueue)
14754 {
14755  enum locateresult intersect, exactloc;
14756  point checkpt;
14757  REAL epspp, checklen;
14758  int count;
14759 
14760  if (b->verbose > 1) {
14761  printf(" Insert point to mesh: (%.12g, %.12g, %.12g) %d.\n",
14762  newpoint[0], newpoint[1], newpoint[2], pointmark(newpoint));
14763  }
14764 
14765  if (searchtet->tet == (tetrahedron *) NULL) {
14766  // Search for a tetrahedron containing 'newpoint'.
14767  searchtet->tet = dummytet;
14768  exactloc = locate(newpoint, searchtet);
14769  } else {
14770  // Start searching from the tetrahedron provided by the caller.
14771  exactloc = preciselocate(newpoint, searchtet, tetrahedrons->items);
14772  }
14773  intersect = exactloc;
14774  if (approx && (exactloc != ONVERTEX)) {
14775  // Adjust the exact location to an approx. location wrt. epsilon.
14776  epspp = b->epsilon;
14777  count = 0;
14778  while (count < 16) {
14779  intersect = adjustlocate(newpoint, searchtet, exactloc, epspp);
14780  if (intersect == ONVERTEX) {
14781  checkpt = org(*searchtet);
14782  checklen = distance(checkpt, newpoint);
14783  if (checklen / longest > b->epsilon) {
14784  epspp *= 1e-2;
14785  count++;
14786  continue;
14787  }
14788  }
14789  break;
14790  }
14791  }
14792  // Keep current search state for next searching.
14793  recenttet = *searchtet;
14794 
14795  // Insert the point using the right routine
14796  switch (intersect) {
14797  case ONVERTEX:
14798  // There's already a vertex there. Return in 'searchtet' a tetrahedron
14799  // whose origin is the existing vertex.
14800  if (b->verbose > 1) {
14801  printf(" Not insert for duplicating point.\n");
14802  }
14803  return DUPLICATEPOINT;
14804 
14805  case OUTSIDE:
14806  if (b->verbose > 1) {
14807  printf(" Not insert for locating outside the mesh.\n");
14808  }
14809  return OUTSIDEPOINT;
14810 
14811  case ONEDGE:
14812  // 'newpoint' falls on an edge.
14813  splittetedge(newpoint, searchtet, flipqueue);
14814  return SUCCESSONEDGE;
14815 
14816  case ONFACE:
14817  // 'newpoint' falls on a face.
14818  splittetface(newpoint, searchtet, flipqueue);
14819  return SUCCESSONFACE;
14820 
14821  case INTETRAHEDRON:
14822  // 'newpoint' falls inside a tetrahedron.
14823  splittetrahedron(newpoint, searchtet, flipqueue);
14824  return SUCCESSINTET;
14825 
14826  default:
14827  // Impossible case.
14828  return OUTSIDEPOINT;
14829  }
14830 }
14831 
14833 // //
14834 // undosite() Undo the most recently point insertion. //
14835 // //
14836 // 'insresult' indicates in where the newpoint has been inserted, i.e., in a //
14837 // tetrahedron, on a face, or on an edge. A correspoding routine will be //
14838 // called to undo the point insertion. 'splittet' is a handle represent one //
14839 // of the resulting tetrahedra, but it may be changed after transformation, //
14840 // even may be dead. Four points 'torg', ... 'toppo' are the corners which //
14841 // 'splittet' should have. On finish, 'newpoint' is not removed. //
14842 // //
14844 
14845 void tetgenmesh::undosite(enum insertsiteresult insresult, triface* splittet,
14846  point torg, point tdest, point tapex, point toppo)
14847 {
14848  // Set the four corners of 'splittet' exactly be 'torg', ... 'toppo'.
14849  findface(splittet, torg, tdest, tapex);
14850  if (oppo(*splittet) != toppo) {
14851  symself(*splittet);
14852 #ifdef SELF_CHECK
14853  assert(oppo(*splittet) == toppo);
14854 #endif
14855  // The sym() operation may inverse the edge, correct it if so.
14856  findedge(splittet, torg, tdest);
14857  }
14858 
14859  // Unsplit the tetrahedron according to 'insresult'.
14860  switch (insresult) {
14861  case SUCCESSINTET:
14862  // 'splittet' should be the face with 'newpoint' as its opposite.
14863  unsplittetrahedron(splittet);
14864  break;
14865  case SUCCESSONFACE:
14866  // 'splittet' should be the one of three splitted face with 'newpoint'
14867  // as its apex.
14868  unsplittetface(splittet);
14869  break;
14870  case SUCCESSONEDGE:
14871  // 'splittet' should be the tet with destination is 'newpoint'.
14872  unsplittetedge(splittet);
14873  break;
14874  default: // To omit compile warnings.
14875  break;
14876  }
14877 }
14878 
14880 // //
14881 // closeopenface() Close "open" faces recursively. //
14882 // //
14883 // This is the support routine of inserthullsite(). A point p which lies out-//
14884 // side of CH(T). p is inserted to T by forming a tet t from p and a visible //
14885 // CH face f. The three sides of f which have p as a vertex is called "open" //
14886 // face. Each open face will be closed by either creating a tet on top of it //
14887 // or become a new CH face. //
14888 // //
14890 
14891 void tetgenmesh::closeopenface(triface* openface, queue* flipque)
14892 {
14893  triface newtet, oldhull;
14894  triface newopenface, closeface;
14895  point inspoint, pa, pb, pc;
14896  REAL attrib, volume;
14897  int i;
14898 
14899  // Get the new point p.
14900  inspoint = apex(*openface);
14901  // Find the old CH face f_o (f and f_o share the same edge).
14902  esym(*openface, oldhull);
14903  while (fnextself(oldhull)) ;
14904  if (apex(oldhull) != inspoint) {
14905  // Is f_o visible by p?
14906  pa = org(oldhull);
14907  pb = dest(oldhull);
14908  pc = apex(oldhull);
14909  if (orient3d(pa, pb, pc, inspoint) < 0.0) {
14910  // Yes. Create a new tet t above f_o.
14911  maketetrahedron(&newtet);
14912  setorg(newtet, pa);
14913  setdest(newtet, pb);
14914  setapex(newtet, pc);
14915  setoppo(newtet, inspoint);
14916  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
14917  attrib = elemattribute(oldhull.tet, i);
14918  setelemattribute(newtet.tet, i, attrib);
14919  }
14920  if (b->varvolume) {
14921  volume = volumebound(oldhull.tet);
14922  setvolumebound(newtet.tet, volume);
14923  }
14924  // Connect t to T.
14925  bond(newtet, oldhull);
14926  // Close f.
14927  fnext(newtet, newopenface);
14928  bond(newopenface, *openface);
14929  // f_o becomes an interior face.
14930  enqueueflipface(oldhull, flipque);
14931  // Hull face number decreases.
14932  hullsize--;
14933  // Two faces of t become open face.
14934  enextself(newtet);
14935  for (i = 0; i < 2; i++) {
14936  fnext(newtet, newopenface);
14937  sym(newopenface, closeface);
14938  if (closeface.tet == dummytet) {
14939  closeopenface(&newopenface, flipque);
14940  }
14941  enextself(newtet);
14942  }
14943  } else {
14944  // Inivisible. f becomes a new CH face.
14945  hullsize++;
14946  // Let 'dummytet' holds f for the next point location.
14947  dummytet[0] = encode(*openface);
14948  }
14949  } else {
14950  // f_o is co-incident with f --> f is closed by f_o.
14951  bond(*openface, oldhull);
14952  // f is an interior face.
14953  enqueueflipface(*openface, flipque);
14954  }
14955 }
14956 
14958 // //
14959 // inserthullsite() Insert a point which lies outside the convex hull. //
14960 // //
14961 // The 'inspoint' p lies outside the tetrahedralization T. The 'horiz' f is //
14962 // on the convex hull of T, CH(T), which is visible by p (Imagine f is para- //
14963 // llel to the horizon). To insert p into T we have to enlarge the CH(T) and //
14964 // update T so that p is on the new CH(T). //
14965 // //
14966 // To enlarge the CH(T). We need to find the set F of faces which are on CH //
14967 // (T) and visible by p (F can be formed by a depth-first search from f). p //
14968 // is then inserted into T by mounting new tets formed by p and these faces. //
14969 // Faces of F become interior faces and may non-locally Delaunay. They are //
14970 // queued in 'flipqueue' for flip tests. //
14971 // //
14973 
14974 void tetgenmesh::inserthullsite(point inspoint, triface* horiz, queue* flipque)
14975 {
14976  triface firstnewtet;
14977  triface openface, closeface;
14978  REAL attrib, volume;
14979  int i;
14980 
14981  // Let f face to p.
14982  adjustedgering(*horiz, CW);
14983  // Create the first tet t (from f and p).
14984  maketetrahedron(&firstnewtet);
14985  setorg (firstnewtet, org(*horiz));
14986  setdest(firstnewtet, dest(*horiz));
14987  setapex(firstnewtet, apex(*horiz));
14988  setoppo(firstnewtet, inspoint);
14989  for (i = 0; i < in->numberoftetrahedronattributes; i++) {
14990  attrib = elemattribute(horiz->tet, i);
14991  setelemattribute(firstnewtet.tet, i, attrib);
14992  }
14993  if (b->varvolume) {
14994  volume = volumebound(horiz->tet);
14995  setvolumebound(firstnewtet.tet, volume);
14996  }
14997  // Connect t to T.
14998  bond(firstnewtet, *horiz);
14999  // f is not on CH(T) anymore.
15000  enqueueflipface(*horiz, flipque);
15001  // Hull face number decreases.
15002  hullsize--;
15003 
15004  // Call the faces of t which have p as a vertex "open" face.
15005  for (i = 0; i < 3; i++) {
15006  // Get an open face f_i of t.
15007  fnext(firstnewtet, openface);
15008  // Close f_i if it is still open.
15009  sym(openface, closeface);
15010  if (closeface.tet == dummytet) {
15011  closeopenface(&openface, flipque);
15012  }
15013  // Go to the next open face of t.
15014  enextself(firstnewtet);
15015  }
15016 }
15017 
15019 // //
15020 // Terminology: BC(p) and CBC(p), B(p) and C(p). //
15021 // //
15022 // Given an arbitrary point p, the Bowyer-Watson cavity BC(p) is formed by //
15023 // tets whose circumspheres containing p. The outer faces of BC(p) form a //
15024 // polyhedron B(p). //
15025 // //
15026 // If p is on a facet F, the constrained Bowyer-Watson cavity CBC(p) on F is //
15027 // formed by subfaces of F whose circumspheres containing p. The outer edges //
15028 // of CBC(p) form a polygon C(p). B(p) is separated into two parts by C(p), //
15029 // denoted as B_1(p) and B_2(p), one of them may be empty (F is on the hull).//
15030 // //
15031 // If p is on a segment S which is shared by n facets. There exist n C(p)s, //
15032 // each one is a non-closed polygon (without S). B(p) is split into n parts, //
15033 // each of them is denoted as B_i(p), some B_i(p) may be empty. //
15034 // //
15036 
15038 // //
15039 // formbowatcavitysub() Form CBC(p) and C(p) on a facet F. //
15040 // //
15041 // Parameters: bp = p, bpseg = S, sublist = CBC(p), subceillist = C(p). //
15042 // //
15043 // CBC(p) contains at least one subface on input; S may be NULL which means //
15044 // that p is inside a facet. On output, all subfaces of CBC(p) are infected, //
15045 // and the edge rings are oriented to the same halfspace. //
15046 // //
15048 
15049 void tetgenmesh::formbowatcavitysub(point bp, face* bpseg, list* sublist,
15050  list* subceillist)
15051 {
15052  triface adjtet;
15053  face startsh, neighsh;
15054  face checkseg;
15055  point pa, pb, pc, pd;
15056  REAL sign;
15057  int i, j;
15058 
15059  // Form CBC(p) and C(p) by a broadth-first searching.
15060  for (i = 0; i < sublist->len(); i++) {
15061  startsh = * (face *)(* sublist)[i]; // startsh = f.
15062  // Look for three neighbors of f.
15063  for (j = 0; j < 3; j++) {
15064  sspivot(startsh, checkseg);
15065  if (checkseg.sh == dummysh) {
15066  // Get its neighbor n.
15067  spivot(startsh, neighsh);
15068  // Is n already in CBC(p)?
15069  if (!sinfected(neighsh)) {
15070  stpivot(neighsh, adjtet);
15071  if (adjtet.tet == dummytet) {
15072  sesymself(neighsh);
15073  stpivot(neighsh, adjtet);
15074  }
15075  // For positive orientation that insphere() test requires.
15076  adjustedgering(adjtet, CW);
15077  pa = org(adjtet);
15078  pb = dest(adjtet);
15079  pc = apex(adjtet);
15080  pd = oppo(adjtet);
15081  sign = insphere(pa, pb, pc, pd, bp);
15082  if (sign >= 0.0) {
15083  // Orient edge ring of n according to that of f.
15084  if (sorg(neighsh) != sdest(startsh)) sesymself(neighsh);
15085  // Collect it into CBC(p).
15086  sinfect(neighsh);
15087  sublist->append(&neighsh);
15088  } else {
15089  subceillist->append(&startsh); // Found an edge of C(p).
15090  }
15091  }
15092  } else {
15093  // Do not cross a segment.
15094  if (bpseg != (face *) NULL) {
15095  if (checkseg.sh != bpseg->sh) {
15096  subceillist->append(&startsh); // Found an edge of C(p).
15097  }
15098  } else {
15099  subceillist->append(&startsh); // Found an edge of C(p).
15100  }
15101  }
15102  senextself(startsh);
15103  }
15104  }
15105 
15106  if (b->verbose > 2) {
15107  printf(" Collect CBC(%d): %d subfaces, %d edges.\n", pointmark(bp),
15108  sublist->len(), subceillist->len());
15109  }
15110 }
15111 
15113 // //
15114 // formbowatcavityquad() Form BC_i(p) and B_i(p) in a quadrant. //
15115 // //
15116 // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). //
15117 // //
15118 // BC_i(p) contains at least one tet on input. On finish, all tets collected //
15119 // in BC_i(p) are infected. B_i(p) may not closed when p is on segment or in //
15120 // facet. C(p) must be formed before this routine. Check the infect flag of //
15121 // a subface to identify the unclosed side of B_i(p). These sides will be //
15122 // closed by new subfaces of C(p)s. //
15123 // //
15125 
15126 void tetgenmesh::formbowatcavityquad(point bp, list* tetlist, list* ceillist)
15127 {
15128  triface starttet, neightet;
15129  face checksh;
15130  point pa, pb, pc, pd;
15131  REAL sign;
15132  int i;
15133 
15134  // Form BC_i(p) and B_i(p) by a broadth-first searching.
15135  for (i = 0; i < tetlist->len(); i++) {
15136  starttet = * (triface *)(* tetlist)[i];
15137  for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
15138  // Try to collect the neighbor of the face (f).
15139  tspivot(starttet, checksh);
15140  if (checksh.sh == dummysh) {
15141  // Get its neighbor n.
15142  sym(starttet, neightet);
15143  // Is n already in BC_i(p)?
15144  if (!infected(neightet)) {
15145  // For positive orientation that insphere() test requires.
15146  adjustedgering(neightet, CW);
15147  pa = org(neightet);
15148  pb = dest(neightet);
15149  pc = apex(neightet);
15150  pd = oppo(neightet);
15151  sign = insphere(pa, pb, pc, pd, bp);
15152  if (sign >= 0.0) {
15153  // Collect it into BC_i(p).
15154  infect(neightet);
15155  tetlist->append(&neightet);
15156  } else {
15157  ceillist->append(&starttet); // Found a face of B_i(p).
15158  }
15159  }
15160  } else {
15161  // Do not cross a boundary face.
15162  if (!sinfected(checksh)) {
15163  ceillist->append(&starttet); // Found a face of B_i(p).
15164  }
15165  }
15166  }
15167  }
15168 
15169  if (b->verbose > 2) {
15170  printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
15171  tetlist->len(), ceillist->len());
15172  }
15173 }
15174 
15176 // //
15177 // formbowatcavitysegquad() Form BC_i(p) and B_i(p) in a segment quadrant.//
15178 // //
15179 // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). //
15180 // //
15181 // BC_i(p) contains at least one tet on input. On finish, all tets collected //
15182 // in BC_i(p) are infected. B_i(p) is not closed. C(p) must be formed before //
15183 // this routine. Check the infect flag of a subface to identify the unclosed //
15184 // sides of B_i(p). These sides will be closed by new subfaces of C(p)s. //
15185 // //
15186 // During the repair of encroaching subsegments, there may exist locally non-//
15187 // Delaunay faces. These faces are collected in BC_i(p) either. B_i(p) has //
15188 // to be formed later than BC_i(p). //
15189 // //
15191 
15192 void tetgenmesh::formbowatcavitysegquad(point bp, list* tetlist,list* ceillist)
15193 {
15194  triface starttet, neightet, cavtet;
15195  face checksh;
15196  point pa, pb, pc, pd, pe;
15197  REAL sign;
15198  int i;
15199 
15200  // Form BC_i(p) by a broadth-first searching.
15201  for (i = 0; i < tetlist->len(); i++) {
15202  starttet = * (triface *)(* tetlist)[i];
15203  for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
15204  // Try to collect the neighbor of the face f.
15205  tspivot(starttet, checksh);
15206  if (checksh.sh == dummysh) {
15207  // Get its neighbor n.
15208  sym(starttet, neightet);
15209  // Is n already in BC_i(p)?
15210  if (!infected(neightet)) {
15211  // For positive orientation that insphere() test requires.
15212  adjustedgering(neightet, CW);
15213  pa = org(neightet);
15214  pb = dest(neightet);
15215  pc = apex(neightet);
15216  pd = oppo(neightet);
15217  sign = insphere(pa, pb, pc, pd, bp);
15218  if (sign >= 0.0) {
15219  // Collect it into BC_i(p).
15220  infect(neightet);
15221  tetlist->append(&neightet);
15222  } else {
15223  // Check if the face is locally non-Delaunay.
15224  pe = oppo(starttet);
15225  sign = insphere(pa, pb, pc, pd, pe);
15226  if (sign >= 0.0) {
15227  // Collect it into BC_i(p).
15228  infect(neightet);
15229  tetlist->append(&neightet);
15230  }
15231  }
15232  }
15233  }
15234  }
15235  }
15236 
15237  // Generate B_i(p).
15238  for (i = 0; i < tetlist->len(); i++) {
15239  cavtet = * (triface *)(* tetlist)[i];
15240  for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
15241  tspivot(cavtet, checksh);
15242  if (checksh.sh == dummysh) {
15243  sym(cavtet, neightet);
15244  if (!infected(neightet)) {
15245  ceillist->append(&cavtet); // Found a face of B(p).
15246  }
15247  } else {
15248  // Do not cross a boundary face.
15249  if (!sinfected(checksh)) {
15250  ceillist->append(&cavtet); // Found a face of B(p).
15251  }
15252  }
15253  }
15254  }
15255 
15256  if (b->verbose > 2) {
15257  printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp),
15258  tetlist->len(), ceillist->len());
15259  }
15260 }
15261 
15263 // //
15264 // formbowatcavity() Form BC(p), B(p), CBC(p)s, and C(p)s. //
15265 // //
15266 // If 'bpseg'(S) != NULL, p is on segment S, else, p is on facet containing //
15267 // 'bpsh' (F). 'n' returns the number of quadrants in BC(p). 'nmax' is the //
15268 // maximum pre-allocated array length for the lists. //
15269 // //
15271 
15272 void tetgenmesh::formbowatcavity(point bp, face* bpseg, face* bpsh, int* n,
15273  int* nmax, list** sublists, list** subceillists, list** tetlists,
15274  list** ceillists)
15275 {
15276  list *sublist;
15277  triface adjtet;
15278  face startsh, spinsh;
15279  point pa, pb;
15280  int i, j;
15281 
15282  *n = 0;
15283  if (bpseg != (face *) NULL) {
15284  // p is on segment S.
15285  bpseg->shver = 0;
15286  pa = sorg(*bpseg);
15287  pb = sdest(*bpseg);
15288  // Count the number of facets sharing at S.
15289  spivot(*bpseg, startsh);
15290  spinsh = startsh;
15291  do {
15292  (*n)++; // spinshlist->append(&spinsh);
15293  spivotself(spinsh);
15294  } while (spinsh.sh != startsh.sh);
15295  // *n is the number of quadrants around S.
15296  if (*n > *nmax) {
15297  // Reallocate arrays. Should not happen very often.
15298  delete [] tetlists;
15299  delete [] ceillists;
15300  delete [] sublists;
15301  delete [] subceillists;
15302  tetlists = new list*[*n];
15303  ceillists = new list*[*n];
15304  sublists = new list*[*n];
15305  subceillists = new list*[*n];
15306  *nmax = *n;
15307  }
15308  // Form CBC(p)s and C(p)s.
15309  spinsh = startsh;
15310  for (i = 0; i < *n; i++) {
15311  sublists[i] = new list(sizeof(face), NULL, 256);
15312  subceillists[i] = new list(sizeof(face), NULL, 256);
15313  // Set a subface f to start search.
15314  startsh = spinsh;
15315  // Let f face to the quadrant of interest (used in forming BC(p)).
15316  findedge(&startsh, pa, pb);
15317  sinfect(startsh);
15318  sublists[i]->append(&startsh);
15319  formbowatcavitysub(bp, bpseg, sublists[i], subceillists[i]);
15320  // Go to the next facet.
15321  spivotself(spinsh);
15322  }
15323  } else if (sublists != (list **) NULL) {
15324  // p is on a facet.
15325  *n = 2;
15326  // Form CBC(p) and C(p).
15327  sublists[0] = new list(sizeof(face), NULL, 256);
15328  subceillists[0] = new list(sizeof(face), NULL, 256);
15329  sinfect(*bpsh);
15330  sublists[0]->append(bpsh);
15331  formbowatcavitysub(bp, NULL, sublists[0], subceillists[0]);
15332  } else {
15333  // p is inside a tet.
15334  *n = 1;
15335  }
15336 
15337  // Form BC_i(p) and B_i(p).
15338  for (i = 0; i < *n; i++) {
15339  tetlists[i] = new list(sizeof(triface), NULL, 256);
15340  ceillists[i] = new list(sizeof(triface), NULL, 256);
15341  if (sublists != (list **) NULL) {
15342  // There are C(p)s.
15343  sublist = ((bpseg == (face *) NULL) ? sublists[0] : sublists[i]);
15344  // Add all adjacent tets of C_i(p) into BC_i(p).
15345  for (j = 0; j < sublist->len(); j++) {
15346  startsh = * (face *)(* sublist)[j];
15347  // Adjust the side facing to the right quadrant for C(p).
15348  if ((bpseg == (face *) NULL) && (i == 1)) sesymself(startsh);
15349  stpivot(startsh, adjtet);
15350  if (adjtet.tet != dummytet) {
15351  if (!infected(adjtet)) {
15352  infect(adjtet);
15353  tetlists[i]->append(&adjtet);
15354  }
15355  }
15356  }
15357  if (bpseg != (face *) NULL) {
15358  // The quadrant is bounded by another facet.
15359  sublist = ((i < *n - 1) ? sublists[i + 1] : sublists[0]);
15360  for (j = 0; j < sublist->len(); j++) {
15361  startsh = * (face *)(* sublist)[j];
15362  // Adjust the side facing to the right quadrant for C(p).
15363  sesymself(startsh);
15364  stpivot(startsh, adjtet);
15365  if (adjtet.tet != dummytet) {
15366  if (!infected(adjtet)) {
15367  infect(adjtet);
15368  tetlists[i]->append(&adjtet);
15369  }
15370  }
15371  }
15372  }
15373  }
15374  // It is possible that BC_i(p) is empty.
15375  if (tetlists[i]->len() == 0) continue;
15376  // Collect the rest of tets of BC_i(p) and form B_i(p).
15377  // if (b->conformdel) {
15378  // formbowatcavitysegquad(bp, tetlists[i], ceillists[i]);
15379  // } else {
15380  formbowatcavityquad(bp, tetlists[i], ceillists[i]);
15381  // }
15382  }
15383 }
15384 
15386 // //
15387 // releasebowatcavity() Undo and free the memory allocated in routine //
15388 // formbowatcavity(). //
15389 // //
15391 
15392 void tetgenmesh::releasebowatcavity(face* bpseg, int n, list** sublists,
15393  list** subceillist, list** tetlists, list** ceillists)
15394 {
15395  triface oldtet;
15396  face oldsh;
15397  int i, j;
15398 
15399  if (sublists != (list **) NULL) {
15400  // Release CBC(p)s.
15401  for (i = 0; i < n; i++) {
15402  // Uninfect subfaces of CBC(p).
15403  for (j = 0; j < sublists[i]->len(); j++) {
15404  oldsh = * (face *)(* (sublists[i]))[j];
15405 #ifdef SELF_CHECK
15406  assert(sinfected(oldsh));
15407 #endif
15408  suninfect(oldsh);
15409  }
15410  delete sublists[i];
15411  delete subceillist[i];
15412  sublists[i] = (list *) NULL;
15413  subceillist[i] = (list *) NULL;
15414  if (bpseg == (face *) NULL) break;
15415  }
15416  }
15417  // Release BC(p).
15418  for (i = 0; i < n; i++) {
15419  // Uninfect tets of BC_i(p).
15420  for (j = 0; j < tetlists[i]->len(); j++) {
15421  oldtet = * (triface *)(* (tetlists[i]))[j];
15422 #ifdef SELF_CHECK
15423  assert(infected(oldtet));
15424 #endif
15425  uninfect(oldtet);
15426  }
15427  delete tetlists[i];
15428  delete ceillists[i];
15429  tetlists[i] = (list *) NULL;
15430  ceillists[i] = (list *) NULL;
15431  }
15432 }
15433 
15435 // //
15436 // validatebowatcavityquad() Valid B_i(p). //
15437 // //
15438 // B_i(p) is valid if all faces of B_i(p) are visible by p, else B_i(p) is //
15439 // invalid. Each tet of BC_i(p) which has such a face is marked (uninfect). //
15440 // They will be removed in updatebowatcavityquad(). //
15441 // //
15442 // Return TRUE if B(p) is valid, else, return FALSE. //
15443 // //
15445 
15446 bool tetgenmesh::validatebowatcavityquad(point bp,list* ceillist,REAL maxcosd)
15447 {
15448  triface ceiltet;
15449  point pa, pb, pc;
15450  REAL ori, cosd;
15451  int remcount, i;
15452 
15453  // Check the validate of B(p), cut tets having invisible faces.
15454  remcount = 0;
15455  for (i = 0; i < ceillist->len(); i++) {
15456  ceiltet = * (triface *)(* ceillist)[i];
15457  if (infected(ceiltet)) {
15458  adjustedgering(ceiltet, CCW);
15459  pa = org(ceiltet);
15460  pb = dest(ceiltet);
15461  pc = apex(ceiltet);
15462  ori = orient3d(pa, pb, pc, bp);
15463  if (ori >= 0.0) {
15464  // Found an invisible face.
15465  uninfect(ceiltet);
15466  remcount++;
15467  continue;
15468  }
15469  // If a non-trival 'maxcosd' is given.
15470  if (maxcosd > -1.0) {
15471  // Get the maximal dihedral angle of tet abcp.
15472  tetalldihedral(pa, pb, pc, bp, NULL, &cosd, NULL);
15473  // Do not form the tet if the maximal dihedral angle is not reduced.
15474  if (cosd < maxcosd) {
15475  uninfect(ceiltet);
15476  remcount++;
15477  }
15478  }
15479  }
15480  }
15481  return remcount == 0;
15482 }
15483 
15485 // //
15486 // updatebowatcavityquad() Update BC_i(p) and reform B_i(p). //
15487 // //
15488 // B_i(p) is invalid and some tets in BC_i(p) have been marked to be removed //
15489 // in validatebowatcavityquad(). This routine actually remove the cut tets //
15490 // of BC_i(p) and re-form the B_i(p). //
15491 // //
15493 
15494 void tetgenmesh::updatebowatcavityquad(list* tetlist, list* ceillist)
15495 {
15496  triface cavtet, neightet;
15497  face checksh;
15498  int remcount, i;
15499 
15500  remcount = 0;
15501  for (i = 0; i < tetlist->len(); i++) {
15502  cavtet = * (triface *)(* tetlist)[i];
15503  if (!infected(cavtet)) {
15504  tetlist->del(i, 1);
15505  remcount++;
15506  i--;
15507  }
15508  }
15509 
15510  // Are there tets have been cut in BC_i(p)?
15511  if (remcount > 0) {
15512  // Re-form B_i(p).
15513  ceillist->clear();
15514  for (i = 0; i < tetlist->len(); i++) {
15515  cavtet = * (triface *)(* tetlist)[i];
15516  for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) {
15517  tspivot(cavtet, checksh);
15518  if (checksh.sh == dummysh) {
15519  sym(cavtet, neightet);
15520  if (!infected(neightet)) {
15521  ceillist->append(&cavtet); // Found a face of B_i(p).
15522  }
15523  } else {
15524  // Do not cross a boundary face.
15525  if (!sinfected(checksh)) {
15526  ceillist->append(&cavtet); // Found a face of B_i(p).
15527  }
15528  }
15529  }
15530  }
15531  if (b->verbose > 2) {
15532  printf(" Update BC_i(p): %d tets, %d faces.\n", tetlist->len(),
15533  ceillist->len());
15534  }
15535  }
15536 }
15537 
15539 // //
15540 // updatebowatcavitysub() Check and update CBC(p) and C(p). //
15541 // //
15542 // A CBC(p) is valid if all its subfaces are inside or on the hull of BC(p). //
15543 // A subface s of CBC(p) is invalid if it is in one of the two cases: //
15544 // (1) s is completely outside BC(p); //
15545 // (2) s has two adjacent tets but only one of them is in BC(p); //
15546 // s is removed from CBC(p) if it is invalid. If there is an adjacent tet of //
15547 // s which is in BC(p), it gets removed from BC(p) too. If CBC(p) is updated,//
15548 // C(p) is re-formed. //
15549 // //
15550 // A C(p) is valid if all its edges are on the hull of BC(p). An edge e of //
15551 // C(p) may be inside BC(p) if e is a segment and belongs to only one facet. //
15552 // To correct C(p), a tet of BC(p) which shields e gets removed. //
15553 // //
15554 // If BC(p) is formed with locally non-Delaunay check (b->conformdel > 0). //
15555 // A boundary-consistent check is needed for non-segment edges of C(p). Let //
15556 // e be such an edge, the subface f contains e and outside C(p) may belong //
15557 // to B(p) due to the non-coplanarity of the facet definition. The tet of //
15558 // BC(p) containing f gets removed to avoid creating a degenerate new tet. //
15559 // //
15560 // 'cutcount' accumulates the total number of cuttets(not only by this call).//
15561 // //
15563 
15564 void tetgenmesh::updatebowatcavitysub(list* sublist, list* subceillist,
15565  int* cutcount)
15566 {
15567  triface adjtet, rotface;
15568  face checksh, neighsh;
15569  face checkseg;
15570  point pa, pb, pc;
15571  REAL ori1, ori2;
15572  int remcount;
15573  int i, j;
15574 
15575  remcount = 0;
15576  // Check the validity of CBC(p).
15577  for (i = 0; i < sublist->len(); i++) {
15578  checksh = * (face *)(* sublist)[i];
15579  // Check two adjacent tets of s.
15580  for (j = 0; j < 2; j++) {
15581  stpivot(checksh, adjtet);
15582  if (adjtet.tet != dummytet) {
15583  if (!infected(adjtet)) {
15584  // Could be either case (1) or (2).
15585  suninfect(checksh); // s survives.
15586  // If the sym. adjtet exists, it should remove from BC(p) too.
15587  sesymself(checksh);
15588  stpivot(checksh, adjtet);
15589  if (adjtet.tet != dummytet) {
15590  if (infected(adjtet)) {
15591  // Found an adj. tet in BC(p), remove it.
15592  uninfect(adjtet);
15593  (*cutcount)++;
15594  }
15595  }
15596  // Remove s from C(p).
15597  sublist->del(i, 1);
15598  i--;
15599  remcount++;
15600  break;
15601  }
15602  }
15603  sesymself(checksh);
15604  }
15605  }
15606  if (remcount > 0) {
15607  if (b->verbose > 2) {
15608  printf(" Removed %d subfaces from CBC(p).\n", remcount);
15609  }
15610  // Re-generate C(p).
15611  subceillist->clear();
15612  for (i = 0; i < sublist->len(); i++) {
15613  checksh = * (face *)(* sublist)[i];
15614  for (j = 0; j < 3; j++) {
15615  spivot(checksh, neighsh);
15616  if (!sinfected(neighsh)) {
15617  subceillist->append(&checksh);
15618  }
15619  senextself(checksh);
15620  }
15621  }
15622  if (b->verbose > 2) {
15623  printf(" Update CBC(p): %d subs, %d edges.\n", sublist->len(),
15624  subceillist->len());
15625  }
15626  }
15627 
15628  // Check the validity of C(p).
15629  for (i = 0; i < subceillist->len(); i++) {
15630  checksh = * (face *)(* subceillist)[i];
15631  sspivot(checksh, checkseg);
15632  if (checkseg.sh != dummysh) {
15633  // A segment. Check if it is inside BC(p).
15634  stpivot(checksh, adjtet);
15635  if (adjtet.tet == dummytet) {
15636  sesym(checksh, neighsh);
15637  stpivot(neighsh, adjtet);
15638  }
15639  findedge(&adjtet, sorg(checkseg), sdest(checkseg));
15640  adjustedgering(adjtet, CCW);
15641  fnext(adjtet, rotface); // It's the same tet.
15642  // Rotate rotface (f), stop on either of the following cases:
15643  // (a) meet a subface, or
15644  // (b) enter an uninfected tet, or
15645  // (c) rewind back to adjtet.
15646  do {
15647  if (!infected(rotface)) break; // case (b)
15648  tspivot(rotface, neighsh);
15649  if (neighsh.sh != dummysh) break; // case (a)
15650  // Go to the next tet of the facing ring.
15651  fnextself(rotface);
15652  } while (apex(rotface) != apex(adjtet));
15653  // Is it case (c)?
15654  if (apex(rotface) == apex(adjtet)) {
15655  // The segment is enclosed by BC(p), invalid cavity.
15656  pa = org(adjtet);
15657  pb = dest(adjtet);
15658  pc = apex(adjtet);
15659  // Find the shield tet and cut it. Notice that the shield tet may
15660  // not be unique when there are four coplanar points, ie.,
15661  // ori1 * ori2 == 0.0. In such case, choose either of them.
15662  fnext(adjtet, rotface);
15663  do {
15664  fnextself(rotface);
15665  assert(infected(rotface));
15666  ori1 = orient3d(pa, pb, pc, apex(rotface));
15667  ori2 = orient3d(pa, pb, pc, oppo(rotface));
15668  } while (ori1 * ori2 > 0.0);
15669  // Cut this tet from BC(p).
15670  uninfect(rotface);
15671  (*cutcount)++;
15672  }
15673  } else {
15674  /*// An edge. Check if boundary-consistency should be enforced.
15675  if (b->conformdel > 0) {
15676  // Get the adj-sub n at e, it must be outside C(p).
15677  spivot(checksh, neighsh);
15678  assert(!sinfected(neighsh));
15679  // Check if n is on B(p).
15680  for (j = 0; j < 2; j++) {
15681  stpivot(neighsh, adjtet);
15682  if (adjtet.tet != dummytet) {
15683  if (infected(adjtet)) {
15684  uninfect(adjtet);
15685  (*cutcount)++;
15686  }
15687  }
15688  sesymself(neighsh);
15689  }
15690  } */
15691  }
15692  }
15693 }
15694 
15696 // //
15697 // trimbowatcavity() Validate B(p), CBC(p)s and C(p)s, update BC(p). //
15698 // //
15699 // A B(p) is valid if all its faces are visible by p. If a face f of B(p) is //
15700 // found invisible by p, the tet of BC(p) containing f gets removed and B(p) //
15701 // is refromed. The new B(p) may still contain invisible faces by p. Iterat- //
15702 // ively do the above procedure until B(p) is satisfied. //
15703 // //
15704 // A CBC(p) is valid if each subface of CBC(p) is either on the hull of BC(p)//
15705 // or completely inside BC(p). If a subface s of CBC(p) is not valid, it is //
15706 // removed from CBC(p) and C(p) is reformed. If there exists a tet t of BC(p)//
15707 // containg s, t is removed from BC(p). The process for validating BC(p) and //
15708 // B(p) is re-excuted. //
15709 // //
15710 // A C(p) is valid if each edge of C(p) is on the hull of BC(p). If an edge //
15711 // e of C(p) is invalid (e should be a subsegment which only belong to one //
15712 // facet), a tet of BC(p) which contains e and has two other faces shielding //
15713 // e is removed. The process for validating BC(p) and B(p) is re-excuted. //
15714 // //
15715 // If either BC(p) or CBC(p) becomes empty. No valid BC(p) is found, return //
15716 // FALSE. else, return TRUE. //
15717 // //
15719 
15720 bool tetgenmesh::trimbowatcavity(point bp, face* bpseg, int n, list** sublists,
15721  list** subceillists, list** tetlists, list** ceillists, REAL maxcosd)
15722 {
15723  bool valflag;
15724  int oldnum, cutnum, cutcount;
15725  int i;
15726 
15727  cutnum = 0; // Count the total number of cut-off tets of BC(p).
15728  valflag = true;
15729 
15730  do {
15731  // Validate BC(p), B(p).
15732  for (i = 0; i < n && valflag; i++) {
15733  oldnum = tetlists[i]->len();
15734  // Iteratively validate BC_i(p) and B_i(p).
15735  while (!validatebowatcavityquad(bp, ceillists[i], maxcosd)) {
15736  // Update BC_i(p) and B_i(p).
15737  updatebowatcavityquad(tetlists[i], ceillists[i]);
15738  valflag = tetlists[i]->len() > 0;
15739  }
15740  cutnum += (oldnum - tetlists[i]->len());
15741  }
15742  if (valflag && (sublists != (list **) NULL)) {
15743  // Validate CBC(p), C(p).
15744  cutcount = 0;
15745  for (i = 0; i < n; i++) {
15746  updatebowatcavitysub(sublists[i], subceillists[i], &cutcount);
15747  // Only do once if p is on a facet.
15748  if (bpseg == (face *) NULL) break;
15749  }
15750  // Are there cut tets?
15751  if (cutcount > 0) {
15752  // Squeeze all cut tets in BC(p), keep valflag once it gets FLASE.
15753  for (i = 0; i < n; i++) {
15754  if (tetlists[i]->len() > 0) {
15755  updatebowatcavityquad(tetlists[i], ceillists[i]);
15756  if (valflag) {
15757  valflag = tetlists[i]->len() > 0;
15758  }
15759  }
15760  }
15761  cutnum += cutcount;
15762  // Go back to valid the updated BC(p).
15763  continue;
15764  }
15765  }
15766  break; // Leave the while-loop.
15767  } while (true);
15768 
15769  // Check if any CBC(p) becomes non-empty.
15770  if (valflag && (sublists != (list **) NULL)) {
15771  for (i = 0; i < n && valflag; i++) {
15772  valflag = (sublists[i]->len() > 0);
15773  if (bpseg == (face *) NULL) break;
15774  }
15775  }
15776 
15777  if (valflag && (cutnum > 0)) {
15778  // Accumulate counters.
15779  if (bpseg != (face *) NULL) {
15780  updsegcount++;
15781  } else if (sublists != (list **) NULL) {
15782  updsubcount++;
15783  } else {
15784  updvolcount++;
15785  }
15786  }
15787 
15788  if (!valflag) {
15789  // Accumulate counters.
15790  if (bpseg != (face *) NULL) {
15791  failsegcount++;
15792  } else if (sublists != (list **) NULL) {
15793  failsubcount++;
15794  } else {
15795  failvolcount++;
15796  }
15797  }
15798 
15799  return valflag;
15800 }
15801 
15803 // //
15804 // bowatinsertsite() Insert a point using the Bowyer-Watson method. //
15805 // //
15806 // Parameters: 'bp' = p, 'splitseg' = S, 'n' = the number of quadrants, //
15807 // 'sublists', an array of CBC_i(p)s, 'subceillists', an array of C_i(p)s, //
15808 // 'tetlists', an array of BC_i(p)s, 'ceillists', an array of B_i(p)s. //
15809 // //
15810 // If p is inside the mesh domain, then S = NULL, n = 1, CBC(p) and C(p) are //
15811 // NULLs. 'tetlists[0]' = BC(p), 'ceillists[0]' = B(p). //
15812 // If p is on a facet F, then S = NULL, n = 2, and 'subceillists[0]' = C(p), //
15813 // 'subceillists[1]' is not needed (set it to NULL). B_1(p) and B_2(p) are //
15814 // in 'ceillists[0]' and 'ceillists[1]'. //
15815 // If p is on a segment S, then F(S) is a list of subfaces around S, and n = //
15816 // len(F(S)), there are n C_i(p)s and B_i(p)s supplied in 'subceillists[i]'//
15817 // and 'ceillists[i]'. //
15818 // //
15819 // If 'verlist' != NULL, it returns a list of vertices which connect to p. //
15820 // This vertices are used for interpolating size of p. //
15821 // //
15822 // If 'flipque' != NULL, it returns a list of internal faces of new tets in //
15823 // BC(p), faces on C(p)s are excluded. These faces may be locally non- //
15824 // Delaunay and will be flipped if they are flippable. Such non-Delaunay //
15825 // faces may exist when p is inserted to split an encroaching segment. //
15826 // //
15827 // 'chkencseg', 'chkencsub', and 'chkbadtet' are flags that indicate whether //
15828 // or not there should be checks for the creation of encroached subsegments, //
15829 // subfaces, or bad quality tets. If 'chkencseg' = TRUE, the encroached sub- //
15830 // segments are added to the list of subsegments to be split. //
15831 // //
15832 // On return, 'ceillists' returns Star(p). //
15833 // //
15835 
15836 void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists,
15837  list** subceillists, list** tetlists, list** ceillists, list* verlist,
15838  queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet)
15839 {
15840  list *ceillist, *subceillist;
15841  triface oldtet, newtet, newface, rotface, neightet;
15842  face oldsh, newsh, newedge, checksh;
15843  face spinsh, casingin, casingout;
15844  face *apsegshs, *pbsegshs;
15845  face apseg, pbseg, checkseg;
15846  point pa, pb, pc;
15847  pa=NULL;
15848  pb=NULL;
15849  REAL attrib, volume;
15850  int idx, i, j, k;
15851 
15852  apsegshs = NULL;
15853  pbsegshs = NULL;
15854 
15855  if (b->verbose > 1) {
15856  printf(" Insert point %d (%.12g, %.12g, %.12g)", pointmark(bp), bp[0],
15857  bp[1], bp[2]);
15858  }
15859  if (splitseg != (face *) NULL) {
15860  if (b->verbose > 1) {
15861  printf(" on segment.\n");
15862  }
15863  bowatsegcount++;
15864  } else {
15865  if (subceillists != (list **) NULL) {
15866  if (b->verbose > 1) {
15867  printf(" on facet.\n");
15868  }
15869  bowatsubcount++;
15870  } else {
15871  if (b->verbose > 1) {
15872  printf(" in volume.\n");
15873  }
15874  bowatvolcount++;
15875  }
15876  }
15877 
15878  // Create new tets to fill B(p).
15879  for (k = 0; k < n; k++) {
15880  // Create new tets from each B_i(p).
15881  ceillist = ceillists[k];
15882  for (i = 0; i < ceillist->len(); i++) {
15883  oldtet = * (triface *)(* ceillist)[i];
15884  adjustedgering(oldtet, CCW);
15885  pa = org(oldtet);
15886  pb = dest(oldtet);
15887  pc = apex(oldtet);
15888  maketetrahedron(&newtet);
15889  setorg(newtet, pa);
15890  setdest(newtet, pb);
15891  setapex(newtet, pc);
15892  setoppo(newtet, bp);
15893  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
15894  attrib = elemattribute(oldtet.tet, j);
15895  setelemattribute(newtet.tet, j, attrib);
15896  }
15897  if (b->varvolume) {
15898  volume = volumebound(oldtet.tet);
15899  if (volume > 0.0) {
15900  if (!b->fixedvolume && b->refine) {
15901  // '-r -a' switches and a .vol file case. Enlarge the maximum
15902  // volume constraint for the new tets. Hence the new points
15903  // only spread near the original constrained tet.
15904  volume *= 1.2;
15905  }
15906  }
15907  setvolumebound(newtet.tet, volume);
15908  }
15909  sym(oldtet, neightet);
15910  tspivot(oldtet, checksh);
15911  if (neightet.tet != dummytet) {
15912  bond(newtet, neightet);
15913  }
15914  if (checksh.sh != dummysh) {
15915  tsbond(newtet, checksh);
15916  }
15917  if (verlist != (list *) NULL) {
15918  // Collect vertices connecting to p.
15919  idx = pointmark(pa);
15920  if (idx >= 0) {
15921  setpointmark(pa, -idx - 1);
15922  verlist->append(&pa);
15923  }
15924  idx = pointmark(pb);
15925  if (idx >= 0) {
15926  setpointmark(pb, -idx - 1);
15927  verlist->append(&pb);
15928  }
15929  idx = pointmark(pc);
15930  if (idx >= 0) {
15931  setpointmark(pc, -idx - 1);
15932  verlist->append(&pc);
15933  }
15934  }
15935  // Replace the tet by the newtet for checking the quality.
15936  * (triface *)(* ceillist)[i] = newtet;
15937  }
15938  }
15939  if (verlist != (list *) NULL) {
15940  // Uninfect collected vertices.
15941  for (i = 0; i < verlist->len(); i++) {
15942  pa = * (point *)(* verlist)[i];
15943  idx = pointmark(pa);
15944  setpointmark(pa, -(idx + 1));
15945  }
15946  }
15947 
15948  // Connect new tets of B(p). Not all faces of new tets can be connected,
15949  // e.g., if there are empty B_i(p)s.
15950  for (k = 0; k < n; k++) {
15951  ceillist = ceillists[k];
15952  for (i = 0; i < ceillist->len(); i++) {
15953  newtet = * (triface *)(* ceillist)[i];
15954  newtet.ver = 0;
15955  for (j = 0; j < 3; j++) {
15956  fnext(newtet, newface);
15957  sym(newface, neightet);
15958  if (neightet.tet == dummytet) {
15959  // Find the neighbor face by rotating the faces at edge ab.
15960  esym(newtet, rotface);
15961  pa = org(rotface);
15962  pb = dest(rotface);
15963  while (fnextself(rotface));
15964  // Do we meet a boundary face?
15965  tspivot(rotface, checksh);
15966  if (checksh.sh != dummysh) {
15967  // Walk through the boundary and continue to rotate faces.
15968  do {
15969  findedge(&checksh, pa, pb);
15970  sfnextself(checksh);
15971  assert((sorg(checksh) == pa) && (sdest(checksh) == pb));
15972  stpivot(checksh, rotface);
15973  if (infected(rotface)) {
15974  // Meet an old tet of B_i(p). This side is on the hull and
15975  // will be connected to a new subface created in C(p).
15976  break;
15977  }
15978  findedge(&rotface, pa, pb);
15979  while (fnextself(rotface));
15980  tspivot(rotface, checksh);
15981  } while (checksh.sh != dummysh);
15982  }
15983  // The rotface has edge ab, but it may not have newpt.
15984  if (apex(rotface) == apex(newface)) {
15985  // Bond the two tets together.
15986  bond(newface, rotface);
15987  // Queue (uniquely) this face if 'flipque' is given.
15988  if (flipque != (queue *) NULL) {
15989  enqueueflipface(newface, flipque);
15990  }
15991  }
15992  }
15993  enextself(newtet);
15994  }
15995  }
15996  }
15997 
15998  if (subceillists != (list **) NULL) {
15999  // There are C(p)s.
16000  if (splitseg != (face *) NULL) {
16001  // S (ab) is split by p.
16002  splitseg->shver = 0;
16003  pa = sorg(*splitseg);
16004  pb = sdest(*splitseg);
16005  // Allcate two arrays for saving the subface rings of the two new
16006  // segments a->p and p->b.
16007  apsegshs = new face[n];
16008  pbsegshs = new face[n];
16009  }
16010 
16011  // For each C_k(p), do the following:
16012  // (1) Create new subfaces to fill C_k(p), insert them into B(p);
16013  // (2) Connect new subfaces to each other;
16014  for (k = 0; k < n; k++) {
16015  subceillist = subceillists[k];
16016 
16017  // Check if 'hullsize' should be updated.
16018  oldsh = * (face *)(* subceillist)[0];
16019  stpivot(oldsh, neightet);
16020  if (neightet.tet != dummytet) {
16021  sesymself(oldsh);
16022  stpivot(oldsh, neightet);
16023  }
16024  if (neightet.tet == dummytet) {
16025  // The hull size changes.
16026  hullsize += (subceillist->len() - sublists[k]->len());
16027  }
16028 
16029  // (1) Create new subfaces to fill C_k(p), insert them into B(p).
16030  for (i = 0; i < subceillist->len(); i++) {
16031  oldsh = * (face *)(* subceillist)[i];
16032  makeshellface(subfaces, &newsh);
16033  setsorg(newsh, sorg(oldsh));
16034  setsdest(newsh, sdest(oldsh));
16035  setsapex(newsh, bp);
16036  if (b->quality && varconstraint) {
16037  setareabound(newsh, areabound(oldsh));
16038  }
16039  setshellmark(newsh, shellmark(oldsh));
16040  setshelltype(newsh, shelltype(oldsh));
16041  if (checkpbcs) {
16042  setshellpbcgroup(newsh, shellpbcgroup(oldsh));
16043  }
16044  // Replace oldsh by newsh at the edge.
16045  spivot(oldsh, casingout);
16046  sspivot(oldsh, checkseg);
16047  if (checkseg.sh != dummysh) {
16048  // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
16049  if (oldsh.sh != casingout.sh) {
16050  // s is not bonded to itself.
16051  spinsh = casingout;
16052  do {
16053  casingin = spinsh;
16054  spivotself(spinsh);
16055  } while (sapex(spinsh) != sapex(oldsh));
16056  assert(casingin.sh != oldsh.sh);
16057  // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
16058  sbond1(casingin, newsh);
16059  sbond1(newsh, casingout);
16060  } else {
16061  // Bond newsh -> newsh.
16062  sbond(newsh, newsh);
16063  }
16064  // Bond the segment.
16065  ssbond(newsh, checkseg);
16066  } else {
16067  // Bond s <-> s_out (and dissolve s_out -> s_old).
16068  sbond(newsh, casingout);
16069  }
16070 
16071  // Insert newsh into B(p). Use the coonections of oldsh.
16072  stpivot(oldsh, neightet);
16073  if (neightet.tet == dummytet) {
16074  sesymself(oldsh);
16075  sesymself(newsh); // Keep the same orientation as oldsh.
16076  stpivot(oldsh, neightet);
16077  }
16078  assert(infected(neightet));
16079  // Set on the rotating edge.
16080  findedge(&neightet, sorg(oldsh), sdest(oldsh));
16081  // Choose the rotating direction (to the inside of B(p)).
16082  adjustedgering(neightet, CCW);
16083  rotface = neightet;
16084  // Rotate face. Stop at a non-infected tet t (not in B(p)) or a
16085  // hull face f (on B(p)). Get the neighbor n of t or f. n is
16086  // a new tet that has just been created to fill B(p).
16087  do {
16088  fnextself(rotface);
16089  sym(rotface, neightet);
16090  if (neightet.tet == dummytet) {
16091  tspivot(rotface, checksh);
16092  assert(checksh.sh != dummysh);
16093  stpivot(checksh, newtet);
16094  break;
16095  } else if (!infected(neightet)) {
16096  sym(neightet, newtet);
16097  break;
16098  }
16099  } while (true);
16100  assert(newtet.tet != rotface.tet);
16101  // Set the rotating edge of n.
16102  findedge(&newtet, sorg(oldsh), sdest(oldsh));
16103  // Choose the rotating direction (to the inside of B(p)).
16104  adjustedgering(newtet, CCW);
16105  fnext(newtet, newface);
16106  assert(apex(newface) == bp);
16107  // newsh has already been oriented toward n.
16108  tsbond(newface, newsh);
16109  sym(newface, neightet); // 'neightet' maybe outside.
16110  sesymself(newsh);
16111  tsbond(neightet, newsh); // Bond them anyway.
16112 
16113  // Replace oldsh by newsh in list.
16114  * (face *)(* subceillist)[i] = newsh;
16115  }
16116 
16117  // (2) Connect new subfaces to each other.
16118  for (i = 0; i < subceillist->len(); i++) {
16119  // Get a face cdp.
16120  newsh = * (face *)(* subceillist)[i];
16121  // Get a new tet containing cdp.
16122  stpivot(newsh, newtet);
16123  if (newtet.tet == dummytet) {
16124  sesymself(newsh);
16125  stpivot(newsh, newtet);
16126  }
16127  for (j = 0; j < 2; j++) {
16128  if (j == 0) {
16129  senext(newsh, newedge); // edge dp.
16130  } else {
16131  senext2(newsh, newedge); // edge pc.
16132  sesymself(newedge); // edge cp.
16133  }
16134  if (splitseg != (face *) NULL) {
16135  // Don not operate on newedge if it is ap or pb.
16136  if (sorg(newedge) == pa) {
16137  apsegshs[k] = newedge;
16138  continue;
16139  } else if (sorg(newedge) == pb) {
16140  pbsegshs[k] = newedge;
16141  continue;
16142  }
16143  }
16144  // There should no segment inside the cavity. Check it.
16145  sspivot(newedge, checkseg);
16146  assert(checkseg.sh == dummysh);
16147  spivot(newedge, casingout);
16148  if (casingout.sh == dummysh) {
16149  rotface = newtet;
16150  findedge(&rotface, sorg(newedge), sdest(newedge));
16151  // Rotate newtet until meeting a new subface which contains
16152  // newedge. It must exist since newedge is not a seg.
16153  adjustedgering(rotface, CCW);
16154  do {
16155  fnextself(rotface);
16156  tspivot(rotface, checksh);
16157  if (checksh.sh != dummysh) break;
16158  } while (true);
16159  findedge(&checksh, sorg(newedge), sdest(newedge));
16160  sbond(newedge, checksh);
16161  }
16162  }
16163  }
16164  // Only do once if p is on a facet.
16165  if (splitseg == (face *) NULL) break;
16166  } // for (k = 0; k < n; k++)
16167 
16168  if (splitseg != (face *) NULL) {
16169  // Update a->b to be a->p.
16170  apseg = *splitseg;
16171  setsdest(apseg, bp);
16172  // Create a new subsegment p->b.
16173  makeshellface(subsegs, &pbseg);
16174  setsorg(pbseg, bp);
16175  setsdest(pbseg, pb);
16176  // p->b gets the same mark and segment type as a->p.
16177  setshellmark(pbseg, shellmark(apseg));
16178  setshelltype(pbseg, shelltype(apseg));
16179  if (b->quality && varconstraint) {
16180  // Copy the area bound into the new subsegment.
16181  setareabound(pbseg, areabound(apseg));
16182  }
16183  senext(apseg, checkseg);
16184  // Get the old connection at b of a->b.
16185  spivot(checkseg, casingout);
16186  // Bond a->p and p->b together.
16187  senext2(pbseg, casingin);
16188  sbond(casingin, checkseg);
16189  if (casingout.sh != dummysh) {
16190  // There is a subsegment connect at b of p->b.
16191  casingout.shver = 0;
16192 #ifdef SELF_CHECK
16193  assert(sorg(casingout) == pb);
16194 #endif
16195  senext2self(casingout);
16196  senext(pbseg, casingin);
16197  sbond(casingin, casingout);
16198  }
16199 
16200  // Bond all new subfaces to a->p and p->b.
16201  for (i = 0; i < n; i++) {
16202  spinsh = apsegshs[i];
16203  findedge(&spinsh, pa, bp);
16204  ssbond(spinsh, apseg);
16205  spinsh = pbsegshs[i];
16206  findedge(&spinsh, bp, pb);
16207  ssbond(spinsh, pbseg);
16208  }
16209  // Bond all subfaces share at a->p together.
16210  for (i = 0; i < n; i++) {
16211  spinsh = apsegshs[i];
16212  if (i < (n - 1)) {
16213  casingout = apsegshs[i + 1];
16214  } else {
16215  casingout = apsegshs[0];
16216  }
16217  sbond1(spinsh, casingout);
16218  }
16219  // Bond all subfaces share at p->b together.
16220  for (i = 0; i < n; i++) {
16221  spinsh = pbsegshs[i];
16222  if (i < (n - 1)) {
16223  casingout = pbsegshs[i + 1];
16224  } else {
16225  casingout = pbsegshs[0];
16226  }
16227  sbond1(spinsh, casingout);
16228  }
16229  delete [] apsegshs;
16230  delete [] pbsegshs;
16231 
16232  // Check for newly encroached subsegments if the flag is set.
16233  if (chkencseg) {
16234  // Check if a->p and p->b are encroached by other vertices.
16235  checkseg4encroach(&apseg, NULL, NULL, true);
16236  checkseg4encroach(&pbseg, NULL, NULL, true);
16237  // Check if the adjacent segments are encroached by p.
16238  tallencsegs(bp, n, ceillists);
16239  }
16240  } // if (splitseg != (face *) NULL)
16241 
16242  // Delete subfaces of old CBC_i(p)s.
16243  for (k = 0; k < n; k++) {
16244  for (i = 0; i < sublists[k]->len(); i++) {
16245  oldsh = * (face *)(* (sublists[k]))[i];
16246  shellfacedealloc(subfaces, oldsh.sh);
16247  }
16248  // Clear the list so that the subs will not get unmarked later in
16249  // routine releasebowatcavity() which only frees the memory.
16250  sublists[k]->clear();
16251  // Only do once if p is on a facet.
16252  if (splitseg == (face *) NULL) break;
16253  }
16254 
16255  // Check for newly encroached subfaces if the flag is set.
16256  if (chkencsub) {
16257  // Check if new subfaces of C_i(p) are encroached by other vertices.
16258  for (k = 0; k < n; k++) {
16259  subceillist = subceillists[k];
16260  for (i = 0; i < subceillist->len(); i++) {
16261  newsh = * (face *)(* subceillist)[i];
16262  checksub4encroach(&newsh, NULL, true);
16263  }
16264  // Only do once if p is on a facet.
16265  if (splitseg == (face *) NULL) break;
16266  }
16267  // Check if the adjacent subfaces are encroached by p.
16268  tallencsubs(bp, n, ceillists);
16269  }
16270  } // if (subceillists != (list **) NULL)
16271 
16272  // Delete tets of old BC_i(p)s.
16273  for (k = 0; k < n; k++) {
16274  for (i = 0; i < tetlists[k]->len(); i++) {
16275  oldtet = * (triface *)(* (tetlists[k]))[i];
16276  tetrahedrondealloc(oldtet.tet);
16277  }
16278  // Clear the list so that the tets will not get unmarked later in
16279  // routine releasebowatcavity() which only frees the memory.
16280  tetlists[k]->clear();
16281  }
16282 
16283  // check for bad quality tets if the flags is set.
16284  if (chkbadtet) {
16285  for (k = 0; k < n; k++) {
16286  ceillist = ceillists[k];
16287  for (i = 0; i < ceillist->len(); i++) {
16288  newtet = * (triface *)(* ceillist)[i];
16289  checktet4badqual(&newtet, true);
16290  }
16291  }
16292  }
16293 
16294  if (flipque != (queue *) NULL) {
16295  // Newly created internal faces of BC(p) (excluding faces on C(p)s) are
16296  // in 'flipque'. Some of these faces may be locally non-Delaunay due,
16297  // to the existence of non-constrained tets. check and fix them.
16298  repairflipcount += flip(flipque, NULL);
16299  }
16300 }
16301 
16302 //
16303 // End of mesh transformation routines
16304 //
16305 
16306 //
16307 // Begin Delaunay tetrahedralization routines
16308 //
16309 
16311 // //
16312 // formstarpolyhedron() Get the star ployhedron of a point 'pt'. //
16313 // //
16314 // The polyhedron P is formed by faces of tets having 'pt' as a vertex. If //
16315 // 'complete' is TRUE, P is the complete star of 'pt'. Otherwise, P is boun- //
16316 // ded by subfaces, i.e. P is only part of the star of 'pt'. //
16317 // //
16318 // 'tetlist' T returns the tets, it has one of such tets on input. Moreover, //
16319 // if t is in T, then oppo(t) = p. Topologically, T is the star of p; and //
16320 // the faces of T is the link of p. 'verlist' V returns the vertices of T. //
16321 // //
16323 
16324 void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist,
16325  bool complete)
16326 {
16327  triface starttet, neightet;
16328  face checksh;
16329  point ver[3];
16330  int idx, i, j;
16331 
16332  // Get a tet t containing p.
16333  starttet = * (triface *)(* tetlist)[0];
16334  // Let oppo(t) = p.
16335  for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
16336  if (oppo(starttet) == pt) break;
16337  }
16338  assert(starttet.loc < 4);
16339  // Add t into T.
16340  * (triface *)(* tetlist)[0] = starttet;
16341  infect(starttet);
16342  if (verlist != (list *) NULL) {
16343  // Add three verts of t into V.
16344  ver[0] = org(starttet);
16345  ver[1] = dest(starttet);
16346  ver[2] = apex(starttet);
16347  for (i = 0; i < 3; i++) {
16348  // Mark the vert by inversing the index of the vert.
16349  idx = pointmark(ver[i]);
16350  setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero.
16351  verlist->append(&(ver[i]));
16352  }
16353  }
16354 
16355  // Find other tets by a broadth-first search.
16356  for (i = 0; i < tetlist->len(); i++) {
16357  starttet = * (triface *)(* tetlist)[i];
16358  starttet.ver = 0;
16359  for (j = 0; j < 3; j++) {
16360  fnext(starttet, neightet);
16361  tspivot(neightet, checksh);
16362  // Should we cross a subface.
16363  if ((checksh.sh == dummysh) || complete) {
16364  // Get the neighbor n.
16365  symself(neightet);
16366  if ((neightet.tet != dummytet) && !infected(neightet)) {
16367  // Let oppo(n) = p.
16368  for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
16369  if (oppo(neightet) == pt) break;
16370  }
16371  assert(neightet.loc < 4);
16372  // Add n into T.
16373  infect(neightet);
16374  tetlist->append(&neightet);
16375  if (verlist != (list *) NULL) {
16376  // Add the apex vertex in n into V.
16377  ver[0] = org(starttet);
16378  ver[1] = dest(starttet);
16379  findedge(&neightet, ver[0], ver[1]);
16380  ver[2] = apex(neightet);
16381  idx = pointmark(ver[2]);
16382  if (idx >= 0) {
16383  setpointmark(ver[2], -idx - 1);
16384  verlist->append(&(ver[2]));
16385  }
16386  }
16387  }
16388  }
16389  enextself(starttet);
16390  }
16391  }
16392 
16393  // Uninfect tets.
16394  for (i = 0; i < tetlist->len(); i++) {
16395  starttet = * (triface *)(* tetlist)[i];
16396  uninfect(starttet);
16397  }
16398  if (verlist != (list *) NULL) {
16399  // Uninfect vertices.
16400  for (i = 0; i < verlist->len(); i++) {
16401  ver[0] = * (point *)(* verlist)[i];
16402  idx = pointmark(ver[0]);
16403  setpointmark(ver[0], -(idx + 1));
16404  }
16405  }
16406 }
16407 
16409 // //
16410 // unifypoint() Unify two distinct points if they're very close. //
16411 // //
16412 // This function is used for dealing with inputs from CAD tools. Two points //
16413 // p and q are unified if: dist(p, q) / longest < eps. Where dist() is the //
16414 // Euclidean distance between p and q, longest is the maximum edge size of //
16415 // the input point set, eps is the tolerrence specified by user, default is //
16416 // 1e-6, it can be adjusted by '-T' switch. //
16417 // //
16419 
16420 bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult
16421  loc, REAL eps)
16422 {
16423  triface symtet, spintet;
16424  point checkpt, tapex;
16425  REAL tol;
16426  bool merged;
16427  int hitbdry;
16428  int i;
16429 
16430  merged = false;
16431  tol = longest * eps;
16432  if ((loc == OUTSIDE) || (loc == INTETRAHEDRON) || (loc == ONFACE)) {
16433  // Check p is close to the four corners of the tet.
16434  for (i = 0; i < 4; i++) {
16435  checkpt = (point) starttet->tet[4 + i];
16436  if (distance(testpt, checkpt) < tol) {
16437  merged = true; // Found a merge point p'.
16438  break;
16439  }
16440  }
16441  if (!merged && (loc == ONFACE)) {
16442  // Check the opposite point of the neighbor tet if it exists.
16443  sym(*starttet, symtet);
16444  if (symtet.tet != dummytet) {
16445  checkpt = oppo(symtet);
16446  if (distance(testpt, checkpt) < tol) {
16447  merged = true; // Found a merge point p'.
16448  }
16449  }
16450  }
16451  } else if (loc == ONEDGE) {
16452  // Check two endpoints of the edge.
16453  checkpt = org(*starttet);
16454  if (distance(testpt, checkpt) < tol) {
16455  merged = true; // Found a merge point p'.
16456  }
16457  if (!merged) {
16458  checkpt = dest(*starttet);
16459  if (distance(testpt, checkpt) < tol) {
16460  merged = true; // Found a merge point p'.
16461  }
16462  }
16463  if (!merged) {
16464  // Check apexes of the faces having the edge.
16465  spintet = *starttet;
16466  tapex = apex(*starttet);
16467  hitbdry = 0;
16468  do {
16469  checkpt = apex(spintet);
16470  if (distance(testpt, checkpt) < tol) {
16471  merged = true; // Found a merge point p'.
16472  break;
16473  }
16474  if (!fnextself(spintet)) {
16475  hitbdry++;
16476  if (hitbdry < 2) {
16477  esym(*starttet, spintet);
16478  if (!fnextself(spintet)) {
16479  hitbdry++;
16480  }
16481  }
16482  }
16483  } while ((apex(spintet) != tapex) && (hitbdry < 2));
16484  }
16485  }
16486  if (merged) {
16487  if (b->object != tetgenbehavior::STL) {
16488  if (!b->quiet) {
16489  printf("Warning: Point %d is unified to point %d.\n",
16490  pointmark(testpt), pointmark(checkpt));
16491  }
16492  // Count the number of duplicated points.
16493  dupverts++;
16494  }
16495  // Remember it is a duplicated point.
16496  setpointtype(testpt, DUPLICATEDVERTEX);
16497  // Set a pointer to the point it duplicates.
16498  setpoint2ppt(testpt, checkpt);
16499  }
16500  return merged;
16501 }
16502 
16504 // //
16505 // incrflipdelaunay() Construct a delaunay tetrahedrization from a set of //
16506 // 3D points by the incremental flip algorithm. //
16507 // //
16508 // The incremental flip algorithm (by Edelsbrunner and Shah) can be describ- //
16509 // ed as follows: //
16510 // //
16511 // S be a set of points in 3D, Let 4 <= i <= n and assume that the //
16512 // Delaunay tetrahedralization of the first i-1 points in S is already //
16513 // constructed; call it D(i-1). Add the i-th point p_i (belong to S) to //
16514 // D(i-1), and restore Delaunayhood by flipping; this result in D(i). //
16515 // Repeat this procedure until i = n. //
16516 // //
16517 // This strategy always leads to the Delaunay triangulation of a point set. //
16518 // The return value is the number of convex hull faces of D. //
16519 // //
16521 
16522 void tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray,
16523  long arraysize, bool jump, bool merge, REAL eps, queue* flipque)
16524 {
16525  triface newtet, searchtet;
16526  point swappt, lastpt;
16527  enum locateresult loc;
16528  REAL det, n[3];
16529  REAL attrib, volume;
16530  int i, j;
16531 #ifdef SELF_CHECK
16532  clock_t loc_start, loc_end;
16533 #endif
16534 
16535  det = 0.0;
16536  if (b->verbose > 0) {
16537  printf(" Creating initial tetrahedralization.\n");
16538  }
16539 
16540  // The initial tetrahedralization T only has one tet formed by 4 affinely
16541  // linear independent vertices of the point set V = 'insertarray'. The
16542  // first point a = insertarray[0].
16543 
16544  // Get the second point b, that is not identical or very close to a.
16545  for (i = 1; i < arraysize; i++) {
16546  det = distance(insertarray[0], insertarray[i]);
16547  if (det > (longest * eps)) break;
16548  }
16549  if (i == arraysize) {
16550  printf("\nAll points seem to be identical.\n");
16551  return;
16552  } else {
16553  // Swap to move b from index i to index 1.
16554  swappt = insertarray[i];
16555  insertarray[i] = insertarray[1];
16556  insertarray[1] = swappt;
16557  }
16558  // Get the third point c, that is not collinear with a and b.
16559  for (i++; i < arraysize; i++) {
16560  if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps))
16561  break;
16562  }
16563  if (i == arraysize) {
16564  printf("\nAll points seem to be collinear.\n");
16565  return;
16566  } else {
16567  // Swap to move c from index i to index 2.
16568  swappt = insertarray[i];
16569  insertarray[i] = insertarray[2];
16570  insertarray[2] = swappt;
16571  }
16572  // Get the fourth point d, that is not coplanar with a, b, and c.
16573  for (i++; i < arraysize; i++) {
16574  det = orient3d(insertarray[0], insertarray[1], insertarray[2],
16575  insertarray[i]);
16576  if (det == 0.0) continue;
16577  if (!iscoplanar(insertarray[0], insertarray[1], insertarray[2],
16578  insertarray[i], det, eps)) break;
16579  }
16580  if (i == arraysize) {
16581  // It's a 2D problem.
16582  in->mesh_dim = 2;
16583  // All points are coplanar.
16584  if (b->plc) {
16585  // Create an abovepoint. Maybe a surface triangulation can be formed.
16586  facenormal(insertarray[0], insertarray[1], insertarray[2], n, &det);
16587  if (det != 0.0) for (j = 0; j < 3; j++) n[j] /= det;
16588  // Take the average edge length of the bounding box.
16589  det = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
16590  // Temporarily create a point. It will be removed by jettison();
16591  makepoint(&lastpt);
16592  for (j = 0; j < 3; j++) lastpt[j] = insertarray[0][j] + det * n[j];
16593  abovepoint = lastpt;
16594  det = orient3d(insertarray[0], insertarray[1], insertarray[2], lastpt);
16595  // The index of the next inserting point is 3.
16596  i = 3;
16597  } else {
16598  printf("\nAll points seem to be coplanar.\n");
16599  return;
16600  }
16601  } else {
16602  // Swap to move d from index i to index 3.
16603  swappt = insertarray[i];
16604  insertarray[i] = insertarray[3];
16605  insertarray[3] = swappt;
16606  lastpt = insertarray[3];
16607  // The index of the next inserting point is 4.
16608  i = 4;
16609  }
16610 
16611  // Create the initial tet.
16612  maketetrahedron(&newtet);
16613  if (det > 0.0) {
16614  // For keeping the positive orientation.
16615  swappt = insertarray[0];
16616  insertarray[0] = insertarray[1];
16617  insertarray[1] = swappt;
16618  }
16619  if (b->verbose > 2) {
16620  printf(" Create the first tet (%d, %d, %d, %d).\n",
16621  pointmark(insertarray[0]), pointmark(insertarray[1]),
16622  pointmark(insertarray[2]), pointmark(lastpt));
16623  }
16624  setorg(newtet, insertarray[0]);
16625  setdest(newtet, insertarray[1]);
16626  setapex(newtet, insertarray[2]);
16627  setoppo(newtet, lastpt);
16628  if (oldtet != (triface *) NULL) {
16629  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
16630  attrib = elemattribute(oldtet->tet, j);
16631  setelemattribute(newtet.tet, j, attrib);
16632  }
16633  if (b->varvolume) {
16634  volume = volumebound(oldtet->tet);
16635  setvolumebound(newtet.tet, volume);
16636  }
16637  }
16638  // Set vertex type be FREEVOLVERTEX if it has no type yet.
16639  if (pointtype(insertarray[0]) == UNUSEDVERTEX) {
16640  setpointtype(insertarray[0], FREEVOLVERTEX);
16641  }
16642  if (pointtype(insertarray[1]) == UNUSEDVERTEX) {
16643  setpointtype(insertarray[1], FREEVOLVERTEX);
16644  }
16645  if (pointtype(insertarray[2]) == UNUSEDVERTEX) {
16646  setpointtype(insertarray[2], FREEVOLVERTEX);
16647  }
16648  if (pointtype(lastpt) == UNUSEDVERTEX) {
16649  setpointtype(lastpt, FREEVOLVERTEX);
16650  }
16651  // Bond to 'dummytet' for point location.
16652  dummytet[0] = encode(newtet);
16653  if (b->verbose > 3) {
16654  printf(" Creating tetra ");
16655  printtet(&newtet);
16656  }
16657  // At init, all faces of this tet are hull faces.
16658  hullsize = 4;
16659 
16660  if (b->verbose > 0) {
16661  printf(" Incrementally inserting points.\n");
16662  }
16663 
16664  flip23s = flip32s = flip22s = flip44s = 0;
16665  searchtet.tet = (tetrahedron *) NULL;
16666 
16667  // Insert the rest of points, one by one.
16668  for (; i < arraysize; i++) {
16669  // Locate p_i in T.
16670 #ifdef SELF_CHECK
16671  loc_start = clock();
16672 #endif
16673  if (jump) {
16674  loc = locate(insertarray[i], &searchtet);
16675  } else {
16676  loc = preciselocate(insertarray[i], &searchtet, tetrahedrons->items);
16677  }
16678 #ifdef SELF_CHECK
16679  loc_end = clock();
16680  tloctime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
16681 #endif
16682  // Keep current search state for next searching.
16683  recenttet = searchtet;
16684  if (loc == ONVERTEX) {
16685  if (b->object != tetgenbehavior::STL) {
16686  if (!b->quiet) {
16687  printf("Warning: Point %d is identical with point %d.\n",
16688  pointmark(insertarray[i]), pointmark(org(searchtet)));
16689  }
16690  }
16691  // Count the number of duplicated points.
16692  dupverts++;
16693  // Remember it is a duplicated point.
16694  setpointtype(insertarray[i], DUPLICATEDVERTEX);
16695  if (b->plc || b->refine) {
16696  // Set a pointer to the point it duplicates.
16697  setpoint2ppt(insertarray[i], org(searchtet));
16698  }
16699  continue; // p_i is not inserted.
16700  }
16701  if (merge) {
16702  // Unify p_i if it is too close to a point of T.
16703  if (unifypoint(insertarray[i], &searchtet, loc, eps)) {
16704  continue; // p_i is not inserted.
16705  }
16706  }
16707  // Insert p_i in T.
16708  if (loc != OUTSIDE) {
16709  if (b->verbose > 1) {
16710  printf(" Insert point %d in tetrahedralization.\n",
16711  pointmark(insertarray[i]));
16712  }
16713  if (loc == INTETRAHEDRON) {
16714  splittetrahedron(insertarray[i], &searchtet, flipque);
16715  } else if (loc == ONFACE) {
16716  splittetface(insertarray[i], &searchtet, flipque);
16717  } else if (loc == ONEDGE) {
16718  splittetedge(insertarray[i], &searchtet, flipque);
16719  }
16720  } else {
16721  if (b->verbose > 1) {
16722  printf(" Insert point %d on convex hull.\n",
16723  pointmark(insertarray[i]));
16724  }
16725  inserthullsite(insertarray[i], &searchtet, flipque);
16726  }
16727  if (pointtype(insertarray[i]) == UNUSEDVERTEX) {
16728  // p_i becomes a (volume) vertex of T.
16729  setpointtype(insertarray[i], FREEVOLVERTEX);
16730  }
16731 #ifdef SELF_CHECK
16732  loc_start = clock();
16733 #endif
16734  if (!b->noflip) {
16735  // Recover Delaunayness of T by flipping.
16736  flip(flipque, NULL);
16737  } else {
16738  lawson(NULL, flipque);
16739  // T remains regular.
16740  // flipque->clear();
16741  }
16742 #ifdef SELF_CHECK
16743  loc_end = clock();
16744  tfliptime += ((REAL) (loc_end - loc_start)) / CLOCKS_PER_SEC;
16745 #endif
16746  }
16747 
16748  if (b->verbose > 0) {
16749  printf(" %ld Flips (T23 %ld, T32 %ld, T22 %ld, T44 %ld)\n",
16750  flip23s+flip32s+flip22s+flip44s, flip23s, flip32s, flip22s, flip44s);
16751  }
16752 }
16753 
16755 // //
16756 // delaunizevertices() Form a Delaunay tetrahedralization. //
16757 // //
16758 // Given a point set V (saved in 'points'). The Delaunay tetrahedralization //
16759 // D of V is created by incrementally inserting vertices. Returns the number //
16760 // of triangular faces bounding the convex hull of D. //
16761 // //
16763 
16764 long tetgenmesh::delaunizevertices()
16765 {
16766  queue *flipque;
16767  point *insertarray;
16768  long arraysize;
16769  int i, j;
16770 
16771  if (!b->quiet) {
16772  if (!b->noflip) {
16773  printf("Constructing Delaunay tetrahedralization.\n");
16774  } else {
16775  printf("Constructing regular tetrahedralization.\n");
16776  }
16777  }
16778 
16779  flipque = new queue(sizeof(badface));
16780  // Prepare the array of points for inserting.
16781  arraysize = points->items;
16782  insertarray = new point[arraysize];
16783  points->traversalinit();
16784 
16785  // Randomize the point order.
16786  // randomseed = b->srandseed;
16787  for (i = 0; i < arraysize; i++) {
16788  j = (int) randomnation(i + 1); // 0 <= j <= i;
16789  insertarray[i] = insertarray[j];
16790  insertarray[j] = pointtraverse();
16791  }
16792 
16793  // Use lawson flip.
16794  b->noflip = 1;
16795 
16796  // Form the DT by incremental flip Delaunay algorithm.
16797  incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, b->epsilon,
16798  flipque);
16799 
16800  b->noflip = 0;
16801 
16802  delete [] insertarray;
16803  delete flipque;
16804  return hullsize;
16805 }
16806 
16807 //
16808 // End Delaunay tetrahedralization routines
16809 //
16810 
16811 //
16812 // Begin of surface triangulation routines
16813 //
16814 
16816 // //
16817 // formstarpolygon() Form the star polygon of a point in facet. //
16818 // //
16819 // The polygon P is formed by all coplanar subfaces having 'pt' as a vertex. //
16820 // P is bounded by segments, e.g, if no segments, P is the full star of pt. //
16821 // //
16822 // 'trilist' T returns the subfaces, it has one of such subfaces on input. //
16823 // In addition, if f is in T, then sapex(f) = p. 'vertlist' V are verts of P.//
16824 // Topologically, T is the star of p; V and the edges of T are the link of p.//
16825 // //
16827 
16828 void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist)
16829 {
16830  face steinsh, lnextsh, rnextsh;
16831  face checkseg;
16832  point pa, pb, pc, pd;
16833  int i;
16834 
16835  // Get a subface f containing p.
16836  steinsh = * (face *)(* trilist)[0];
16837  steinsh.shver = 0; // CCW
16838  // Let sapex(f) be p.
16839  for (i = 0; i < 3; i++) {
16840  if (sapex(steinsh) == pt) break;
16841  senextself(steinsh);
16842  }
16843  assert(i < 3);
16844  // Add the edge f into list.
16845  * (face *)(* trilist)[0] = steinsh;
16846  pa = sorg(steinsh);
16847  pb = sdest(steinsh);
16848  if (vertlist != (list *) NULL) {
16849  // Add two verts a, b into V,
16850  vertlist->append(&pa);
16851  vertlist->append(&pb);
16852  }
16853 
16854  // Rotate edge pa to the left (CW) until meet pb or a segment.
16855  lnextsh = steinsh;
16856  pc = pa;
16857  do {
16858  senext2self(lnextsh);
16859  assert(sorg(lnextsh) == pt);
16860  sspivot(lnextsh, checkseg);
16861  if (checkseg.sh != dummysh) break; // Do not cross a segment.
16862  // Get neighbor subface n (must exist).
16863  spivotself(lnextsh);
16864  if (lnextsh.sh == dummysh) break; // It's a hull edge.
16865  // Go to the edge ca opposite to p.
16866  if (sdest(lnextsh) != pt) sesymself(lnextsh);
16867  assert(sdest(lnextsh) == pt);
16868  senext2self(lnextsh);
16869  // Add n (at edge ca) to T.
16870  trilist->append(&lnextsh);
16871  // Add edge ca to E.
16872  pc = sorg(lnextsh);
16873  if (pc == pb) break; // Rotate back.
16874  if (vertlist != (list *) NULL) {
16875  // Add vert c into V.
16876  vertlist->append(&pc);
16877  }
16878  } while (true);
16879 
16880  if (pc != pb) {
16881  // Rotate edge bp to the right (CCW) until meet a segment.
16882  rnextsh = steinsh;
16883  do {
16884  senextself(rnextsh);
16885  assert(sdest(rnextsh) == pt);
16886  sspivot(rnextsh, checkseg);
16887  if (checkseg.sh != dummysh) break; // Do not cross a segment.
16888  // Get neighbor subface n (must exist).
16889  spivotself(rnextsh);
16890  if (rnextsh.sh == dummysh) break; // It's a hull edge.
16891  // Go to the edge bd opposite to p.
16892  if (sorg(rnextsh) != pt) sesymself(rnextsh);
16893  assert(sorg(rnextsh) == pt);
16894  senextself(rnextsh);
16895  // Add n (at edge bd) to T.
16896  trilist->append(&rnextsh);
16897  // Add edge bd to E.
16898  pd = sdest(rnextsh);
16899  if (pd == pa) break; // Rotate back.
16900  if (vertlist != (list *) NULL) {
16901  // Add vert d into V.
16902  vertlist->append(&pd);
16903  }
16904  } while (true);
16905  }
16906 }
16907 
16909 // //
16910 // About the 'abovepoint' //
16911 // //
16912 // The 'abovepoint' of a facet is a point which is exactly non-coplanar with //
16913 // the plane containing that facet. With such an point, the 3D predicates: //
16914 // orient3d(), and insphere() can be used to substitute the corresponding 2D //
16915 // siblings, e.g. orient2d(), and incircle(). Its location is not critical, //
16916 // but floating-point accuracy is improved if it is nicely placed over the //
16917 // facet, not too close or too far away. //
16918 // //
16919 // We take the convention that the abovepoint of a facet always lies above //
16920 // the facet. By this convention, given three points a, b, and c in a facet, //
16921 // we say c has the counterclockwise order with ab is corresponding to say //
16922 // that c is below the plane abp, where p is the lift point. //
16923 // //
16925 
16927 // //
16928 // getfacetabovepoint() Get a point above a plane pass through a facet. //
16929 // //
16930 // The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'//
16931 // is set on return. //
16932 // //
16934 
16935 void tetgenmesh::getfacetabovepoint(face* facetsh)
16936 {
16937  list *verlist, *trilist, *tetlist;
16938  triface adjtet;
16939  face symsh;
16940  point p1, p2, p3, pa;
16941  enum locateresult loc;
16942  REAL smallcos, cosa;
16943  REAL largevol, volume;
16944  REAL v1[3], v2[3], len;
16945  int smallidx, largeidx;
16946  int shmark;
16947  int i, j;
16948 
16949  abovecount++;
16950  // Initialize working lists.
16951  verlist = new list(sizeof(point *), NULL);
16952  trilist = new list(sizeof(face), NULL);
16953  tetlist = new list(sizeof(triface), NULL);
16954 
16955  // Get three pivotal points p1, p2, and p3 in the facet as a base triangle
16956  // which is non-trivil and has good base angle (close to 90 degree).
16957 
16958  // p1 is chosen as the one which has the smallest index in pa, pb, pc.
16959  p1 = sorg(*facetsh);
16960  pa = sdest(*facetsh);
16961  if (pointmark(pa) < pointmark(p1)) p1 = pa;
16962  pa = sapex(*facetsh);
16963  if (pointmark(pa) < pointmark(p1)) p1 = pa;
16964  // Form the star polygon of p1.
16965  trilist->append(facetsh);
16966  formstarpolygon(p1, trilist, verlist);
16967 
16968  // Get the second pivotal point p2.
16969  p2 = * (point *)(* verlist)[0];
16970  // Get vector v1 = p1->p2.
16971  for (i = 0; i < 3; i++) v1[i] = p2[i] - p1[i];
16972  len = sqrt(dot(v1, v1));
16973  assert(len > 0.0); // p2 != p1.
16974  for (i = 0; i < 3; i++) v1[i] /= len;
16975 
16976  // Get the third pivotal point p3. p3 is chosen as the one in 'verlist'
16977  // which forms an angle with v1 closer to 90 degree than others do.
16978  smallcos = 1.0; // The cosine value of 0 degree.
16979  smallidx = 1; // Default value.
16980  for (i = 1; i < verlist->len(); i++) {
16981  p3 = * (point *)(* verlist)[i];
16982  for (j = 0; j < 3; j++) v2[j] = p3[j] - p1[j];
16983  len = sqrt(dot(v2, v2));
16984  if (len > 0.0) { // v2 is not too small.
16985  cosa = fabs(dot(v1, v2)) / len;
16986  if (cosa < smallcos) {
16987  smallidx = i;
16988  smallcos = cosa;
16989  }
16990  }
16991  }
16992  assert(smallcos < 1.0); // p1->p3 != p1->p2.
16993  p3 = * (point *)(* verlist)[smallidx];
16994  verlist->clear();
16995 
16996  if (tetrahedrons->items > 0l) {
16997  // Get a tet having p1 as a vertex.
16998  stpivot(*facetsh, adjtet);
16999  if (adjtet.tet == dummytet) {
17000  sesym(*facetsh, symsh);
17001  stpivot(symsh, adjtet);
17002  }
17003  if (adjtet.tet == dummytet) {
17004  decode(point2tet(p1), adjtet);
17005  if (isdead(&adjtet)) {
17006  adjtet.tet = dummytet;
17007  } else {
17008  if (!findorg(&adjtet, p1)) {
17009  adjtet.tet = dummytet;
17010  }
17011  }
17012  }
17013  if (adjtet.tet == dummytet) {
17014  loc = locate(p1, &adjtet);
17015  if (loc == ONVERTEX) {
17016  setpoint2tet(p1, encode(adjtet));
17017  } else {
17018  adjtet.tet = dummytet;
17019  }
17020  }
17021  if (adjtet.tet != dummytet) {
17022  // Get the star polyhedron of p1.
17023  tetlist->append(&adjtet);
17024  formstarpolyhedron(p1, tetlist, verlist, false);
17025  }
17026  }
17027 
17028  // Get the abovepoint in 'verlist'. It is the one form the largest valid
17029  // volumw with the base triangle over other points in 'verlist.
17030  largevol = 0.0;
17031  largeidx = 0;
17032  for (i = 0; i < verlist->len(); i++) {
17033  pa = * (point *)(* verlist)[i];
17034  volume = orient3d(p1, p2, p3, pa);
17035  if (!iscoplanar(p1, p2, p3, pa, volume, b->epsilon * 1e+2)) {
17036  if (fabs(volume) > largevol) {
17037  largevol = fabs(volume);
17038  largeidx = i;
17039  }
17040  }
17041  }
17042 
17043  // Do we have the abovepoint?
17044  if (largevol > 0.0) {
17045  abovepoint = * (point *)(* verlist)[largeidx];
17046  if (b->verbose > 1) {
17047  printf(" Chosen abovepoint %d for facet %d.\n", pointmark(abovepoint),
17048  shellmark(*facetsh));
17049  }
17050  } else {
17051  // Calculate an abovepoint for this facet.
17052  facenormal(p1, p2, p3, v1, &len);
17053  if (len != 0.0) for (i = 0; i < 3; i++) v1[i] /= len;
17054  // Take the average edge length of the bounding box.
17055  len = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0;
17056  // Temporarily create a point. It will be removed by jettison();
17057  makepoint(&abovepoint);
17058  setpointtype(abovepoint, UNUSEDVERTEX);
17059  unuverts++;
17060  for (i = 0; i < 3; i++) abovepoint[i] = p1[i] + len * v1[i];
17061  if (b->verbose > 1) {
17062  printf(" Calculated abovepoint %d for facet %d.\n",
17063  pointmark(abovepoint), shellmark(*facetsh));
17064  }
17065  }
17066  // Save the abovepoint in 'facetabovepointarray'.
17067  shmark = shellmark(*facetsh);
17068  facetabovepointarray[shmark] = abovepoint;
17069 
17070  delete trilist;
17071  delete tetlist;
17072  delete verlist;
17073 }
17074 
17076 // //
17077 // collectcavsubs() Collect non-locally Delaunay subfaces wrt a point. //
17078 // //
17079 // 'cavsublist' returns the list of subfaces. On input, it conatins at least //
17080 // one subface. //
17081 // //
17083 
17084 void tetgenmesh::collectcavsubs(point newpoint, list* cavsublist)
17085 {
17086  face startsub, neighsub;
17087  face checkseg;
17088  point pa, pb, pc;
17089  REAL sign, ori;
17090  int i, j;
17091 
17092  // First infect subfaces in 'cavsublist'.
17093  for (i = 0; i < cavsublist->len(); i++) {
17094  startsub = * (face *)(* cavsublist)[i];
17095  sinfect(startsub);
17096  }
17097  // Find the other subfaces by a broadth-first searching.
17098  for (i = 0; i < cavsublist->len(); i++) {
17099  startsub = * (face *)(* cavsublist)[i];
17100  for (j = 0; j < 3; j++) {
17101  sspivot(startsub, checkseg);
17102  // Is there a segment?
17103  if (checkseg.sh == dummysh) {
17104  // No segment. Get the neighbor.
17105  spivot(startsub, neighsub);
17106  if (!sinfected(neighsub)) {
17107  pa = sorg(neighsub);
17108  pb = sdest(neighsub);
17109  pc = sapex(neighsub);
17110  sign = insphere(pa, pb, pc, abovepoint, newpoint);
17111  ori = orient3d(pa, pb, pc, abovepoint);
17112  if (sign != 0.0) {
17113  // Correct the sign.
17114  sign = ori > 0.0 ? sign : -sign;
17115  }
17116  if (sign > 0.0) {
17117  // neighsub is encroached by newpoint.
17118  sinfect(neighsub);
17119  cavsublist->append(&neighsub);
17120  }
17121  }
17122  }
17123  senextself(startsub);
17124  }
17125  }
17126  // Having found all subfaces, uninfect them before return.
17127  for (i = 0; i < cavsublist->len(); i++) {
17128  startsub = * (face *)(* cavsublist)[i];
17129  suninfect(startsub);
17130  }
17131 }
17132 
17134 // //
17135 // collectvisiblesubs() Collect convex hull edges which are visible from //
17136 // the inserting point. Construct new subfaces from //
17137 // these edges and the point. //
17138 // //
17139 // Let T be the current Delaunay triangulation (of vertices of a facet F). //
17140 // 'shmark', the index of F in 'in->facetlist' (starts from 1); 'inspoint' //
17141 // lies outside of T; 'horiz' is a hull edge of T which is visible by it. //
17142 // //
17144 
17145 void tetgenmesh::collectvisiblesubs(int shmark, point inspoint, face* horiz,
17146  queue* flipqueue)
17147 {
17148  face newsh, hullsh;
17149  face rightsh, leftsh, spinedge;
17150  point horg, hdest;
17151  bool aboveflag;
17152  REAL ori, sign;
17153 
17154  // Get the sign of abovepoint (so we can assume it is above the plane).
17155  adjustedgering(*horiz, CCW);
17156  horg = sorg(*horiz);
17157  hdest = sdest(*horiz);
17158  ori = orient3d(horg, hdest, sapex(*horiz), abovepoint);
17159  sign = ori > 0.0 ? -1 : 1;
17160 
17161  // Create a new subface above 'horiz'.
17162  makeshellface(subfaces, &newsh);
17163  setsorg(newsh, hdest);
17164  setsdest(newsh, horg);
17165  setsapex(newsh, inspoint);
17166  setshellmark(newsh, shmark);
17167  if (b->quality && varconstraint) {
17168  setareabound(newsh, areabound(*horiz));
17169  }
17170  if (checkpbcs) {
17171  setshellpbcgroup(newsh, shellpbcgroup(*horiz));
17172  }
17173  // Make the connection.
17174  sbond(newsh, *horiz);
17175  // 'horiz' becomes interior edge.
17176  enqueueflipedge(*horiz, flipqueue);
17177 
17178  // Finish the hull edges at the right side of the newsh.
17179  hullsh = *horiz;
17180  while (1) {
17181  senext(newsh, rightsh);
17182  // Get the right hull edge of 'horiz' by spinning inside edges around
17183  // 'horg' until reaching the 'dummysh'.
17184  spinedge = hullsh;
17185  do {
17186  hullsh = spinedge;
17187  senext2self(hullsh);
17188  spivot(hullsh, spinedge);
17189  if (spinedge.sh == dummysh) break;
17190  if (sorg(spinedge) != horg) sesymself(spinedge);
17191  assert(sorg(spinedge) == horg);
17192  } while (true);
17193  horg = sorg(hullsh);
17194  // Test whether 'inspoint' is visible by 'hullsh'.
17195  ori = orient3d(horg, sdest(hullsh), abovepoint, inspoint);
17196  ori *= sign;
17197  aboveflag = ori < 0.0;
17198  if (aboveflag) {
17199  // It's visible.
17200  makeshellface(subfaces, &newsh);
17201  setsorg(newsh, sdest(hullsh));
17202  setsdest(newsh, horg);
17203  setsapex(newsh, inspoint);
17204  setshellmark(newsh, shmark);
17205  if (b->quality && varconstraint) {
17206  setareabound(newsh, areabound(hullsh));
17207  }
17208  if (checkpbcs) {
17209  setshellpbcgroup(newsh, shellpbcgroup(hullsh));
17210  }
17211  // Make the connection.
17212  sbond(newsh, hullsh);
17213  senext2(newsh, leftsh);
17214  sbond(leftsh, rightsh);
17215  // 'hullsh' becomes interior edge.
17216  enqueueflipedge(hullsh, flipqueue);
17217  } else {
17218  // 'rightsh' is a new hull edge.
17219  dummysh[0] = sencode(rightsh);
17220  break;
17221  }
17222  }
17223 
17224  // Finish the hull edges at the left side of the newsh.
17225  hullsh = *horiz;
17226  spivot(*horiz, newsh);
17227  while (1) {
17228  senext2(newsh, leftsh);
17229  // Get the left hull edge of 'horiz' by spinning edges around 'hdest'.
17230  spinedge = hullsh;
17231  do {
17232  hullsh = spinedge;
17233  senextself(hullsh);
17234  spivot(hullsh, spinedge);
17235  if (spinedge.sh == dummysh) break;
17236  if (sdest(spinedge) != hdest) sesymself(spinedge);
17237  assert(sdest(spinedge) == hdest);
17238  } while (true);
17239  // Update 'hdest'.
17240  hdest = sdest(hullsh);
17241  // Test whether 'inspoint' is visible from 'hullsh'.
17242  ori = orient3d(sorg(hullsh), hdest, abovepoint, inspoint);
17243  ori *= sign;
17244  aboveflag = ori < 0.0;
17245  if (aboveflag) {
17246  // It's a visible hull edge.
17247  makeshellface(subfaces, &newsh);
17248  setsorg(newsh, hdest);
17249  setsdest(newsh, sorg(hullsh));
17250  setsapex(newsh, inspoint);
17251  setshellmark(newsh, shmark);
17252  if (b->quality && varconstraint) {
17253  setareabound(newsh, areabound(hullsh));
17254  }
17255  if (checkpbcs) {
17256  setshellpbcgroup(newsh, shellpbcgroup(hullsh));
17257  }
17258  // Make the connection.
17259  sbond(newsh, hullsh);
17260  senext(newsh, rightsh);
17261  sbond(rightsh, leftsh);
17262  // 'horiz' becomes interior edge.
17263  enqueueflipedge(hullsh, flipqueue);
17264  } else {
17265  // 'leftsh' is a new hull edge.
17266  dummysh[0] = sencode(leftsh);
17267  break;
17268  }
17269  }
17270 }
17271 
17273 // //
17274 // incrflipdelaunaysub() Create a DT from a 3D coplanar point set using //
17275 // the incremental flip algorithm. //
17276 // //
17277 // Let T be the current Delaunay triangulation (of vertices of a facet F). //
17278 // 'shmark', the index of F in 'in->facetlist' (starts from 1). //
17279 // //
17281 
17282 void tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist,
17283  int holes, REAL* holelist, queue* flipque)
17284 {
17285  face newsh, startsh;
17286  point *insertarray;
17287  point swappt;
17288  pbcdata *pd;
17289  enum locateresult loc;
17290  REAL det, area;
17291  bool aboveflag;
17292  int arraysize;
17293  int epscount;
17294  int fmarker;
17295  int idx, i, j, k;
17296 
17297  // Get the point array (saved in 'ptlist').
17298  insertarray = (point *) ptlist->base;
17299  arraysize = ptlist->len();
17300  if (arraysize < 3) return;
17301 
17302  // Do calculation of 'abovepoint' if number of points > 3.
17303  aboveflag = (arraysize > 3);
17304 
17305  // The initial triangulation T only has one triangle formed by 3 not
17306  // cillinear points of the set V = 'insertarray'. The first point:
17307  // a = insertarray[0].
17308 
17309  epscount = 0;
17310  while (true) {
17311  for (i = 1; i < arraysize; i++) {
17312  det = distance(insertarray[0], insertarray[i]);
17313  if (det > (longest * eps)) break;
17314  }
17315  if (i < arraysize) {
17316  // Swap to move b from index i to index 1.
17317  swappt = insertarray[i];
17318  insertarray[i] = insertarray[1];
17319  insertarray[1] = swappt;
17320  }
17321  // Get the third point c, that is not collinear with a and b.
17322  for (i++; i < arraysize; i++) {
17323  if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps))
17324  break;
17325  }
17326  if (i < arraysize) {
17327  // Swap to move c from index i to index 2.
17328  swappt = insertarray[i];
17329  insertarray[i] = insertarray[2];
17330  insertarray[2] = swappt;
17331  i = 3; // The next inserting point.
17332  } else {
17333  // The set of vertices is not good (or nearly degenerate). However,
17334  // a trivial triangulation can be formed (using 3 vertices). It may
17335  // be corrected (or deleted) by mergefacet().
17336  if ((eps == 0.0) || (epscount > 16)) {
17337  printf("Error: Invalid PLC.\n");
17338  printf(" Facet (%d, %d, %d", pointmark(insertarray[0]),
17339  pointmark(insertarray[1]), pointmark(insertarray[2]));
17340  if (ptlist->len() > 3) {
17341  printf(", ...");
17342  }
17343  printf(") (%d) is not a valid polygon.\n", shmark);
17344  terminatetetgen(1);
17345  }
17346  // Decrease the eps, and continue to try.
17347  eps *= 1e-2;
17348  epscount++;
17349  continue;
17350  }
17351  break;
17352  } // while (true);
17353 
17354  // Create the initial triangle.
17355  makeshellface(subfaces, &newsh);
17356  setsorg(newsh, insertarray[0]);
17357  setsdest(newsh, insertarray[1]);
17358  setsapex(newsh, insertarray[2]);
17359  // Remeber the facet it belongs to.
17360  setshellmark(newsh, shmark);
17361  // Set vertex type be FREESUBVERTEX if it has no type yet.
17362  if (pointtype(insertarray[0]) == FREEVOLVERTEX) {
17363  setpointtype(insertarray[0], FREESUBVERTEX);
17364  }
17365  if (pointtype(insertarray[1]) == FREEVOLVERTEX) {
17366  setpointtype(insertarray[1], FREESUBVERTEX);
17367  }
17368  if (pointtype(insertarray[2]) == FREEVOLVERTEX) {
17369  setpointtype(insertarray[2], FREESUBVERTEX);
17370  }
17371  // Let 'dummysh' point to it (for point location).
17372  dummysh[0] = sencode(newsh);
17373 
17374  // Are there area constraints?
17375  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
17376  idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
17377  for (k = 0; k < in->numberoffacetconstraints; k++) {
17378  fmarker = (int) in->facetconstraintlist[k * 2];
17379  if (fmarker == idx) {
17380  area = in->facetconstraintlist[k * 2 + 1];
17381  setareabound(newsh, area);
17382  break;
17383  }
17384  }
17385  }
17386 
17387  // Are there pbc conditions?
17388  if (checkpbcs) {
17389  idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
17390  for (k = 0; k < in->numberofpbcgroups; k++) {
17391  pd = &subpbcgrouptable[k];
17392  for (j = 0; j < 2; j++) {
17393  if (pd->fmark[j] == idx) {
17394  setshellpbcgroup(newsh, k);
17395  pd->ss[j] = newsh;
17396  }
17397  }
17398  }
17399  }
17400 
17401  if (aboveflag) {
17402  // Compute the 'abovepoint' for orient3d().
17403  abovepoint = facetabovepointarray[shmark];
17404  if (abovepoint == (point) NULL) {
17405  getfacetabovepoint(&newsh);
17406  }
17407  }
17408 
17409  if (holes > 0) {
17410  // Project hole points onto the plane containing the facet.
17411  REAL prj[3];
17412  for (k = 0; k < holes; k++) {
17413  projpt2face(&(holelist[k * 3]), insertarray[0], insertarray[1],
17414  insertarray[2], prj);
17415  for (j = 0; j < 3; j++) holelist[k * 3 + j] = prj[j];
17416  }
17417  }
17418 
17419  // Incrementally insert the rest of points into T.
17420  for (; i < arraysize; i++) {
17421  // Insert p_i.
17422  startsh.sh = dummysh;
17423  loc = locatesub(insertarray[i], &startsh, 0, 0.0);
17424  if (loc == ONFACE) {
17425  splitsubface(insertarray[i], &startsh, flipque);
17426  } else if (loc == ONEDGE) {
17427  splitsubedge(insertarray[i], &startsh, flipque);
17428  } else if (loc == OUTSIDE) {
17429  collectvisiblesubs(shmark, insertarray[i], &startsh, flipque);
17430  } else if (loc == ONVERTEX) {
17431  // !should not happen!
17432  }
17433  // Set p_i's type FREESUBVERTEX if it has no type yet.
17434  if (pointtype(insertarray[i]) == FREEVOLVERTEX) {
17435  setpointtype(insertarray[i], FREESUBVERTEX);
17436  }
17437  flipsub(flipque);
17438  }
17439 }
17440 
17442 // //
17443 // finddirectionsub() Find the first subface in a facet on the path from //
17444 // one point to another. //
17445 // //
17446 // Finds the subface in the facet that intersects a line segment drawn from //
17447 // the origin of `searchsh' to the point `tend', and returns the result in //
17448 // `searchsh'. The origin of `searchsh' does not change, even though the //
17449 // subface returned may differ from the one passed in. //
17450 // //
17451 // The return value notes whether the destination or apex of the found face //
17452 // is collinear with the two points in question. //
17453 // //
17455 
17456 enum tetgenmesh::finddirectionresult tetgenmesh::finddirectionsub(
17457  face* searchsh, point tend)
17458 {
17459  face checksh;
17460  point startpoint, leftpoint, rightpoint;
17461  REAL leftccw, rightccw;
17462  REAL ori, sign;
17463  int leftflag, rightflag;
17464 
17465  startpoint = sorg(*searchsh);
17466  // Find the sign to simulate that abovepoint is 'above' the facet.
17467  adjustedgering(*searchsh, CCW);
17468  // Make sure 'startpoint' is the origin.
17469  if (sorg(*searchsh) != startpoint) senextself(*searchsh);
17470  rightpoint = sdest(*searchsh);
17471  leftpoint = sapex(*searchsh);
17472  ori = orient3d(startpoint, rightpoint, leftpoint, abovepoint);
17473  sign = ori > 0.0 ? -1 : 1;
17474 
17475  // Is `tend' to the left?
17476  ori = orient3d(tend, startpoint, abovepoint, leftpoint);
17477  leftccw = ori * sign;
17478  leftflag = leftccw > 0.0;
17479  // Is `tend' to the right?
17480  ori = orient3d(startpoint, tend, abovepoint, rightpoint);
17481  rightccw = ori * sign;
17482  rightflag = rightccw > 0.0;
17483  if (leftflag && rightflag) {
17484  // `searchsh' faces directly away from `tend'. We could go left or
17485  // right. Ask whether it's a triangle or a boundary on the left.
17486  senext2(*searchsh, checksh);
17487  spivotself(checksh);
17488  if (checksh.sh == dummysh) {
17489  leftflag = 0;
17490  } else {
17491  rightflag = 0;
17492  }
17493  }
17494  while (leftflag) {
17495  // Turn left until satisfied.
17496  senext2self(*searchsh);
17497  spivotself(*searchsh);
17498  if (searchsh->sh == dummysh) {
17499  printf("Internal error in finddirectionsub(): Unable to find a\n");
17500  printf(" subface leading from %d to %d.\n", pointmark(startpoint),
17501  pointmark(tend));
17502  internalerror();
17503  }
17504  if (sorg(*searchsh) != startpoint) sesymself(*searchsh);
17505  assert(sorg(*searchsh) == startpoint);
17506  leftpoint = sapex(*searchsh);
17507  rightccw = leftccw;
17508  ori = orient3d(tend, startpoint, abovepoint, leftpoint);
17509  leftccw = ori * sign;
17510  leftflag = leftccw > 0.0;
17511  }
17512  while (rightflag) {
17513  // Turn right until satisfied.
17514  spivotself(*searchsh);
17515  if (searchsh->sh == dummysh) {
17516  printf("Internal error in finddirectionsub(): Unable to find a\n");
17517  printf(" subface leading from %d to %d.\n", pointmark(startpoint),
17518  pointmark(tend));
17519  internalerror();
17520  }
17521  if (sdest(*searchsh) != startpoint) sesymself(*searchsh);
17522  assert(sdest(*searchsh) == startpoint);
17523  senextself(*searchsh);
17524  rightpoint = sdest(*searchsh);
17525  leftccw = rightccw;
17526  ori = orient3d(startpoint, tend, abovepoint, rightpoint);
17527  rightccw = ori * sign;
17528  rightflag = rightccw > 0.0;
17529  }
17530  if (leftccw == 0.0) {
17531  return LEFTCOLLINEAR;
17532  } else if (rightccw == 0.0) {
17533  return RIGHTCOLLINEAR;
17534  } else {
17535  return ACROSSEDGE;
17536  }
17537 }
17538 
17540 // //
17541 // insertsubseg() Create a subsegment and insert it between two subfaces. //
17542 // //
17543 // The new subsegment ab is inserted at the edge of subface 'tri'. If ab is //
17544 // not a hull edge, it is inserted between two subfaces. If 'tri' is a hull //
17545 // face, the initial face ring of ab will be set only one face which is self-//
17546 // bonded. The final face ring will be constructed in 'unifysegments()'. //
17547 // //
17549 
17550 void tetgenmesh::insertsubseg(face* tri)
17551 {
17552  face oppotri;
17553  face newsubseg;
17554  point pa, pb;
17555  REAL len;
17556  int e1, e2;
17557  int i;
17558 
17559  // Check if there's already a subsegment here.
17560  sspivot(*tri, newsubseg);
17561  if (newsubseg.sh == dummysh) {
17562  // Make new subsegment and initialize its vertices.
17563  makeshellface(subsegs, &newsubseg);
17564  pa = sorg(*tri);
17565  pb = sdest(*tri);
17566  setsorg(newsubseg, pa);
17567  setsdest(newsubseg, pb);
17568  // Are there length constraints?
17569  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
17570  for (i = 0; i < in->numberofsegmentconstraints; i++) {
17571  e1 = (int) in->segmentconstraintlist[i * 3];
17572  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
17573  if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
17574  ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
17575  len = in->segmentconstraintlist[i * 3 + 2];
17576  setareabound(newsubseg, len);
17577  break;
17578  }
17579  }
17580  }
17581  // Bond new subsegment to the two subfaces it is sandwiched between.
17582  ssbond(*tri, newsubseg);
17583  spivot(*tri, oppotri);
17584  // 'oppotri' might be "out space".
17585  if (oppotri.sh != dummysh) {
17586  ssbond(oppotri, newsubseg);
17587  } /* else {
17588  // Outside! Bond '*tri' to itself.
17589  sbond(*tri, *tri);
17590  } */
17591  }
17592 }
17593 
17595 // //
17596 // scoutsegmentsub() Scout the first triangle on the path from one point //
17597 // to another, and check for completion (reaching the //
17598 // second point), a collinear point,or the intersection //
17599 // of two segments. //
17600 // //
17601 // Returns true if the entire segment is successfully inserted, and false if //
17602 // the job must be finished by constrainededge(). //
17603 // //
17605 
17606 bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend)
17607 {
17608  face newsubseg;
17609  face crosssub, crosssubseg;
17610  point leftpoint, rightpoint;
17611  enum finddirectionresult collinear;
17612 
17613  collinear = finddirectionsub(searchsh, tend);
17614  rightpoint = sdest(*searchsh);
17615  leftpoint = sapex(*searchsh);
17616  if (rightpoint == tend || leftpoint == tend) {
17617  // The segment is already an edge.
17618  if (leftpoint == tend) {
17619  senext2self(*searchsh);
17620  }
17621  // Insert a subsegment.
17622  insertsubseg(searchsh);
17623  return true;
17624  } else if (collinear == LEFTCOLLINEAR) {
17625  // We've collided with a vertex between the segment's endpoints.
17626  // Make the collinear vertex be the triangle's origin.
17627  senextself(*searchsh); // lprevself(*searchtri);
17628  // Insert a subsegment.
17629  insertsubseg(searchsh);
17630  // Insert the remainder of the segment.
17631  return scoutsegmentsub(searchsh, tend);
17632  } else if (collinear == RIGHTCOLLINEAR) {
17633  // We've collided with a vertex between the segment's endpoints.
17634  // Insert a subsegment.
17635  insertsubseg(searchsh);
17636  // Make the collinear vertex be the triangle's origin.
17637  senextself(*searchsh); // lnextself(*searchtri);
17638  // Insert the remainder of the segment.
17639  return scoutsegmentsub(searchsh, tend);
17640  } else {
17641  senext(*searchsh, crosssub); // lnext(*searchtri, crosstri);
17642  // Check for a crossing segment.
17643  sspivot(crosssub, crosssubseg);
17644 #ifdef SELF_CHECK
17645  assert(crosssubseg.sh == dummysh);
17646 #endif
17647  return false;
17648  }
17649 }
17650 
17652 // //
17653 // flipedgerecursive() Flip an edge. //
17654 // //
17655 // This is a support routine for inserting segments into a CDT. //
17656 // //
17657 // Let 'flipedge' be ab, and two triangles abc, abd share at it. ab may not //
17658 // flipable if the four vertices a, b, c, and d are non-convex. If it is the //
17659 // case, recursively flip ad or bd. Return when ab is flipped. //
17660 // //
17662 
17663 void tetgenmesh::flipedgerecursive(face* flipedge, queue* flipqueue)
17664 {
17665  face fixupsh;
17666  point pa, pb, pc, pd;
17667  REAL oria, orib;
17668  bool doflip;
17669 
17670  pa = sorg(*flipedge);
17671  pb = sdest(*flipedge);
17672  pc = sapex(*flipedge);
17673  do {
17674  spivot(*flipedge, fixupsh);
17675  pd = sapex(fixupsh);
17676  oria = orient3d(pc, pd, abovepoint, pa);
17677  orib = orient3d(pc, pd, abovepoint, pb);
17678  doflip = (oria * orib < 0.0);
17679  if (doflip) {
17680  // Flip the edge (a, b) away.
17681  flip22sub(flipedge, flipqueue);
17682  // Fix flipedge on edge e (c, d).
17683  findedge(flipedge, pc, pd);
17684  } else {
17685  // ab is unflipable. Get the next edge (bd, or da) to flip.
17686  if (sorg(fixupsh) != pb) sesymself(fixupsh);
17687  assert(sdest(fixupsh) == pa);
17688  if (fabs(oria) > fabs(orib)) {
17689  // acd has larger area. Choose da.
17690  senextself(fixupsh);
17691  } else {
17692  // bcd has larger area. Choose bd.
17693  senext2self(fixupsh);
17694  }
17695  // Flip the edge.
17696  flipedgerecursive(&fixupsh, flipqueue);
17697  }
17698  } while (!doflip);
17699 }
17700 
17702 // //
17703 // constrainededge() Force a segment into a CDT. //
17704 // //
17705 // The segment s is recovered by flipping away the edges it intersects, and //
17706 // triangulating the polygons that form on each side of it. //
17707 // //
17708 // Generates a single subsegment connecting `tstart' to `tend'. The triangle //
17709 // `startsh' has `tstart' as its origin. //
17710 // //
17712 
17713 void tetgenmesh::constrainededge(face* startsh, point tend, queue* flipqueue)
17714 {
17715  point tstart, tright, tleft;
17716  REAL rori, lori;
17717  bool collision;
17718 
17719  tstart = sorg(*startsh);
17720  do {
17721  // Loop edges oppo to tstart until find one crosses the segment.
17722  do {
17723  tright = sdest(*startsh);
17724  tleft = sapex(*startsh);
17725  // Is edge (tright, tleft) corss the segment.
17726  rori = orient3d(tstart, tright, abovepoint, tend);
17727  collision = (rori == 0.0);
17728  if (collision) break; // tright is on the segment.
17729  lori = orient3d(tstart, tleft, abovepoint, tend);
17730  collision = (lori == 0.0);
17731  if (collision) { // tleft is on the segment.
17732  senext2self(*startsh);
17733  break;
17734  }
17735  if (rori * lori < 0.0) break; // Find the crossing edge.
17736  // Both points are at one side of the segment.
17737  finddirectionsub(startsh, tend);
17738  } while (true);
17739  if (collision) break;
17740  // Get the neighbor face at edge e (tright, tleft).
17741  senextself(*startsh);
17742  // Flip the crossing edge.
17743  flipedgerecursive(startsh, flipqueue);
17744  // After flip, sorg(*startsh) == tstart.
17745  assert(sorg(*startsh) == tstart);
17746  } while (sdest(*startsh) != tend);
17747 
17748  // Insert a subsegment to make the segment permanent.
17749  insertsubseg(startsh);
17750  // If there was a collision with an interceding vertex, install another
17751  // segment connecting that vertex with endpoint2.
17752  if (collision) {
17753  // Insert the remainder of the segment.
17754  if (!scoutsegmentsub(startsh, tend)) {
17755  constrainededge(startsh, tend, flipqueue);
17756  }
17757  }
17758 }
17759 
17761 // //
17762 // recoversegment() Recover a segment in the surface triangulation. //
17763 // //
17765 
17766 void tetgenmesh::recoversegment(point tstart, point tend, queue* flipqueue)
17767 {
17768  face searchsh;
17769 
17770  if (b->verbose > 2) {
17771  printf(" Insert seg (%d, %d).\n", pointmark(tstart), pointmark(tend));
17772  }
17773 
17774  // Find a triangle whose origin is the segment's first endpoint.
17775  searchsh.sh = dummysh;
17776  // Search for the segment's first endpoint by point location.
17777  if (locatesub(tstart, &searchsh, 0, 0.0) != ONVERTEX) {
17778  // Possibly caused by a degenerate subface. Do a brute-force search.
17779  list *newshlist;
17780  int i, j;
17781  newshlist = new list(sizeof(face), NULL, 256);
17782  // Get new subfaces, do not remove protected segments.
17783  retrievenewsubs(newshlist, false);
17784  // Search for a sub contain tstart.
17785  for (i = 0; i < newshlist->len(); i++) {
17786  searchsh = * (face *)(* newshlist)[i];
17787  for (j = 0; j < 3; j++) {
17788  if (sorg(searchsh) == tstart) break;
17789  senextself(searchsh);
17790  }
17791  if (j < 3) break;
17792  }
17793  delete newshlist;
17794  if (sorg(searchsh) != tstart) {
17795  printf("Internal error in recoversegment(): Vertex location failed.\n");
17796  internalerror();
17797  }
17798  }
17799  // Scout the segment and insert it if it is found.
17800  if (scoutsegmentsub(&searchsh, tend)) {
17801  // The segment was easily inserted.
17802  return;
17803  }
17804  // Insert the segment into the triangulation by flips.
17805  constrainededge(&searchsh, tend, flipqueue);
17806  // Some edges may need flipping.
17807  flipsub(flipqueue);
17808 }
17809 
17811 // //
17812 // infecthullsub() Virally infect all of the triangles of the convex hull //
17813 // that are not protected by subsegments. //
17814 // //
17816 
17817 void tetgenmesh::infecthullsub(memorypool* viri)
17818 {
17819  face hulltri, nexttri, starttri;
17820  face hullsubseg;
17821  shellface **deadshellface;
17822 
17823  // Find a triangle handle on the hull.
17824  hulltri.sh = dummysh;
17825  hulltri.shver = 0;
17826  spivotself(hulltri);
17827  adjustedgering(hulltri, CCW);
17828  // Remember where we started so we know when to stop.
17829  starttri = hulltri;
17830  // Go once counterclockwise around the convex hull.
17831  do {
17832  // Ignore triangles that are already infected.
17833  if (!sinfected(hulltri)) {
17834  // Is the triangle protected by a subsegment?
17835  sspivot(hulltri, hullsubseg);
17836  if (hullsubseg.sh == dummysh) {
17837  // The triangle is not protected; infect it.
17838  if (!sinfected(hulltri)) {
17839  sinfect(hulltri);
17840  deadshellface = (shellface **) viri->alloc();
17841  *deadshellface = hulltri.sh;
17842  }
17843  }
17844  }
17845  // To find the next hull edge, go clockwise around the next vertex.
17846  senextself(hulltri); // lnextself(hulltri);
17847  spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
17848  if (nexttri.sh == hulltri.sh) {
17849  nexttri.sh = dummysh; // 'hulltri' is self-bonded.
17850  } else {
17851  adjustedgering(nexttri, CCW);
17852  senextself(nexttri);
17853  }
17854  while (nexttri.sh != dummysh) {
17855  hulltri = nexttri;
17856  spivot(hulltri, nexttri); // oprev(hulltri, nexttri);
17857  if (nexttri.sh == hulltri.sh) {
17858  nexttri.sh = dummysh; // 'hulltri' is self-bonded.
17859  } else {
17860  adjustedgering(nexttri, CCW);
17861  senextself(nexttri);
17862  }
17863  }
17864  } while (hulltri != starttri);
17865 }
17866 
17868 // //
17869 // plaguesub() Spread the virus from all infected triangles to any //
17870 // neighbors not protected by subsegments. Delete all //
17871 // infected triangles. //
17872 // //
17873 // This is the procedure that actually creates holes and concavities. //
17874 // //
17876 
17877 void tetgenmesh::plaguesub(memorypool* viri)
17878 {
17879  face testtri, neighbor, ghostsh;
17880  face neighborsubseg;
17881  shellface **virusloop;
17882  shellface **deadshellface;
17883  int i;
17884 
17885  // Loop through all the infected triangles, spreading the virus to
17886  // their neighbors, then to their neighbors' neighbors.
17887  viri->traversalinit();
17888  virusloop = (shellface **) viri->traverse();
17889  while (virusloop != (shellface **) NULL) {
17890  testtri.sh = *virusloop;
17891  // Check each of the triangle's three neighbors.
17892  for (i = 0; i < 3; i++) {
17893  // Find the neighbor.
17894  spivot(testtri, neighbor);
17895  // Check for a subsegment between the triangle and its neighbor.
17896  sspivot(testtri, neighborsubseg);
17897  // Check if the neighbor is nonexistent or already infected.
17898  if ((neighbor.sh == dummysh) || sinfected(neighbor)) {
17899  if (neighborsubseg.sh != dummysh) {
17900  // There is a subsegment separating the triangle from its
17901  // neighbor, but both triangles are dying, so the subsegment
17902  // dies too.
17903  shellfacedealloc(subsegs, neighborsubseg.sh);
17904  if (neighbor.sh != dummysh) {
17905  // Make sure the subsegment doesn't get deallocated again
17906  // later when the infected neighbor is visited.
17907  ssdissolve(neighbor);
17908  }
17909  }
17910  } else { // The neighbor exists and is not infected.
17911  if (neighborsubseg.sh == dummysh) {
17912  // There is no subsegment protecting the neighbor, so the
17913  // neighbor becomes infected.
17914  sinfect(neighbor);
17915  // Ensure that the neighbor's neighbors will be infected.
17916  deadshellface = (shellface **) viri->alloc();
17917  *deadshellface = neighbor.sh;
17918  } else { // The neighbor is protected by a subsegment.
17919  // Remove this triangle from the subsegment.
17920  ssbond(neighbor, neighborsubseg);
17921  }
17922  }
17923  senextself(testtri);
17924  }
17925  virusloop = (shellface **) viri->traverse();
17926  }
17927 
17928  ghostsh.sh = dummysh; // A handle of outer space.
17929  viri->traversalinit();
17930  virusloop = (shellface **) viri->traverse();
17931  while (virusloop != (shellface **) NULL) {
17932  testtri.sh = *virusloop;
17933  // Record changes in the number of boundary edges, and disconnect
17934  // dead triangles from their neighbors.
17935  for (i = 0; i < 3; i++) {
17936  spivot(testtri, neighbor);
17937  if (neighbor.sh != dummysh) {
17938  // Disconnect the triangle from its neighbor.
17939  // sdissolve(neighbor);
17940  sbond(neighbor, ghostsh);
17941  }
17942  senextself(testtri);
17943  }
17944  // Return the dead triangle to the pool of triangles.
17945  shellfacedealloc(subfaces, testtri.sh);
17946  virusloop = (shellface **) viri->traverse();
17947  }
17948  // Empty the virus pool.
17949  viri->restart();
17950 }
17951 
17953 // //
17954 // carveholessub() Find the holes and infect them. Find the area //
17955 // constraints and infect them. Infect the convex hull. //
17956 // Spread the infection and kill triangles. Spread the //
17957 // area constraints. //
17958 // //
17959 // This routine mainly calls other routines to carry out all these functions.//
17960 // //
17962 
17963 void tetgenmesh::carveholessub(int holes, REAL* holelist, memorypool *viri)
17964 {
17965  face searchtri, triangleloop;
17966  shellface **holetri;
17967  enum locateresult intersect;
17968  int i;
17969 
17970  // Mark as infected any unprotected triangles on the boundary.
17971  // This is one way by which concavities are created.
17972  infecthullsub(viri);
17973 
17974  if (holes > 0) {
17975  // Infect each triangle in which a hole lies.
17976  for (i = 0; i < 3 * holes; i += 3) {
17977  // Ignore holes that aren't within the bounds of the mesh.
17978  if ((holelist[i] >= xmin) && (holelist[i] <= xmax)
17979  && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)
17980  && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) {
17981  // Start searching from some triangle on the outer boundary.
17982  searchtri.sh = dummysh;
17983  // Find a triangle that contains the hole.
17984  intersect = locatesub(&holelist[i], &searchtri, 0, 0.0);
17985  if ((intersect != OUTSIDE) && (!sinfected(searchtri))) {
17986  // Infect the triangle. This is done by marking the triangle
17987  // as infected and including the triangle in the virus pool.
17988  sinfect(searchtri);
17989  holetri = (shellface **) viri->alloc();
17990  *holetri = searchtri.sh;
17991  }
17992  }
17993  }
17994  }
17995 
17996  if (viri->items > 0) {
17997  // Carve the holes and concavities.
17998  plaguesub(viri);
17999  }
18000  // The virus pool should be empty now.
18001 }
18002 
18004 // //
18005 // triangulate() Triangulate a PSLG into a CDT. //
18006 // //
18007 // A Planar Straight Line Graph (PSLG) P is actually a 2D polygonal region, //
18008 // possibly contains holes, segments and vertices in its interior. P is tri- //
18009 // angulated into a set of _subfaces_ forming a CDT of P. //
18010 // //
18011 // The vertices and segments of P are found in 'ptlist' and 'conlist', resp- //
18012 // ectively. 'holelist' contains a list of hole points. 'shmark' will be set //
18013 // to all subfaces of P. //
18014 // //
18015 // The CDT is created directly in the pools 'subfaces' and 'subsegs'. It can //
18016 // be retrived by a broadth-first searching starting from 'dummysh[0]'(debug //
18017 // function 'outsurfmesh()' does it). //
18018 // //
18020 
18021 void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist,
18022  int holes, REAL* holelist, memorypool* viri, queue* flipqueue)
18023 {
18024  face newsh;
18025  point *cons;
18026  int i;
18027 
18028  if (b->verbose > 1) {
18029  printf(" %d vertices, %d segments", ptlist->len(), conlist->len());
18030  if (holes > 0) {
18031  printf(", %d holes", holes);
18032  }
18033  printf(", shmark: %d.\n", shmark);
18034  }
18035 
18036  // Create the DT of V by the 2D incremental flip algorithm.
18037  incrflipdelaunaysub(shmark, eps, ptlist, holes, holelist, flipqueue);
18038  // Recover boundary edges.
18039  if (ptlist->len() > 3) {
18040  // Insert segments into the DT.
18041  for (i = 0; i < conlist->len(); i++) {
18042  cons = (point *)(* conlist)[i];
18043  recoversegment(cons[0], cons[1], flipqueue);
18044  }
18045  // Carve holes and concavities.
18046  carveholessub(holes, holelist, viri);
18047  } else if (ptlist->len() == 3) {
18048  // Insert 3 segments directly.
18049  newsh.sh = dummysh;
18050  newsh.shver = 0;
18051  spivotself(newsh);
18052  for (i = 0; i < 3; i++) {
18053  insertsubseg(&newsh);
18054  senextself(newsh);
18055  }
18056  } else if (ptlist->len() == 2) {
18057  // This facet is actually a segment. It is not support by the mesh data
18058  // strcuture. Hence the segment will not be maintained in the mesh.
18059  // However, during segment recovery, the segment can be processed.
18060  cons = (point *)(* conlist)[0];
18061  makeshellface(subsegs, &newsh);
18062  setsorg(newsh, cons[0]);
18063  setsdest(newsh, cons[1]);
18064  }
18065 }
18066 
18068 // //
18069 // retrievenewsubs() Retrieve newly created subfaces. //
18070 // //
18071 // The new subfaces created by triangulate() can be found by a broadth-first //
18072 // searching starting from 'dummysh[0]'. //
18073 // //
18074 // 'newshlist' (empty on input) returns the retrieved subfaces. Each edge on //
18075 // the hull is bound to 'dummysh' and protected by a segment. If 'removeseg' //
18076 // is TRUE, the segment is removed. //
18077 // //
18079 
18080 void tetgenmesh::retrievenewsubs(list* newshlist, bool removeseg)
18081 {
18082  face startsh, neighsh;
18083  face deadseg;
18084  int i, j;
18085 
18086  // The first new subface is found at dummysh[0].
18087  startsh.sh = dummysh;
18088  startsh.shver = 0;
18089  spivotself(startsh);
18090  assert(startsh.sh != dummysh);
18091  sinfect(startsh);
18092  newshlist->append(&startsh);
18093 
18094  // Find the rest of new subfaces by a broadth-first searching.
18095  for (i = 0; i < newshlist->len(); i++) {
18096  // Get a new subface s.
18097  startsh = * (face *)(* newshlist)[i];
18098  for (j = 0; j < 3; j++) {
18099  spivot(startsh, neighsh);
18100  if (neighsh.sh != dummysh) {
18101  if (!sinfected(neighsh)) {
18102  // Discovered a new subface.
18103  sinfect(neighsh);
18104  newshlist->append(&neighsh);
18105  }
18106  } else {
18107  // Found a boundary edge.
18108  if (removeseg) {
18109  // This side of s may be protected by a segment.
18110  sspivot(startsh, deadseg);
18111  if (deadseg.sh != dummysh) {
18112  // Detach it from s.
18113  ssdissolve(startsh);
18114  // Delete the segment.
18115  shellfacedealloc(subsegs, deadseg.sh);
18116  }
18117  }
18118  }
18119  senextself(startsh);
18120  }
18121  }
18122  for (i = 0; i < newshlist->len(); i++) {
18123  startsh = * (face *)(* newshlist)[i];
18124  suninfect(startsh);
18125  }
18126 }
18127 
18129 // //
18130 // unifysegments() Unify identical segments and build facet connections. //
18131 // //
18132 // After creating the surface mesh. Each facet has its own segments. There //
18133 // are duplicated segments between adjacent facets. This routine has three //
18134 // purposes: //
18135 // (1) identify the set of segments which have the same endpoints and //
18136 // unify them into one segment, remove redundant ones; //
18137 // (2) create the face rings of the unified segments, hence setup the //
18138 // connections between facets; and //
18139 // (3) set a unique marker (1-based) for each segment. //
18140 // On finish, each segment is unique and the face ring around it (right-hand //
18141 // rule) is constructed. The connections between facets-facets are setup. //
18142 // //
18144 
18145 void tetgenmesh::unifysegments()
18146 {
18147  list *sfacelist;
18148  shellface **facesperverlist;
18149  face subsegloop, testseg;
18150  face sface, sface1, sface2;
18151  point torg, tdest;
18152  REAL da1, da2;
18153  int *idx2facelist;
18154  int segmarker;
18155  int idx, k, m;
18156 
18157  if (b->verbose > 0) {
18158  printf(" Unifying segments.\n");
18159  }
18160 
18161  // Compute a mapping from indices of vertices to subfaces.
18162  makesubfacemap(idx2facelist, facesperverlist);
18163  // Initialize 'sfacelist' for constructing the face link of each segment.
18164  sfacelist = new list(sizeof(face), NULL);
18165 
18166  segmarker = 1;
18167  subsegs->traversalinit();
18168  subsegloop.sh = shellfacetraverse(subsegs);
18169  while (subsegloop.sh != (shellface *) NULL) {
18170  subsegloop.shver = 0; // For sure.
18171  torg = sorg(subsegloop);
18172  tdest = sdest(subsegloop);
18173  idx = pointmark(torg) - in->firstnumber;
18174  // Loop through the set of subfaces containing 'torg'. Get all the
18175  // subfaces containing the edge (torg, tdest). Save and order them
18176  // in 'sfacelist', the ordering is defined by the right-hand rule
18177  // with thumb points from torg to tdest.
18178  for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) {
18179  sface.sh = facesperverlist[k];
18180  sface.shver = 0;
18181  // sface may be died due to the removing of duplicated subfaces.
18182  if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) {
18183  // 'sface' contains this segment.
18184  findedge(&sface, torg, tdest);
18185  // Save it in 'sfacelist'.
18186  if (sfacelist->len() < 2) {
18187  sfacelist->append(&sface);
18188  } else {
18189  for (m = 0; m < sfacelist->len() - 1; m++) {
18190  sface1 = * (face *)(* sfacelist)[m];
18191  sface2 = * (face *)(* sfacelist)[m + 1];
18192  da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface));
18193  da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
18194  if (da1 < da2) {
18195  break; // Insert it after m.
18196  }
18197  }
18198  sfacelist->insert(m + 1, &sface);
18199  }
18200  }
18201  }
18202  if (b->verbose > 1) {
18203  printf(" Identifying %d segments of (%d %d).\n", sfacelist->len(),
18204  pointmark(torg), pointmark(tdest));
18205  }
18206  // Set the connection between this segment and faces containing it,
18207  // at the same time, remove redundant segments.
18208  for (k = 0; k < sfacelist->len(); k++) {
18209  sface = *(face *)(* sfacelist)[k];
18210  sspivot(sface, testseg);
18211  // If 'testseg' is not 'subsegloop', it is a redundant segment that
18212  // needs be removed. BE CAREFUL it may already be removed. Do not
18213  // remove it twice, i.e., do test 'isdead()' together.
18214  if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) {
18215  shellfacedealloc(subsegs, testseg.sh);
18216  }
18217  // 'ssbond' bonds the subface and the segment together, and dissloves
18218  // the old bond as well.
18219  ssbond(sface, subsegloop);
18220  }
18221  // Set connection between these faces.
18222  sface = *(face *)(* sfacelist)[0];
18223  for (k = 1; k <= sfacelist->len(); k++) {
18224  if (k < sfacelist->len()) {
18225  sface1 = *(face *)(* sfacelist)[k];
18226  } else {
18227  sface1 = *(face *)(* sfacelist)[0]; // Form a face loop.
18228  }
18229  /*
18230  // Check if these two subfaces are the same. It is possible when user
18231  // defines one facet (or polygon) two or more times. If they are,
18232  // they should not be bonded together, instead of that, one of them
18233  // should be delete from the surface mesh.
18234  if ((sfacelist->len() > 1) && sapex(sface) == sapex(sface1)) {
18235  // They are duplicated faces.
18236  if (b->verbose > 0) {
18237  printf(" A duplicated subface (%d, %d, %d) is removed.\n",
18238  pointmark(torg), pointmark(tdest), pointmark(sapex(sface)));
18239  }
18240  if (k == sfacelist->len()) {
18241  // 'sface' is the last face, however, it is same as the first one.
18242  // In order to form the ring, we have to let the second last
18243  // face bond to the first one 'sface1'.
18244  shellfacedealloc(subfaces, sface.sh);
18245  assert(sfacelist->len() >= 2);
18246  assert(k == sfacelist->len());
18247  sface = *(face *)(* sfacelist)[k - 2];
18248  } else {
18249  // 'sface1' is in the middle and may be the last one.
18250  shellfacedealloc(subfaces, sface1.sh);
18251  // Skip this face and go to the next one.
18252  continue;
18253  }
18254  }
18255  */
18256  if (b->verbose > 2) {
18257  printf(" Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n",
18258  pointmark(torg), pointmark(tdest), pointmark(sapex(sface)),
18259  pointmark(torg), pointmark(tdest), pointmark(sapex(sface1)));
18260  }
18261  sbond1(sface, sface1);
18262  sface = sface1;
18263  }
18264  // Set the unique segment marker into the unified segment.
18265  setshellmark(subsegloop, segmarker);
18266  // Increase the marker.
18267  segmarker++;
18268  // Clear the working list.
18269  sfacelist->clear();
18270  subsegloop.sh = shellfacetraverse(subsegs);
18271  }
18272 
18273  delete [] idx2facelist;
18274  delete [] facesperverlist;
18275  delete sfacelist;
18276 }
18277 
18279 // //
18280 // mergefacets() Merge adjacent facets to be one facet if they are //
18281 // coplanar and have the same boundary marker. //
18282 // //
18283 // Segments between two merged facets will be removed from the mesh. If all //
18284 // segments around a vertex have been removed, change its vertex type to be //
18285 // FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of //
18286 // the triangulation of merged facets. //
18287 // //
18289 
18290 void tetgenmesh::mergefacets(queue* flipqueue)
18291 {
18292  face parentsh, neighsh, neineighsh;
18293  face segloop;
18294  point eorg, edest;
18295  REAL ori;
18296  bool mergeflag, pbcflag;
18297  int* segspernodelist;
18298  int fidx1, fidx2;
18299  int i, j;
18300 
18301  if (b->verbose > 0) {
18302  printf(" Merging coplanar facets.\n");
18303  }
18304  // Create and initialize 'segspernodelist'.
18305  segspernodelist = new int[points->items + 1];
18306  for (i = 0; i < points->items + 1; i++) segspernodelist[i] = 0;
18307 
18308  // Loop the segments, counter the number of segments sharing each vertex.
18309  subsegs->traversalinit();
18310  segloop.sh = shellfacetraverse(subsegs);
18311  while (segloop.sh != (shellface *) NULL) {
18312  // Increment the number of sharing segments for each endpoint.
18313  for (i = 0; i < 2; i++) {
18314  j = pointmark((point) segloop.sh[3 + i]);
18315  segspernodelist[j]++;
18316  }
18317  segloop.sh = shellfacetraverse(subsegs);
18318  }
18319 
18320  // Loop the segments, find out dead segments.
18321  subsegs->traversalinit();
18322  segloop.sh = shellfacetraverse(subsegs);
18323  while (segloop.sh != (shellface *) NULL) {
18324  eorg = sorg(segloop);
18325  edest = sdest(segloop);
18326  spivot(segloop, parentsh);
18327  spivot(parentsh, neighsh);
18328  spivot(neighsh, neineighsh);
18329  if (parentsh.sh != neighsh.sh && parentsh.sh == neineighsh.sh) {
18330  // Exactly two subfaces at this segment.
18331  fidx1 = shellmark(parentsh) - 1;
18332  fidx2 = shellmark(neighsh) - 1;
18333  pbcflag = false;
18334  if (checkpbcs) {
18335  pbcflag = (shellpbcgroup(parentsh) >= 0)
18336  || (shellpbcgroup(neighsh) >= 0);
18337  }
18338  // Possibly merge them if they are not in the same facet.
18339  if ((fidx1 != fidx2) && !pbcflag) {
18340  // Test if they are coplanar.
18341  ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh));
18342  if (ori != 0.0) {
18343  if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori,
18344  b->epsilon)) {
18345  ori = 0.0; // They are assumed as coplanar.
18346  }
18347  }
18348  if (ori == 0.0) {
18349  mergeflag = (in->facetmarkerlist == (int *) NULL ||
18350  in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]);
18351  if (mergeflag) {
18352  // This segment becomes dead.
18353  if (b->verbose > 1) {
18354  printf(" Removing segment (%d, %d).\n", pointmark(eorg),
18355  pointmark(edest));
18356  }
18357  ssdissolve(parentsh);
18358  ssdissolve(neighsh);
18359  shellfacedealloc(subsegs, segloop.sh);
18360  j = pointmark(eorg);
18361  segspernodelist[j]--;
18362  if (segspernodelist[j] == 0) {
18363  setpointtype(eorg, FREESUBVERTEX);
18364  }
18365  j = pointmark(edest);
18366  segspernodelist[j]--;
18367  if (segspernodelist[j] == 0) {
18368  setpointtype(edest, FREESUBVERTEX);
18369  }
18370  // Add 'parentsh' to queue checking for flip.
18371  enqueueflipedge(parentsh, flipqueue);
18372  }
18373  }
18374  }
18375  }
18376  segloop.sh = shellfacetraverse(subsegs);
18377  }
18378 
18379  if (!flipqueue->empty()) {
18380  // Restore the Delaunay property in the facet triangulation.
18381  flipsub(flipqueue);
18382  }
18383 
18384  delete [] segspernodelist;
18385 }
18386 
18388 // //
18389 // meshsurface() Create the surface mesh of a PLC. //
18390 // //
18391 // Let X be the PLC, the surface mesh S of X consists of triangulated facets.//
18392 // S is created mainly in the following steps: //
18393 // //
18394 // (1) Form the CDT of each facet of X separately (by routine triangulate()).//
18395 // After it is done, the subfaces of each facet are connected to each other, //
18396 // however there is no connection between facets yet. Notice each facet has //
18397 // its own segments, some of them are duplicated. //
18398 // //
18399 // (2) Remove the redundant segments created in step (1) (by routine unify- //
18400 // segment()). The subface ring of each segment is created, the connection //
18401 // between facets are established as well. //
18402 // //
18403 // The return value indicates the number of segments of X. //
18404 // //
18406 
18407 long tetgenmesh::meshsurface()
18408 {
18409  list *ptlist, *conlist;
18410  queue *flipqueue;
18411  tetgenio::facet *f;
18412  tetgenio::polygon *p;
18413  memorypool *viri;
18414  point *idx2verlist;
18415  point tstart, tend, *cons;
18416  int *worklist;
18417  int end1, end2;
18418  int shmark, i, j;
18419 
18420  if (!b->quiet) {
18421  printf("Creating surface mesh.\n");
18422  }
18423 
18424  // Compute a mapping from indices to points.
18425  makeindex2pointmap(idx2verlist);
18426  // Compute a mapping from points to tets for computing abovepoints.
18427  makepoint2tetmap();
18428  // Initialize 'facetabovepointarray'.
18429  facetabovepointarray = new point[in->numberoffacets + 1];
18430  for (i = 0; i < in->numberoffacets + 1; i++) {
18431  facetabovepointarray[i] = (point) NULL;
18432  }
18433  if (checkpbcs) {
18434  // Initialize the global array 'subpbcgrouptable'.
18435  createsubpbcgrouptable();
18436  }
18437 
18438  // Initialize working lists.
18439  viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
18440  flipqueue = new queue(sizeof(badface));
18441  ptlist = new list(sizeof(point *), NULL, 256);
18442  conlist = new list(sizeof(point *) * 2, NULL, 256);
18443  worklist = new int[points->items + 1];
18444  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
18445 
18446  // Loop the facet list, triangulate each facet. On finish, all subfaces
18447  // are in 'subfaces', all segments are in 'subsegs'. Notice: there're
18448  // redundant segments. Remember: All facet indices count from 1.
18449  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
18450  // Get a facet F.
18451  f = &in->facetlist[shmark - 1];
18452 
18453  // Process the duplicated points first, they are marked with type
18454  // DUPLICATEDVERTEX by incrflipdelaunay(). Let p and q are dup.
18455  // and the index of p is larger than q's, p is substituted by q.
18456  // In a STL mesh, duplicated points are implicitly included.
18457  if ((b->object == tetgenbehavior::STL) || dupverts) {
18458  // Loop all polygons of this facet.
18459  for (i = 0; i < f->numberofpolygons; i++) {
18460  p = &(f->polygonlist[i]);
18461  // Loop other vertices of this polygon.
18462  for (j = 0; j < p->numberofvertices; j++) {
18463  end1 = p->vertexlist[j];
18464  tstart = idx2verlist[end1 - in->firstnumber];
18465  if (pointtype(tstart) == DUPLICATEDVERTEX) {
18466  // Reset the index of vertex-j.
18467  tend = point2ppt(tstart);
18468  end2 = pointmark(tend);
18469  p->vertexlist[j] = end2;
18470  }
18471  }
18472  }
18473  }
18474 
18475  // Loop polygons of F, get the set V of vertices and S of segments.
18476  for (i = 0; i < f->numberofpolygons; i++) {
18477  // Get a polygon.
18478  p = &(f->polygonlist[i]);
18479  // Get the first vertex.
18480  end1 = p->vertexlist[0];
18481  if ((end1 < in->firstnumber) ||
18482  (end1 >= in->firstnumber + in->numberofpoints)) {
18483  if (!b->quiet) {
18484  printf("Warning: Invalid the 1st vertex %d of polygon", end1);
18485  printf(" %d in facet %d.\n", i + 1, shmark);
18486  }
18487  continue; // Skip this polygon.
18488  }
18489  tstart = idx2verlist[end1 - in->firstnumber];
18490  // Add tstart to V if it haven't been added yet.
18491  if (worklist[end1] == 0) {
18492  ptlist->append(&tstart);
18493  worklist[end1] = 1;
18494  }
18495  // Loop other vertices of this polygon.
18496  for (j = 1; j <= p->numberofvertices; j++) {
18497  // get a vertex.
18498  if (j < p->numberofvertices) {
18499  end2 = p->vertexlist[j];
18500  } else {
18501  end2 = p->vertexlist[0]; // Form a loop from last to first.
18502  }
18503  if ((end2 < in->firstnumber) ||
18504  (end2 >= in->firstnumber + in->numberofpoints)) {
18505  if (!b->quiet) {
18506  printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
18507  printf(" in facet %d.\n", shmark);
18508  }
18509  } else {
18510  if (end1 != end2) {
18511  // 'end1' and 'end2' form a segment.
18512  tend = idx2verlist[end2 - in->firstnumber];
18513  // Add tstart to V if it haven't been added yet.
18514  if (worklist[end2] == 0) {
18515  ptlist->append(&tend);
18516  worklist[end2] = 1;
18517  }
18518  // Save the segment in S (conlist).
18519  cons = (point *) conlist->append(NULL);
18520  cons[0] = tstart;
18521  cons[1] = tend;
18522  // Set the start for next continuous segment.
18523  end1 = end2;
18524  tstart = tend;
18525  } else {
18526  // Two identical vertices represent an isolated vertex of F.
18527  if (p->numberofvertices > 2) {
18528  // This may be an error in the input, anyway, we can continue
18529  // by simply skipping this segment.
18530  if (!b->quiet) {
18531  printf("Warning: Polygon %d has two identical verts", i + 1);
18532  printf(" in facet %d.\n", shmark);
18533  }
18534  }
18535  // Ignore this vertex.
18536  }
18537  }
18538  // Is the polygon degenerate (a segment or a vertex)?
18539  if (p->numberofvertices == 2) break;
18540  }
18541  }
18542  // Unmark vertices.
18543  for (i = 0; i < ptlist->len(); i++) {
18544  tstart = * (point *)(* ptlist)[i];
18545  end1 = pointmark(tstart);
18546  assert(worklist[end1] == 1);
18547  worklist[end1] = 0;
18548  }
18549 
18550  // Create a CDT of F.
18551  triangulate(shmark, b->epsilon * 1e+2, ptlist, conlist, f->numberofholes,
18552  f->holelist, viri, flipqueue);
18553  // Clear working lists.
18554  ptlist->clear();
18555  conlist->clear();
18556  viri->restart();
18557  }
18558 
18559  // Unify segments in 'subsegs', remove redundant segments. Face links
18560  // of segments are also built.
18561  unifysegments();
18562  // Remember the number of input segments (for output).
18563  insegments = subsegs->items;
18564 
18565  if (checkpbcs) {
18566  // Create the global array 'segpbcgrouptable'.
18567  createsegpbcgrouptable();
18568  }
18569 
18570  if (b->object == tetgenbehavior::STL) {
18571  // Remove redundant vertices (for .stl input mesh).
18572  jettisonnodes();
18573  }
18574 
18575  if (!b->nomerge && !b->nobisect && !checkpbcs) {
18576  // No '-M' switch - merge adjacent facets if they are coplanar.
18577  mergefacets(flipqueue);
18578  }
18579 
18580  delete [] idx2verlist;
18581  delete [] worklist;
18582  delete ptlist;
18583  delete conlist;
18584  delete flipqueue;
18585  delete viri;
18586 
18587  return subsegs->items;
18588 }
18589 
18590 //
18591 // End of surface triangulation routines
18592 //
18593 
18595 // //
18596 // interecursive() Recursively do intersection test on a set of triangles.//
18597 // //
18598 // Recursively split the set 'subfacearray' of subfaces into two sets using //
18599 // a cut plane parallel to x-, or, y-, or z-axies. The split criteria are //
18600 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
18601 // H, and H- denotes the right halfspace of H; and s be a subface: //
18602 // //
18603 // (1) If all points of s lie at H+, put it into left array; //
18604 // (2) If all points of s lie at H-, put it into right array; //
18605 // (3) If some points of s lie at H+ and some of lie at H-, or some //
18606 // points lie on H, put it into both arraies. //
18607 // //
18608 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
18609 // if axis == '2'. If current cut plane is parallel to the x-axis, the next //
18610 // one will be parallel to y-axis, and the next one after the next is z-axis,//
18611 // and then alternately return back to x-axis. //
18612 // //
18613 // Stop splitting when the number of triangles of the input array is not //
18614 // decreased anymore. Do tests on the current set. //
18615 // //
18617 
18618 void tetgenmesh::
18619 interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin,
18620  REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax,
18621  int* internum)
18622 {
18623  shellface **leftarray, **rightarray;
18624  face sface1, sface2;
18625  point p1, p2, p3;
18626  point p4, p5, p6;
18627  enum interresult intersect;
18628  REAL split;
18629  bool toleft, toright;
18630  int leftsize, rightsize;
18631  int i, j;
18632 
18633  if (b->verbose > 1) {
18634  printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
18635  arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
18636  axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
18637  }
18638 
18639  leftarray = new shellface*[arraysize];
18640  if (leftarray == NULL) {
18641  printf("Error in interecursive(): Insufficient memory.\n");
18642  terminatetetgen(1);
18643  }
18644  rightarray = new shellface*[arraysize];
18645  if (rightarray == NULL) {
18646  printf("Error in interecursive(): Insufficient memory.\n");
18647  terminatetetgen(1);
18648  }
18649  leftsize = rightsize = 0;
18650 
18651  if (axis == 0) {
18652  // Split along x-axis.
18653  split = 0.5 * (bxmin + bxmax);
18654  } else if (axis == 1) {
18655  // Split along y-axis.
18656  split = 0.5 * (bymin + bymax);
18657  } else {
18658  // Split along z-axis.
18659  split = 0.5 * (bzmin + bzmax);
18660  }
18661 
18662  for (i = 0; i < arraysize; i++) {
18663  sface1.sh = subfacearray[i];
18664  p1 = (point) sface1.sh[3];
18665  p2 = (point) sface1.sh[4];
18666  p3 = (point) sface1.sh[5];
18667  toleft = toright = false;
18668  if (p1[axis] < split) {
18669  toleft = true;
18670  if (p2[axis] >= split || p3[axis] >= split) {
18671  toright = true;
18672  }
18673  } else if (p1[axis] > split) {
18674  toright = true;
18675  if (p2[axis] <= split || p3[axis] <= split) {
18676  toleft = true;
18677  }
18678  } else {
18679  // p1[axis] == split;
18680  toleft = true;
18681  toright = true;
18682  }
18683  // At least one is true;
18684 #ifdef SELF_CHECK
18685  assert(!(toleft == false && toright == false));
18686 #endif
18687  if (toleft) {
18688  leftarray[leftsize] = sface1.sh;
18689  leftsize++;
18690  }
18691  if (toright) {
18692  rightarray[rightsize] = sface1.sh;
18693  rightsize++;
18694  }
18695  }
18696 
18697  if (leftsize < arraysize && rightsize < arraysize) {
18698  // Continue to partition the input set. Now 'subfacearray' has been
18699  // split into two sets, it's memory can be freed. 'leftarray' and
18700  // 'rightarray' will be freed in the next recursive (after they're
18701  // partitioned again or performing tests).
18702  delete [] subfacearray;
18703  // Continue to split these two sets.
18704  if (axis == 0) {
18705  interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
18706  bzmin, bzmax, internum);
18707  interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
18708  bzmin, bzmax, internum);
18709  } else if (axis == 1) {
18710  interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
18711  bzmin, bzmax, internum);
18712  interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
18713  bzmin, bzmax, internum);
18714  } else {
18715  interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
18716  bzmin, split, internum);
18717  interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
18718  split, bzmax, internum);
18719  }
18720  } else {
18721  if (b->verbose > 1) {
18722  printf(" Checking intersecting faces.\n");
18723  }
18724  // Perform a brute-force compare on the set.
18725  for (i = 0; i < arraysize; i++) {
18726  sface1.sh = subfacearray[i];
18727  p1 = (point) sface1.sh[3];
18728  p2 = (point) sface1.sh[4];
18729  p3 = (point) sface1.sh[5];
18730  for (j = i + 1; j < arraysize; j++) {
18731  sface2.sh = subfacearray[j];
18732  p4 = (point) sface2.sh[3];
18733  p5 = (point) sface2.sh[4];
18734  p6 = (point) sface2.sh[5];
18735  intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6);
18736  if (intersect == INTERSECT || intersect == SHAREFACE) {
18737  if (!b->quiet) {
18738  if (intersect == INTERSECT) {
18739  printf(" Facet #%d intersects facet #%d at triangles:\n",
18740  shellmark(sface1), shellmark(sface2));
18741  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
18742  pointmark(p1), pointmark(p2), pointmark(p3),
18743  pointmark(p4), pointmark(p5), pointmark(p6));
18744  } else {
18745  printf(" Facet #%d duplicates facet #%d at triangle:\n",
18746  shellmark(sface1), shellmark(sface2));
18747  printf(" (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2),
18748  pointmark(p3));
18749  }
18750  }
18751  // Increase the number of intersecting pairs.
18752  (*internum)++;
18753  // Infect these two faces (although they may already be infected).
18754  sinfect(sface1);
18755  sinfect(sface2);
18756  }
18757  }
18758  }
18759  // Don't forget to free all three arrays. No further partition.
18760  delete [] leftarray;
18761  delete [] rightarray;
18762  delete [] subfacearray;
18763  }
18764 }
18765 
18767 // //
18768 // detectinterfaces() Detect intersecting triangles. //
18769 // //
18770 // Given a set of triangles, find the pairs of intersecting triangles from //
18771 // them. Here the set of triangles is in 'subfaces' which is a surface mesh //
18772 // of a PLC (.poly or .smesh). //
18773 // //
18774 // To detect whether two triangles are intersecting is done by the routine //
18775 // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
18776 // It is based on geometric orientation test which uses exact arithmetics. //
18777 // //
18778 // Use divide-and-conquer algorithm for reducing the number of intersection //
18779 // tests. Start from the bounding box of the input point set, recursively //
18780 // partition the box into smaller boxes, until the number of triangles in a //
18781 // box is not decreased anymore. Then perform triangle-triangle tests on the //
18782 // remaining set of triangles. The memory allocated in the input set is //
18783 // freed immediately after it has been partitioned into two arrays. So it //
18784 // can be re-used for the consequent partitions. //
18785 // //
18786 // On return, the pool 'subfaces' will be cleared, and only the intersecting //
18787 // triangles remain for output (to a .face file). //
18788 // //
18790 
18791 void tetgenmesh::detectinterfaces()
18792 {
18793  shellface **subfacearray;
18794  face shloop;
18795  int internum;
18796  int i;
18797 
18798  if (!b->quiet) {
18799  printf("Detecting intersecting facets.\n");
18800  }
18801 
18802  // Construct a map from indices to subfaces;
18803  subfacearray = new shellface*[subfaces->items];
18804  subfaces->traversalinit();
18805  shloop.sh = shellfacetraverse(subfaces);
18806  i = 0;
18807  while (shloop.sh != (shellface *) NULL) {
18808  subfacearray[i] = shloop.sh;
18809  shloop.sh = shellfacetraverse(subfaces);
18810  i++;
18811  }
18812 
18813  internum = 0;
18814  // Recursively split the set of triangles into two sets using a cut plane
18815  // parallel to x-, or, y-, or z-axies. Stop splitting when the number
18816  // of subfaces is not decreasing anymore. Do tests on the current set.
18817  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
18818  zmin, zmax, &internum);
18819 
18820  if (!b->quiet) {
18821  if (internum > 0) {
18822  printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
18823  } else {
18824  printf("\nNo faces are intersecting.\n\n");
18825  }
18826  }
18827 
18828  if (internum > 0) {
18829  // Traverse all subfaces, deallocate those have not been infected (they
18830  // are not intersecting faces). Uninfect those have been infected.
18831  // After this loop, only intersecting faces remain.
18832  subfaces->traversalinit();
18833  shloop.sh = shellfacetraverse(subfaces);
18834  while (shloop.sh != (shellface *) NULL) {
18835  if (sinfected(shloop)) {
18836  suninfect(shloop);
18837  } else {
18838  shellfacedealloc(subfaces, shloop.sh);
18839  }
18840  shloop.sh = shellfacetraverse(subfaces);
18841  }
18842  } else {
18843  // Deallocate all subfaces.
18844  subfaces->restart();
18845  }
18846 }
18847 
18848 //
18849 // Begin of periodic boundary condition routines
18850 //
18851 
18853 // //
18854 // createsubpbcgrouptable() Create the 'subpbcgrouptable'. //
18855 // //
18856 // Allocate the memory for 'subpbcgrouptable'. Each entry i (a pbcdata) of //
18857 // the table represents a pbcgroup. Most of the fields of a group-i are set //
18858 // in this routine. 'fmark[0]', 'fmark[1]', and 'transmat[0]' are directly //
18859 // copied from the corresponding data of 'in->numberofpbcgroups'. 'transmat //
18860 // [1]' is calculated as the inverse matrix of 'transmat[0]'. 'ss[0]' and //
18861 // 'ss[1]' are initilized be 'dummysh'. They are set in 'trangulatefacet()' //
18862 // (when -p is in use) or 'reconstructmesh()' (when -r is in use). //
18863 // //
18865 
18866 void tetgenmesh::createsubpbcgrouptable()
18867 {
18868  tetgenio::pbcgroup *pg;
18869  pbcdata *pd;
18870  REAL A[4][4], rhs[4], D;
18871  int indx[4];
18872  int i, j, k;
18873 
18874  subpbcgrouptable = new pbcdata[in->numberofpbcgroups];
18875  for (i = 0; i < in->numberofpbcgroups; i++) {
18876  pg = &(in->pbcgrouplist[i]);
18877  pd = &(subpbcgrouptable[i]);
18878  // Copy data from pg to pd.
18879  pd->fmark[0] = pg->fmark1;
18880  pd->fmark[1] = pg->fmark2;
18881  // Initialize array 'pd->ss'.
18882  pd->ss[0].sh = dummysh;
18883  pd->ss[1].sh = dummysh;
18884  // Copy the transform matrix from pg to pd->transmat[0].
18885  for (j = 0; j < 4; j++) {
18886  for (k = 0; k < 4; k++) {
18887  pd->transmat[0][j][k] = pg->transmat[j][k];
18888  // Prepare for inverting the matrix.
18889  A[j][k] = pg->transmat[j][k];
18890  }
18891  }
18892  // Calculate the inverse matrix (pd->transmat[1]) of pd->transmat[0].
18893  lu_decmp(A, 4, indx, &D, 0);
18894  for (j = 0; j < 4; j++) {
18895  for (k = 0; k < 4; k++) rhs[k] = 0.0;
18896  rhs[j] = 1.0;
18897  lu_solve(A, 4, indx, rhs, 0);
18898  for (k = 0; k < 4; k++) pd->transmat[1][k][j] = rhs[k];
18899  }
18900  }
18901 }
18902 
18904 // //
18905 // getsubpbcgroup() Get the pbcgroup of a subface. //
18906 // //
18907 // 'pbcsub' has pbc defined. Its pbcgroup is returned in 'pd'. In addition, //
18908 // 'f1' (0 or 1) indicates the position of 'pbcsub' in 'pd'; 'f2' (= 1 - f1) //
18909 // is the position where the symmetric subface of 'pbcsub' is found. //
18910 // //
18912 
18913 void tetgenmesh::getsubpbcgroup(face* pbcsub, pbcdata** pd, int *f1, int *f2)
18914 {
18915  int groupid, fmark, idx;
18916 
18917  groupid = shellpbcgroup(*pbcsub);
18918  *pd = &subpbcgrouptable[groupid];
18919 
18920  // Get the facet index (1 - based).
18921  idx = shellmark(*pbcsub);
18922  // Get the facet marker from array (0 - based).
18923  fmark = in->facetmarkerlist[idx - 1];
18924  if ((*pd)->fmark[0] == fmark) {
18925  *f1 = 0;
18926  } else {
18927 #ifdef SELF_CHECK
18928  assert((*pd)->fmark[1] == fmark);
18929 #endif
18930  *f1 = 1;
18931  }
18932  *f2 = 1 - (*f1);
18933 }
18934 
18936 // //
18937 // getsubpbcsympoint() Compute the symmetric point for a subface point. //
18938 // //
18939 // 'newpoint' lies on 'splitsub'. This routine calculates a 'sympoint' which //
18940 // locates on 'symsplitsub' and symmtric to 'newpoint'. Return the location //
18941 // of sympoint wrt. symsplitsub. //
18942 // //
18944 
18945 enum tetgenmesh::locateresult tetgenmesh:: getsubpbcsympoint(point newpoint,
18946  face* splitsub, point sympoint, face* symsplitsub)
18947 {
18948  pbcdata *pd;
18949  face subloop;
18950  point pa, pb, pc;
18951  enum locateresult symloc;
18952  REAL ori;
18953  int f1, f2, i;
18954 
18955  // Get the pbcgroup of 'splitsub'.
18956  getsubpbcgroup(splitsub, &pd, &f1, &f2);
18957 
18958  // Transform newpoint from f1 -> f2.
18959  for (i = 0; i < 3; i++) {
18960  sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
18961  + pd->transmat[f1][i][1] * newpoint[1]
18962  + pd->transmat[f1][i][2] * newpoint[2]
18963  + pd->transmat[f1][i][3] * 1.0;
18964  }
18965  // Locate sympoint in f2.
18966  symloc = OUTSIDE;
18967  *symsplitsub = pd->ss[f2];
18968  // Is the stored subface valid? Hole removal may delete the subface.
18969  if ((symsplitsub->sh != dummysh) && !isdead(symsplitsub)) {
18970  // 'symsplitsub' should lie on the symmetric facet. Check it.
18971  i = shellmark(*symsplitsub);
18972  if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
18973  // 'symsplitsub' has the symmetric boundary marker.
18974  pa = sorg(*symsplitsub);
18975  pb = sdest(*symsplitsub);
18976  pc = sapex(*symsplitsub);
18977  // Test if they are (nearly) coplanar. Some facets may have the
18978  // same boundary marker but not coplanar with this point.
18979  ori = orient3d(pa, pb, pc, sympoint);
18980  if (iscoplanar(pa, pb, pc, sympoint, ori, b->epsilon * 1e+2)) {
18981  // Locate sympoint in facet. Don't stop at subsegment.
18982  abovepoint = facetabovepointarray[shellmark(*symsplitsub)];
18983  if (abovepoint == (point) NULL) {
18984  getfacetabovepoint(symsplitsub);
18985  }
18986  symloc = locatesub(sympoint, symsplitsub, 0, b->epsilon * 1e+2);
18987  }
18988  }
18989  }
18990  if (symloc == OUTSIDE) {
18991  // Do a brute-force searching for the symmetric subface.
18992  REAL epspp = b->epsilon * 1e+2;
18993  int lcount = 0;
18994  do {
18995  // Locate sympoint in the pool of subfaces (with fmark pd->fmark[f2]).
18996  subfaces->traversalinit();
18997  subloop.sh = shellfacetraverse(subfaces);
18998  while (subloop.sh != (shellface *) NULL) {
18999  i = shellmark(subloop);
19000  if (in->facetmarkerlist[i - 1] == pd->fmark[f2]) {
19001  // Found a facet have the symmetric boundary marker.
19002  pa = sorg(subloop);
19003  pb = sdest(subloop);
19004  pc = sapex(subloop);
19005  // Test if they are (nearly) coplanar. Some facets may have the
19006  // same boundary marker but not coplanar with this point.
19007  ori = orient3d(pa, pb, pc, sympoint);
19008  if (iscoplanar(pa, pb, pc, sympoint, ori, epspp)) {
19009  // Test if sympoint is (nearly) inside this facet.
19010  // Get the abovepoint of the facet.
19011  abovepoint = facetabovepointarray[shellmark(subloop)];
19012  // Do we need to calculate the abovepoint?
19013  if (abovepoint == (point) NULL) {
19014  getfacetabovepoint(&subloop);
19015  }
19016  // subloop is on the facet, search sympoint.
19017  symloc = locatesub(sympoint, &subloop, 0, epspp);
19018  if (symloc != OUTSIDE) break;
19019  }
19020  }
19021  subloop.sh = shellfacetraverse(subfaces);
19022  }
19023  lcount++;
19024  epspp *= 10.0;
19025  } while ((symloc == OUTSIDE) && (lcount < 3));
19026 #ifdef SELF_CHECK
19027  // sympoint should be inside the facet.
19028  assert(symloc != OUTSIDE);
19029 #endif
19030  // Set the returning subface.
19031  *symsplitsub = subloop;
19032  // Update the stored subface for next searching.
19033  pd->ss[f2] = *symsplitsub;
19034  }
19035 
19036  return adjustlocatesub(sympoint, symsplitsub, symloc, b->epsilon);
19037 }
19038 
19040 // //
19041 // createsegpbcgrouptable() Create the 'segpbcgrouptable'. //
19042 // //
19043 // Each segment may belong to more than one pbcgroups. For example, segment //
19044 // ab may need to be symmteric to both segments cd, and ef, then ab and cd, //
19045 // cd and ef, ef and ab form three pbcgroups. //
19046 // //
19047 // 'segpbcgrouptable' is implemented as a list of pbcdatas. Each item i is //
19048 // a pbcgroup. //
19049 // //
19051 
19052 void tetgenmesh::createsegpbcgrouptable()
19053 {
19054  shellface** segsperverlist;
19055  pbcdata *pd, *ppd, pd1, pd2;
19056  face segloop, symseg;
19057  face startsh, spinsh, symsh;
19058  point pa, pb, syma, symb;
19059  enum locateresult symloc;
19060  REAL testpt[3], sympt[3];
19061  bool inflag;
19062  int *idx2seglist;
19063  int segid1, segid2;
19064  int f1, f2;
19065  int i, j, k, l;
19066 
19067  // Allocate memory for 'subpbcgrouptable'.
19068  segpbcgrouptable = new list(sizeof(pbcdata), NULL, 256);
19069 
19070  if (b->refine) {
19071  // Create a point-to-seg map for quickly finding PBC seg pairs.
19072  makesegmentmap(idx2seglist, segsperverlist);
19073  }
19074 
19075  // Loop through the segment list.
19076  subsegs->traversalinit();
19077  segloop.sh = shellfacetraverse(subsegs);
19078  while (segloop.sh != (shellface *) NULL) {
19079  // Loop the subface ring of segloop ab.
19080  pa = sorg(segloop);
19081  pb = sdest(segloop);
19082  segid1 = shellmark(segloop);
19083  spivot(segloop, startsh);
19084  spinsh = startsh;
19085  do {
19086  // Adjust spinsh be edge ab.
19087  if (sorg(spinsh) != pa) {
19088  sesymself(spinsh);
19089  }
19090  // Does spinsh belong to a pbcgroup?
19091  if (shellpbcgroup(spinsh) != -1) {
19092  // Yes! There exists a segment cd. ab and cd form a pbcgroup.
19093  if (b->refine) {
19094  getsubpbcgroup(&spinsh, &pd, &f1, &f2);
19095  // Transform pa from f1 -> f2.
19096  for (i = 0; i < 3; i++) {
19097  sympt[i] = pd->transmat[f1][i][0] * pa[0]
19098  + pd->transmat[f1][i][1] * pa[1]
19099  + pd->transmat[f1][i][2] * pa[2]
19100  + pd->transmat[f1][i][3] * 1.0;
19101  }
19102  syma = point2pbcpt(pa);
19103  // Is 'sympt == syma'?
19104  if (distance(sympt, syma) > (longest * b->epsilon)) {
19105  // No. Search the symmetric vertex of pa.
19106  symloc = getsubpbcsympoint(pa, &spinsh, sympt, &symsh);
19107  syma = sorg(symsh);
19108  if (symloc != ONVERTEX) {
19109  // Do a brute force search. Not done yet.
19110  assert(0);
19111  }
19112  }
19113  // Transform pb from f1 -> f2.
19114  for (i = 0; i < 3; i++) {
19115  sympt[i] = pd->transmat[f1][i][0] * pb[0]
19116  + pd->transmat[f1][i][1] * pb[1]
19117  + pd->transmat[f1][i][2] * pb[2]
19118  + pd->transmat[f1][i][3] * 1.0;
19119  }
19120  // Search sym subface from the point-to-subface map.
19121  symseg.shver = 0;
19122  j = pointmark(syma) - in->firstnumber;
19123  for (i = idx2seglist[j]; i < idx2seglist[j + 1]; i++) {
19124  symseg.sh = segsperverlist[i];
19125  if (sorg(symseg) == syma) symb = sdest(symseg);
19126  else symb = sorg(symseg);
19127  if (distance(sympt, symb) <= (longest * b->epsilon)) break;
19128  }
19129  assert(i < idx2seglist[j + 1]);
19130  } else {
19131  // 'testpt' is the midpoint of ab used to find cd.
19132  for (i = 0; i < 3; i++) testpt[i] = 0.5 * (pa[i] + pb[i]);
19133  symloc = getsubpbcsympoint(testpt, &spinsh, sympt, &symsh);
19134 #ifdef SELF_CHECK
19135  assert(symloc == ONEDGE);
19136 #endif
19137  sspivot(symsh, symseg);
19138  }
19139 #ifdef SELF_CHECK
19140  assert(symseg.sh != dummysh);
19141 #endif
19142  // Check whether this group has already been created in list.
19143  segid2 = shellmark(symseg);
19144  inflag = false;
19145  for (i = 0; i < segpbcgrouptable->len() && !inflag; i++) {
19146  pd = (pbcdata *)(* segpbcgrouptable)[i];
19147  if (pd->segid[0] == segid1) {
19148  if (pd->segid[1] == segid2) inflag = true;
19149  } else if (pd->segid[0] == segid2) {
19150  if (pd->segid[1] == segid1) inflag = true;
19151  }
19152  }
19153  if (!inflag) {
19154  // Create a segment pbcgroup in list for ab and cd.
19155  pd = (pbcdata *) segpbcgrouptable->append(NULL);
19156  // Save the markers of ab and cd.
19157  pd->segid[0] = segid1;
19158  pd->segid[1] = segid2;
19159  // Save the handles of ab and cd.
19160  pd->ss[0] = segloop;
19161  pd->ss[1] = symseg;
19162  // Find the map from ab to cd.
19163  getsubpbcgroup(&spinsh, &ppd, &f1, &f2);
19164  pd->fmark[0] = ppd->fmark[f1];
19165  pd->fmark[1] = ppd->fmark[f2];
19166  // Set the map from ab to cd.
19167  for (i = 0; i < 4; i++) {
19168  for (j = 0; j < 4; j++) {
19169  pd->transmat[0][i][j] = ppd->transmat[f1][i][j];
19170  }
19171  }
19172  // Set the map from cd to ab.
19173  for (i = 0; i < 4; i++) {
19174  for (j = 0; j < 4; j++) {
19175  pd->transmat[1][i][j] = ppd->transmat[f2][i][j];
19176  }
19177  }
19178  }
19179  }
19180  // Go to the next subface in the ring of ab.
19181  spivotself(spinsh);
19182  } while (spinsh.sh != startsh.sh);
19183  segloop.sh = shellfacetraverse(subsegs);
19184  }
19185 
19186  if (b->refine) {
19187  delete [] segsperverlist;
19188  delete [] idx2seglist;
19189  }
19190 
19191  // Create the indirect segment pbcgroups.
19192  // Bug-fixed (08 Sept. 2006). The total size of 'segpbcgrouptable' may get
19193  // increased. Do not use pointers for 'pd1' and 'pd2'. The addresses may
19194  // be invaild after realloc().
19195  for (i = 0; i < segpbcgrouptable->len(); i++) {
19196  pd1 = * (pbcdata *)(* segpbcgrouptable)[i];
19197  for (f1 = 0; f1 < 2; f1++) {
19198  // Search for a group (except i) contains pd1.segid[f1].
19199  for (j = 0; j < segpbcgrouptable->len(); j++) {
19200  if (j == i) continue;
19201  pd2 = * (pbcdata *)(* segpbcgrouptable)[j];
19202  f2 = -1;
19203  if (pd1.segid[f1] == pd2.segid[0]) {
19204  f2 = 0;
19205  } else if (pd1.segid[f1] == pd2.segid[1]) {
19206  f2 = 1;
19207  }
19208  if (f2 != -1) {
19209 #ifdef SELF_CHECK
19210  assert(pd1.segid[f1] == pd2.segid[f2]);
19211 #endif
19212  segid1 = pd1.segid[1 - f1];
19213  segid2 = pd2.segid[1 - f2];
19214  // Search for the existence of segment pbcgroup (segid1, segid2).
19215  inflag = false;
19216  for (k = 0; k < segpbcgrouptable->len() && !inflag; k++) {
19217  pd = (pbcdata *)(* segpbcgrouptable)[k];
19218  if (pd->segid[0] == segid1) {
19219  if (pd->segid[1] == segid2) inflag = true;
19220  } else if (pd->segid[0] == segid2) {
19221  if (pd->segid[1] == segid1) inflag = true;
19222  }
19223  }
19224  if (!inflag) {
19225  pd = (pbcdata *) segpbcgrouptable->append(NULL);
19226  pd->segid[0] = pd1.segid[1 - f1];
19227  pd->segid[1] = pd2.segid[1 - f2];
19228  pd->ss[0] = pd1.ss[1 - f1];
19229  pd->ss[1] = pd2.ss[1 - f2];
19230  // Invalid the fmark[0] == fmark[1].
19231  pd->fmark[0] = pd->fmark[1] = 0;
19232  // Translate matrix pd->transmat[0] = m2 * m1, where m1 =
19233  // pd1.transmat[1 - f1], m2 = pd2.transmat[f2].
19234  for (k = 0; k < 4; k++) {
19235  for (l = 0; l < 4; l++) {
19236  pd->transmat[0][k][l] = pd2.transmat[f2][k][l];
19237  }
19238  }
19239  m4xm4(pd->transmat[0], pd1.transmat[1 - f1]);
19240  // Translate matrix pd->transmat[1] = m4 * m3, where m3 =
19241  // pd2.transmat[1 - f2], m4 = pd1.transmat[f1].
19242  for (k = 0; k < 4; k++) {
19243  for (l = 0; l < 4; l++) {
19244  pd->transmat[1][k][l] = pd1.transmat[f1][k][l];
19245  }
19246  }
19247  m4xm4(pd->transmat[1], pd2.transmat[1 - f2]);
19248  }
19249  }
19250  }
19251  }
19252  }
19253 
19254  // Form a map from segment index to pbcgroup list of this segment.
19255  idx2segpglist = new int[subsegs->items + 1];
19256  for (i = 0; i < subsegs->items + 1; i++) idx2segpglist[i] = 0;
19257  // Loop through 'segpbcgrouptable', counter the number of pbcgroups of
19258  // each segment.
19259  for (i = 0; i < segpbcgrouptable->len(); i++) {
19260  pd = (pbcdata *)(* segpbcgrouptable)[i];
19261  for (j = 0; j < 2; j++) {
19262  k = pd->segid[j] - 1;
19263  idx2segpglist[k]++;
19264  }
19265  }
19266  // Calculate the total length of array 'segpglist'.
19267  j = idx2segpglist[0];
19268  idx2segpglist[0] = 0; // Array starts from 0 element.
19269  for (i = 0; i < subsegs->items; i++) {
19270  k = idx2segpglist[i + 1];
19271  idx2segpglist[i + 1] = idx2segpglist[i] + j;
19272  j = k;
19273  }
19274  // The total length is in the last unit of idx2segpglist.
19275  segpglist = new int[idx2segpglist[i]];
19276  // Loop the set of pbcgroups again, set the data into segpglist.
19277  for (i = 0; i < segpbcgrouptable->len(); i++) {
19278  pd = (pbcdata *)(* segpbcgrouptable)[i];
19279  for (j = 0; j < 2; j++) {
19280  k = pd->segid[j] - 1;
19281  segpglist[idx2segpglist[k]] = i;
19282  idx2segpglist[k]++;
19283  }
19284  }
19285  // Contents in 'idx2segpglist' are shifted, now shift them back.
19286  for (i = subsegs->items - 1; i >= 0; i--) {
19287  idx2segpglist[i + 1] = idx2segpglist[i];
19288  }
19289  idx2segpglist[0] = 0;
19290 }
19291 
19293 // //
19294 // getsegpbcsympoint() Compute the symmetric point for a segment point. //
19295 // //
19296 // 'newpoint' lies on 'splitseg'. This routine calculates a 'sympoint' which //
19297 // locates on 'symsplitseg' and symmtric to 'newpoint'. Return the location //
19298 // of sympoint wrt. symsplitseg. //
19299 // //
19301 
19302 enum tetgenmesh::locateresult tetgenmesh::
19303 getsegpbcsympoint(point newpoint, face* splitseg, point sympoint,
19304  face* symsplitseg, int groupid)
19305 {
19306  pbcdata *pd;
19307  enum locateresult symloc;
19308  int segid, f1, f2, i;
19309 
19310  pd = (pbcdata *)(* segpbcgrouptable)[groupid];
19311  segid = shellmark(*splitseg);
19312  if (pd->segid[0] == segid) {
19313  f1 = 0;
19314  } else {
19315 #ifdef SELF_CHECK
19316  assert(pd->segid[1] == segid);
19317 #endif
19318  f1 = 1;
19319  }
19320  f2 = 1 - f1;
19321 
19322  // Transform newpoint from f1 -> f2.
19323  for (i = 0; i < 3; i++) {
19324  sympoint[i] = pd->transmat[f1][i][0] * newpoint[0]
19325  + pd->transmat[f1][i][1] * newpoint[1]
19326  + pd->transmat[f1][i][2] * newpoint[2]
19327  + pd->transmat[f1][i][3] * 1.0;
19328  }
19329  // Locate sympoint in f2.
19330  *symsplitseg = pd->ss[f2];
19331 #ifdef SELF_CHECK
19332  assert(symsplitseg->sh != dummysh);
19333 #endif
19334  // Locate sympoint in facet. Stop at subsegment.
19335  symloc = locateseg(sympoint, symsplitseg);
19336  symloc = adjustlocateseg(sympoint, symsplitseg, symloc, b->epsilon * 1e+2);
19337  return symloc;
19338 }
19339 
19340 //
19341 // End of periodic boundary condition routines
19342 //
19343 
19344 //
19345 // Begin of vertex perturbation routines
19346 //
19347 
19349 // //
19350 // randgenerator() Generate a random REAL number between (0, |range|). //
19351 // //
19353 
19354 REAL tetgenmesh::randgenerator(REAL range)
19355 {
19356  REAL worknumber, result;
19357  int expo;
19358 
19359  if (range == 0.0) return 0.0;
19360 
19361  expo = 0;
19362  worknumber = fabs(range);
19363  // Normalize worknumber (i.e., 1.xxxExx)
19364  if (worknumber > 10.0) {
19365  while (worknumber > 10.0) {
19366  worknumber /= 10.0;
19367  expo++;
19368  }
19369  } else if (worknumber < 1.0) {
19370  while (worknumber < 1.0) {
19371  worknumber *= 10.0;
19372  expo--;
19373  }
19374  }
19375 #ifdef SELF_CHECK
19376  assert(worknumber >= 1.0 && worknumber <= 10.0);
19377 #endif
19378 
19379  // Enlarge worknumber 1000 times.
19380  worknumber *= 1e+3;
19381  expo -= 3;
19382  // Generate a randome number between (0, worknumber).
19383  result = (double) randomnation((int) worknumber);
19384 
19385  // Scale result back into the original size.
19386  if (expo > 0) {
19387  while (expo != 0) {
19388  result *= 10.0;
19389  expo--;
19390  }
19391  } else if (expo < 0) {
19392  while (expo != 0) {
19393  result /= 10.0;
19394  expo++;
19395  }
19396  }
19397 #ifdef SELF_CHECK
19398  assert((result >= 0.0) && (result <= fabs(range)));
19399 #endif
19400 
19401  return result;
19402 }
19403 
19405 // //
19406 // checksub4cocir() Test a subface to find co-circular pair of subfaces. //
19407 // //
19408 // 'eps' is a relative tolerance for testing approximately cospherical case. //
19409 // Set it to zero if only exact test is desired. //
19410 // //
19411 // An edge(not a segment) of 'testsub' is locally degenerate if the opposite //
19412 // vertex of the adjacent subface is cocircular with the vertices of testsub.//
19413 // If 'once' is TRUE, operate on the edge only if the pointer 'testsub->sh' //
19414 // is smaller than its neighbor (for each edge is considered only once). //
19415 // //
19416 // Return TRUE if find an edge of testsub is locally degenerate. //
19417 // //
19419 
19420 bool tetgenmesh::checksub4cocir(face* testsub, REAL eps, bool once,
19421  bool enqflag)
19422 {
19423  badface *cocirsub;
19424  face subloop, neighsub;
19425  face checkseg;
19426  point pa, pb, pc, pd;
19427  REAL sign;
19428  int i;
19429 
19430  subloop = *testsub;
19431  subloop.shver = 0; // Keep the CCW orientation.
19432  // Get the abovepoint of the facet.
19433  abovepoint = facetabovepointarray[shellmark(subloop)];
19434  // Do we need to calculate the abovepoint?
19435  if (abovepoint == (point) NULL) {
19436  getfacetabovepoint(&subloop);
19437  }
19438  // Check the three edges of subloop.
19439  for (i = 0; i < 3; i++) {
19440  sspivot(subloop, checkseg);
19441  if (checkseg.sh == dummysh) {
19442  // It is not a segment, get the adjacent subface.
19443  spivot(subloop, neighsub);
19444  // assert(neighsub.sh != dummysh);
19445  if (!once || (once && (neighsub.sh > subloop.sh))) {
19446  pa = sorg(subloop);
19447  pb = sdest(subloop);
19448  pc = sapex(subloop);
19449  pd = sapex(neighsub);
19450  sign = insphere(pa, pb, pc, abovepoint, pd);
19451  if ((sign != 0.0) && (eps > 0.0)) {
19452  if (iscospheric(pa, pb, pc, abovepoint, pd, sign, eps)) sign = 0.0;
19453  }
19454  if (sign == 0.0) {
19455  // It's locally degenerate!
19456  if (enqflag && badsubfaces != (memorypool *) NULL) {
19457  // Save it.
19458  cocirsub = (badface *) badsubfaces->alloc();
19459  cocirsub->ss = subloop;
19460  cocirsub->forg = pa;
19461  cocirsub->fdest = pb;
19462  cocirsub->fapex = pc;
19463  cocirsub->foppo = pd;
19464  setshell2badface(cocirsub->ss, cocirsub);
19465  }
19466  if (b->verbose > 1) {
19467  printf(" Found set (%d, %d, %d, %d).\n", pointmark(pa),
19468  pointmark(pb), pointmark(pc), pointmark(pd));
19469  }
19470  return true;
19471  }
19472  }
19473  }
19474  senextself(subloop);
19475  }
19476 
19477  return false;
19478 }
19479 
19481 // //
19482 // tallcocirsubs() Find all co-circular subfaces and save them in list. //
19483 // //
19485 
19486 void tetgenmesh::tallcocirsubs(REAL eps, bool enqflag)
19487 {
19488  face subloop;
19489 
19490  // Loop over all subfaces.
19491  subfaces->traversalinit();
19492  subloop.sh = shellfacetraverse(subfaces);
19493  while (subloop.sh != (shellface *) NULL) {
19494  checksub4cocir(&subloop, eps, true, enqflag);
19495  subloop.sh = shellfacetraverse(subfaces);
19496  }
19497 }
19498 
19500 // //
19501 // tallencsegsfsubs() Check for encroached segs from a list of subfaces. //
19502 // //
19504 
19505 bool tetgenmesh::tallencsegsfsubs(point testpt, list* cavsublist)
19506 {
19507  face startsub, checkseg;
19508  long oldencnum;
19509  int i, j;
19510 
19511  // Remember the current number of encroached segments.
19512  oldencnum = badsubsegs->items;
19513 
19514  // Check segments in the list of subfaces.
19515  for (i = 0; i < cavsublist->len(); i++) {
19516  startsub = * (face *)(* cavsublist)[i];
19517  // Test all three edges of startsub.
19518  for (j = 0; j < 3; j++) {
19519  sspivot(startsub, checkseg);
19520  if (checkseg.sh != dummysh) {
19521  if (!shell2badface(checkseg)) {
19522  checkseg4encroach(&checkseg, testpt, NULL, true);
19523  }
19524  }
19525  senextself(startsub);
19526  }
19527  }
19528 
19529  return (badsubsegs->items > oldencnum);
19530 }
19531 
19533 // //
19534 // collectflipedges() Collect edges of split subfaces for flip checking. //
19535 // //
19536 // 'inspoint' is a newly inserted segment point (inserted by insertsite()). //
19537 // 'splitseg' is one of the two split subsegments. Some subfaces may be non- //
19538 // Delaunay since they're still not bonded to CDT. This routine collect all //
19539 // such possible subfaces in 'flipqueue'. //
19540 // //
19542 
19543 void tetgenmesh::
19544 collectflipedges(point inspoint, face* splitseg, queue* flipqueue)
19545 {
19546  face startsh, spinsh, checksh;
19547  face nextseg;
19548  point pa, pb;
19549 
19550  // Let the dest of splitseg be inspoint.
19551  splitseg->shver = 0;
19552  if (sdest(*splitseg) != inspoint) {
19553  sesymself(*splitseg);
19554  }
19555 #ifdef SELF_CHECK
19556  assert(sdest(*splitseg) == inspoint);
19557 #endif
19558  pa = sorg(*splitseg);
19559  spivot(*splitseg, startsh);
19560  spinsh = startsh;
19561  do {
19562  findedge(&spinsh, pa, inspoint);
19563  senext2(spinsh, checksh);
19564  enqueueflipedge(checksh, flipqueue);
19565  spivotself(spinsh);
19566  } while (spinsh.sh != startsh.sh);
19567 
19568  // Get the next subsegment.
19569  senext(*splitseg, nextseg);
19570  spivotself(nextseg);
19571 #ifdef SELF_CHECK
19572  assert(nextseg.sh != (shellface *) NULL);
19573 #endif
19574 
19575  // Let the org of nextseg be inspoint.
19576  nextseg.shver = 0;
19577  if (sorg(nextseg) != inspoint) {
19578  sesymself(nextseg);
19579  }
19580 #ifdef SELF_CHECK
19581  assert(sorg(nextseg) == inspoint);
19582 #endif
19583  pb = sdest(nextseg);
19584  spivot(nextseg, startsh);
19585  spinsh = startsh;
19586  do {
19587  findedge(&spinsh, inspoint, pb);
19588  senext(spinsh, checksh);
19589  enqueueflipedge(checksh, flipqueue);
19590  spivotself(spinsh);
19591  } while (spinsh.sh != startsh.sh);
19592 }
19593 
19595 // //
19596 // perturbrepairencsegs() Repair all encroached segments. //
19597 // //
19598 // All encroached segments are stored in 'badsubsegs'. Each segment will be //
19599 // split by adding a perturbed point near its circumcenter. //
19600 // //
19602 
19603 void tetgenmesh::perturbrepairencsegs(queue* flipqueue)
19604 {
19605  badface *encloop;
19606  tetrahedron encodedtet;
19607  triface splittet;
19608  face splitsub, symsplitsub;
19609  face splitseg, symsplitseg;
19610  point newpoint, sympoint;
19611  point pa, pb, pc;
19612  enum insertsiteresult success;
19613  enum locateresult loc, symloc;
19614  REAL cent[3], d1, ps, rs;
19615  int i, j;
19616 
19617  // Note that steinerleft == -1 if an unlimited number of Steiner points
19618  // is allowed. Loop until 'badsubsegs' is empty.
19619  badsubsegs->traversalinit();
19620  encloop = badfacetraverse(badsubsegs);
19621  while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
19622  splitseg = encloop->ss;
19623 #ifdef SELF_CHECK
19624  assert(shell2badface(splitseg) == encloop);
19625 #endif
19626  setshell2badface(splitseg, NULL);
19627  pa = sorg(splitseg);
19628  pb = sdest(splitseg);
19629  if ((pa == encloop->forg) && (pb == encloop->fdest)) {
19630  if (b->verbose > 1) {
19631  printf(" Get seg (%d, %d).\n", pointmark(pa), pointmark(pb));
19632  }
19633  // Create the newpoint.
19634  makepoint(&newpoint);
19635  // Get the circumcenter and radius of ab.
19636  for (i = 0; i < 3; i++) cent[i] = 0.5 * (pa[i] + pb[i]);
19637  d1 = 0.5 * distance(pa, pb);
19638  // Add a random perturbation to newpoint along the vector ab.
19639  ps = randgenerator(d1 * 1.0e-3);
19640  rs = ps / d1;
19641  // Set newpoint (be at the perturbed circumcenter of ab).
19642  for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
19643  setpointtype(newpoint, FREESEGVERTEX);
19644  // Set splitseg into the newpoint.
19645  setpoint2sh(newpoint, sencode(splitseg));
19646 
19647  // Is there periodic boundary condition?
19648  if (checkpbcs) {
19649  // Insert points on other segments of incident pbcgroups.
19650  i = shellmark(splitseg) - 1;
19651  for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
19652  makepoint(&sympoint);
19653  symloc = getsegpbcsympoint(newpoint, &splitseg, sympoint,
19654  &symsplitseg, segpglist[j]);
19655 #ifdef SELF_CHECK
19656  assert(symloc != OUTSIDE);
19657 #endif
19658  // Note: the symsplitseg and splitseg may be identical, in case
19659  // when the the splitseg is the axis of the rotational sym.
19660  if ((symloc == ONEDGE) && (symsplitseg.sh != splitseg.sh)) {
19661  setpointtype(sympoint, FREESEGVERTEX);
19662  setpoint2sh(sympoint, sencode(symsplitseg));
19663  // Insert sympoint into DT.
19664  pc = sorg(symsplitseg);
19665  splittet.tet = dummytet;
19666  // Find a good start point to search.
19667  encodedtet = point2tet(pc);
19668  if (encodedtet != (tetrahedron) NULL) {
19669  decode(encodedtet, splittet);
19670  if (isdead(&splittet)) {
19671  splittet.tet = dummytet;
19672  }
19673  }
19674  // Locate sympoint in DT. Do exact location.
19675  success = insertsite(sympoint, &splittet, false, flipqueue);
19676 #ifdef SELF_CHECK
19677  assert(success != DUPLICATEPOINT);
19678 #endif
19679  if (success == OUTSIDEPOINT) {
19680  inserthullsite(sympoint, &splittet, flipqueue);
19681  }
19682  if (steinerleft > 0) steinerleft--;
19683  // Let sympoint remember splittet.
19684  setpoint2tet(sympoint, encode(splittet));
19685  // Do flip in DT.
19686  flip(flipqueue, NULL);
19687  // Insert sympoint into F.
19688  symloc = locateseg(sympoint, &symsplitseg);
19689  if (symloc == ONEDGE) {
19690  symsplitseg.shver = 0;
19691  spivot(symsplitseg, symsplitsub);
19692  // sympoint should on the edge of symsplitsub.
19693  splitsubedge(sympoint, &symsplitsub, flipqueue);
19694  } else {
19695  // insertsite() has done the whole job.
19696 #ifdef SELF_CHECK
19697  assert(symloc == ONVERTEX);
19698  assert(checksubfaces);
19699 #endif
19700  // Some edges may need to be flipped.
19701  collectflipedges(sympoint, &symsplitseg, flipqueue);
19702  }
19703  // Do flip in facet.
19704  flipsub(flipqueue);
19705  } else { // if (symloc == ONVERTEX) {
19706  // The symmtric point already exists. It is possible when two
19707  // pbc group are idebtical. Omit sympoint.
19708  pointdealloc(sympoint);
19709  }
19710  }
19711  }
19712 
19713  // Insert newpoint into DT.
19714  splittet.tet = dummytet;
19715  // Find a good start point to search.
19716  encodedtet = point2tet(pa);
19717  if (encodedtet != (tetrahedron) NULL) {
19718  decode(encodedtet, splittet);
19719  if (isdead(&splittet)) {
19720  splittet.tet = dummytet;
19721  }
19722  }
19723  if (splittet.tet == dummytet) { // Try pb.
19724  encodedtet = point2tet(pb);
19725  if (encodedtet != (tetrahedron) NULL) {
19726  decode(encodedtet, splittet);
19727  if (isdead(&splittet)) {
19728  splittet.tet = dummytet;
19729  }
19730  }
19731  }
19732  // Locate the newpoint in DT. Do exact location.
19733  success = insertsite(newpoint, &splittet, false, flipqueue);
19734 #ifdef SELF_CHECK
19735  assert(success != DUPLICATEPOINT);
19736 #endif
19737  if (success == OUTSIDEPOINT) {
19738  // A convex hull edge is mssing, and the inserting point lies
19739  // (slightly) outside the convex hull due to the significant
19740  // digits lost in the calculation. Enlarge the convex hull.
19741  inserthullsite(newpoint, &splittet, flipqueue);
19742  }
19743  if (steinerleft > 0) steinerleft--;
19744  // Let newpoint remember splittet.
19745  setpoint2tet(newpoint, encode(splittet));
19746  // Do flip in DT.
19747  flip(flipqueue, NULL);
19748  // Insert newpoint into F.
19749  loc = locateseg(newpoint, &splitseg);
19750  if (loc == ONEDGE) {
19751  splitseg.shver = 0;
19752  spivot(splitseg, splitsub);
19753  // newpoint should on the edge of splitsub.
19754  splitsubedge(newpoint, &splitsub, flipqueue);
19755  } else {
19756  // insertsite() has done the whole job.
19757 #ifdef SELF_CHECK
19758  assert(loc == ONVERTEX);
19759  assert(checksubfaces);
19760 #endif
19761  // Some edges may need to be flipped.
19762  collectflipedges(newpoint, &splitseg, flipqueue);
19763  }
19764  // Do flip in facet.
19765  flipsub(flipqueue);
19766  }
19767  // Remove this entry from list.
19768  badfacedealloc(badsubsegs, encloop);
19769  // Get the next encroached segments.
19770  encloop = badfacetraverse(badsubsegs);
19771  }
19772 }
19773 
19775 // //
19776 // perturbrepairencsubs() Repair all encroached subfaces. //
19777 // //
19778 // All encroached subfaces are stored in 'badsubfaces'. Each subface will be //
19779 // split by adding a perturbed point near its circumcenter. However, if the //
19780 // point encroaches some segments, it will not be inserted. Instead, the //
19781 // encroached segments are split. //
19782 // //
19784 
19785 void tetgenmesh::perturbrepairencsubs(list* cavsublist, queue* flipqueue)
19786 {
19787  badface *encloop, *encsubseg;
19788  tetrahedron encodedtet;
19789  triface splittet;
19790  face splitsub, symsplitsub;
19791  face checkseg, symsplitseg;
19792  point newpoint, sympoint;
19793  point pa, pb, pc, pd;
19794  enum insertsiteresult success;
19795  enum locateresult loc, symloc;
19796  REAL cent[3], d1, ps, rs;
19797  bool reject;
19798  int i;
19799 
19800  // Note that steinerleft == -1 if an unlimited number of Steiner points
19801  // is allowed. Loop until the list 'badsubfaces' is empty.
19802  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
19803  badsubfaces->traversalinit();
19804  encloop = badfacetraverse(badsubfaces);
19805  while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
19806  splitsub = encloop->ss;
19807 #ifdef SELF_CHECK
19808  assert(shell2badface(splitsub) == encloop);
19809 #endif
19810  setshell2badface(splitsub, NULL);
19811  pa = sorg(splitsub);
19812  pb = sdest(splitsub);
19813  pc = sapex(splitsub);
19814  // The subface may be not the same one when it was determined to be
19815  // encroached. If its adjacent encroached subface was split, the
19816  // consequent flips may change it into another subface.
19817  if ((pa == encloop->forg) && (pb == encloop->fdest) &&
19818  (pc == encloop->fapex)) {
19819  if (b->verbose > 1) {
19820  printf(" Get subface (%d, %d, %d).\n", pointmark(pa),
19821  pointmark(pb), pointmark(pc));
19822  }
19823  // Create the newpoint.
19824  makepoint(&newpoint);
19825  // Get the circumcenter of abc.
19826  circumsphere(pa, pb, pc, NULL, cent, &d1);
19827 #ifdef SELF_CHECK
19828  assert(d1 > 0.0);
19829 #endif
19830  // Add a random perturbation to newpoint along the vector a->cent.
19831  // This way, the perturbed point still lies in the plane of abc.
19832  ps = randgenerator(d1 * 1.0e-3);
19833  rs = ps / d1;
19834  // Set newpoint (be at the perturbed circumcenter of abc).
19835  for (i = 0; i < 3; i++) newpoint[i] = cent[i] + rs * (cent[i] - pa[i]);
19836  // Get the abovepoint of the facet.
19837  abovepoint = facetabovepointarray[shellmark(splitsub)];
19838  // Do we need to calculate the abovepoint?
19839  if (abovepoint == (point) NULL) {
19840  getfacetabovepoint(&splitsub);
19841  }
19842  loc = locatesub(newpoint, &splitsub, 1, 0.0);
19843 #ifdef SELF_CHECK
19844  assert(loc != ONVERTEX);
19845 #endif
19846  if (loc != OUTSIDE) {
19847  // Add 'splitsub' into 'cavsublist'.
19848  cavsublist->append(&splitsub);
19849  // Collect all subfaces that encroached by newpoint.
19850  collectcavsubs(newpoint, cavsublist);
19851  // Find if there are encroached segments.
19852  reject = tallencsegsfsubs(newpoint, cavsublist);
19853  // Clear cavsublist for the next use.
19854  cavsublist->clear();
19855  } else {
19856  // newpoint lies outside. splitsub contains the boundary segment.
19857  sspivot(splitsub, checkseg);
19858 #ifdef SELF_CHECK
19859  assert(checkseg.sh != dummysh);
19860 #endif
19861  // Add this segment into list for splitting.
19862  if (b->verbose > 2) {
19863  printf(" Queuing boundary segment (%d, %d).\n",
19864  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
19865  }
19866  encsubseg = (badface *) badsubsegs->alloc();
19867  encsubseg->ss = checkseg;
19868  encsubseg->forg = sorg(checkseg);
19869  encsubseg->fdest = sdest(checkseg);
19870  encsubseg->foppo = (point) NULL;
19871  setshell2badface(encsubseg->ss, encsubseg);
19872  // Reject newpoint.
19873  reject = true;
19874  }
19875 
19876  if (!reject) {
19877  // newpoint is going to be inserted.
19878 
19879  // Is there periodic boundary condition?
19880  if (checkpbcs) {
19881  if (shellpbcgroup(splitsub) >= 0) {
19882  // Insert a point on another facet of the pbcgroup.
19883  makepoint(&sympoint);
19884  // Note: 'abovepoint' will be changed.
19885  symloc = getsubpbcsympoint(newpoint, &splitsub, sympoint,
19886  &symsplitsub);
19887 #ifdef SELF_CHECK
19888  assert(symloc != ONVERTEX);
19889 #endif
19890  setpoint2pbcpt(newpoint, sympoint);
19891  setpoint2pbcpt(sympoint, newpoint);
19892  setpointtype(sympoint, FREESUBVERTEX);
19893  // setpoint2sh(sympoint, sencode(symsplitsub));
19894  // Insert sympoint into DT.
19895  pd = sorg(symsplitsub);
19896  splittet.tet = dummytet;
19897  // Find a good start point to search.
19898  encodedtet = point2tet(pd);
19899  if (encodedtet != (tetrahedron) NULL) {
19900  decode(encodedtet, splittet);
19901  if (isdead(&splittet)) {
19902  splittet.tet = dummytet;
19903  }
19904  }
19905  // Locate sympoint in DT. Do exact location.
19906  success = insertsite(sympoint, &splittet, false, flipqueue);
19907 #ifdef SELF_CHECK
19908  assert(success != DUPLICATEPOINT);
19909 #endif
19910  if (success == OUTSIDEPOINT) {
19911  inserthullsite(sympoint, &splittet, flipqueue);
19912  }
19913  if (steinerleft > 0) steinerleft--;
19914  // Let sympoint remember splittet.
19915  setpoint2tet(sympoint, encode(splittet));
19916  // Do flip in DT.
19917  flip(flipqueue, NULL);
19918  // Insert sympoint into F.
19919  // getabovepoint(&symsplitsub);
19920  // symloc = locatesub(sympoint, &symsplitsub, 1, 0.0);
19921  if (symloc == ONFACE) {
19922  splitsubface(sympoint, &symsplitsub, flipqueue);
19923  } else if (symloc == ONEDGE) {
19924  splitsubedge(sympoint, &symsplitsub, flipqueue);
19925  } else {
19926  // 'insertsite()' has done the whole job.
19927 #ifdef SELF_CHECK
19928  assert(symloc == ONVERTEX);
19929  assert(checksubfaces);
19930 #endif
19931  // Split subfaces have been flipped.
19932  flipqueue->clear();
19933  }
19934  // Do flip in facet.
19935  flipsub(flipqueue);
19936  }
19937  }
19938 
19939  // Insert newpoint into DT.
19940  splittet.tet = dummytet;
19941  // Find a good start point to search.
19942  encodedtet = point2tet(pa);
19943  if (encodedtet != (tetrahedron) NULL) {
19944  decode(encodedtet, splittet);
19945  if (isdead(&splittet)) {
19946  splittet.tet = dummytet;
19947  }
19948  }
19949  if (splittet.tet == dummytet) { // Try pb.
19950  encodedtet = point2tet(pb);
19951  if (encodedtet != (tetrahedron) NULL) {
19952  decode(encodedtet, splittet);
19953  if (isdead(&splittet)) {
19954  splittet.tet = dummytet;
19955  }
19956  }
19957  }
19958  // Locate the newpoint in DT. Do exact location.
19959  success = insertsite(newpoint, &splittet, false, flipqueue);
19960 #ifdef SELF_CHECK
19961  assert(success != DUPLICATEPOINT);
19962 #endif
19963  if (success == OUTSIDEPOINT) {
19964  inserthullsite(newpoint, &splittet, flipqueue);
19965  }
19966  if (steinerleft > 0) steinerleft--;
19967  // Let newpoint remember splittet.
19968  setpoint2tet(newpoint, encode(splittet));
19969  // Do flip in DT.
19970  flip(flipqueue, NULL);
19971  // Insert newpoint into F.
19972  // if (checkpbcs) {
19973  // 'abovepoint' has been changed.
19974  // getabovepoint(&splitsub);
19975  // loc = locatesub(newpoint, &splitsub, 1, 0.0);
19976  // }
19977  if (loc == ONFACE) {
19978  // Insert the newpoint in facet.
19979  splitsubface(newpoint, &splitsub, flipqueue);
19980  } else if (loc == ONEDGE) {
19981  // Insert the newpoint in facet.
19982  splitsubedge(newpoint, &splitsub, flipqueue);
19983  } else {
19984  // 'insertsite()' has done the whole job.
19985 #ifdef SELF_CHECK
19986  assert(loc == ONVERTEX);
19987  assert(checksubfaces);
19988 #endif
19989  // Split subfaces have been flipped.
19990  flipqueue->clear();
19991  }
19992  // Set the type of the newpoint.
19993  setpointtype(newpoint, FREESUBVERTEX);
19994  // Set splitsub into the newpoint.
19995  // setpoint2sh(newpoint, sencode(splitsub));
19996  // Do flip in the facet.
19997  flipsub(flipqueue);
19998 
19999  // Remove this entry from list.
20000  badfacedealloc(badsubfaces, encloop);
20001  } else {
20002  // newpoint is rejected. Remove it from points.
20003  pointdealloc(newpoint);
20004  // Repair all encroached segments.
20005  perturbrepairencsegs(flipqueue);
20006  // Do not remove 'encloop'. Later it will be tested again.
20007  setshell2badface(encloop->ss, encloop);
20008  }
20009  } else {
20010  // This subface has been changed. Remove this entry from list.
20011  badfacedealloc(badsubfaces, encloop);
20012  // It may be co-circular with its neighbors.
20013  // checksub4cocir(&splitsub, eps, false, true);
20014  }
20015  // Get the next encroached subfaces.
20016  encloop = badfacetraverse(badsubfaces);
20017  }
20018  }
20019 }
20020 
20022 // //
20023 // incrperturbvertices() Remove the local degeneracies in DT. //
20024 // //
20025 // A local degeneracy of a DT D is a set of 5 or more vertices which share a //
20026 // common sphere S and no other vertex of D in S. D is not unique if it has //
20027 // local degeneracies. This routine removes the local degeneracies from D by //
20028 // inserting break points (as described in reference [2]). //
20029 // //
20030 // 'eps' is a user-provided error tolerance. It is used to detect whether or //
20031 // not five points are approximate cospherical (evaluated in iscospheric()). //
20032 // Set it to 0.0 to disable it, i.e., only test pure degenerate point set. //
20033 // //
20035 
20036 void tetgenmesh::incrperturbvertices(REAL eps)
20037 {
20038  queue *flipqueue;
20039  list *cavsublist;
20040  long vertcount;
20041 
20042  if (!b->quiet) {
20043  printf("Perturbing vertices.\n");
20044  }
20045 
20046  vertcount = points->items;
20047  // Create a map from points to tets for fastening search.
20048  // makepoint2tetmap(); // This has been done in meshsurface().
20049 
20050  // Initialize working queues, lists.
20051  flipqueue = new queue(sizeof(badface));
20052  cavsublist = new list(sizeof(face), NULL, 256);
20053  // Initialize the pool of encroached subfaces and subsegments.
20054  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
20055  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
20056  // Find all pairs of co-circular subfaces.
20057  tallcocirsubs(eps, true);
20058  if (b->verbose && badsubfaces->items > 0) {
20059  printf(" Removing degenerate subfaces.\n");
20060  }
20061  perturbrepairencsubs(cavsublist, flipqueue);
20062 
20063  if (b->verbose > 0) {
20064  printf(" %ld break points.\n", points->items - vertcount);
20065  }
20066 
20067  delete cavsublist;
20068  delete flipqueue;
20069  delete badsubfaces;
20070  delete badsubsegs;
20071  badsubsegs = (memorypool *) NULL;
20072  badsubfaces = (memorypool *) NULL;
20073 }
20074 
20075 //
20076 // End of vertex perturbation routines
20077 //
20078 
20079 //
20080 // Begin of segment recovery routines
20081 //
20082 
20084 // //
20085 // markacutevertices() Mark acute vertices. //
20086 // //
20087 // A vertex v is called acute if there are two segments sharing at v forming //
20088 // an acute angle (i.e. smaller than 90 degree). //
20089 // //
20090 // This routine finds all acute vertices in the PLC and marks them as point- //
20091 // type ACUTEVERTEX. The other vertices of segments which are non-acute will //
20092 // be marked as NACUTEVERTEX. Vertices which are not endpoints of segments //
20093 // (such as DUPLICATEDVERTEX, UNUSEDVERTEX, etc) are not infected. //
20094 // //
20095 // NOTE: This routine should be called before Steiner points are introduced. //
20096 // That is, no point has type like FREESEGVERTEX, etc. //
20097 // //
20099 
20100 void tetgenmesh::markacutevertices(REAL acuteangle)
20101 {
20102  shellface **segsperverlist;
20103  face segloop, nextseg;
20104  point pointloop, edest, eapex;
20105  REAL cosbound, anglearc;
20106  REAL v1[3], v2[3], L, D;
20107  bool isacute;
20108  int *idx2seglist;
20109  int acutecount;
20110  int idx, i, j, k;
20111 
20112  if (b->verbose > 0) {
20113  printf(" Marking acute vertices.\n");
20114  }
20115 
20116  anglearc = acuteangle * PI / 180.0;
20117  cosbound = cos(anglearc);
20118  acutecount = 0;
20119  // Constructing a map from vertex to segments.
20120  makesegmentmap(idx2seglist, segsperverlist);
20121 
20122  // Loop over the set of vertices.
20123  points->traversalinit();
20124  pointloop = pointtraverse();
20125  while (pointloop != (point) NULL) {
20126  idx = pointmark(pointloop) - in->firstnumber;
20127  // Only do test if p is an endpoint of some segments.
20128  if (idx2seglist[idx + 1] > idx2seglist[idx]) {
20129  // Init p to be non-acute.
20130  setpointtype(pointloop, NACUTEVERTEX);
20131  isacute = false;
20132  // Loop through all segments sharing at p.
20133  for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) {
20134  segloop.sh = segsperverlist[i];
20135  // segloop.shver = 0;
20136  if (sorg(segloop) != pointloop) sesymself(segloop);
20137  edest = sdest(segloop);
20138  for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) {
20139  nextseg.sh = segsperverlist[j];
20140  // nextseg.shver = 0;
20141  if (sorg(nextseg) != pointloop) sesymself(nextseg);
20142  eapex = sdest(nextseg);
20143  // Check the angle formed by segs (p, edest) and (p, eapex).
20144  for (k = 0; k < 3; k++) {
20145  v1[k] = edest[k] - pointloop[k];
20146  v2[k] = eapex[k] - pointloop[k];
20147  }
20148  L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
20149  for (k = 0; k < 3; k++) v1[k] /= L;
20150  L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
20151  for (k = 0; k < 3; k++) v2[k] /= L;
20152  D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
20153  // Is D acute?
20154  isacute = (D >= cosbound);
20155  }
20156  }
20157  if (isacute) {
20158  // Mark p to be acute.
20159  setpointtype(pointloop, ACUTEVERTEX);
20160  acutecount++;
20161  }
20162  }
20163  pointloop = pointtraverse();
20164  }
20165 
20166  delete [] idx2seglist;
20167  delete [] segsperverlist;
20168 
20169  if ((b->verbose > 0) && (acutecount > 0)) {
20170  printf(" %d acute vertices.\n", acutecount);
20171  }
20172 }
20173 
20175 // //
20176 // finddirection() Find the first tetrahedron on the path from one point //
20177 // to another. //
20178 // //
20179 // Find the tetrahedron that intersects a line segment L (from the origin of //
20180 // 'searchtet' to the point 'tend'), and returns the result in 'searchtet'. //
20181 // The origin of 'searchtet' does not change, even though the tetrahedron //
20182 // returned may differ from the one passed in. This routine is used to find //
20183 // the direction to move in to get from one point to another. //
20184 // //
20185 // The return value notes the location of the line segment L with respect to //
20186 // 'searchtet': //
20187 // - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment //
20188 // from the origin to the destination of 'searchtet'. //
20189 // - Returns LEFTCOLLINEAR indicates L is collinear with the line segment //
20190 // from the origin to the apex of 'searchtet'. //
20191 // - Returns TOPCOLLINEAR indicates L is collinear with the line segment //
20192 // from the origin to the opposite of 'searchtet'. //
20193 // - Returns ACROSSEDGE indicates L intersects with the line segment from //
20194 // the destination to the apex of 'searchtet'. //
20195 // - Returns ACROSSFACE indicates L intersects with the face opposite to //
20196 // the origin of 'searchtet'. //
20197 // - Returns BELOWHULL indicates L crosses outside the mesh domain. This //
20198 // can only happen when the domain is non-convex. //
20199 // //
20200 // NOTE: This routine only works correctly when the mesh is exactly Delaunay.//
20201 // //
20202 // If 'maxtetnumber' > 0, stop the searching process if the number of passed //
20203 // tets is larger than it. Return BELOWHULL. //
20204 // //
20206 
20207 enum tetgenmesh::finddirectionresult tetgenmesh::
20208 finddirection(triface *searchtet, point tend, long maxtetnumber)
20209 {
20210  triface neightet;
20211  point tstart, tdest, tapex, toppo;
20212  REAL ori1, ori2, ori3;
20213  long tetnumber;
20214 
20215  tstart = org(*searchtet);
20216 #ifdef SELF_CHECK
20217  assert(tstart != tend);
20218 #endif
20219  adjustedgering(*searchtet, CCW);
20220  if (tstart != org(*searchtet)) {
20221  enextself(*searchtet); // For keeping the same origin.
20222  }
20223  tdest = dest(*searchtet);
20224  if (tdest == tend) {
20225  return RIGHTCOLLINEAR;
20226  }
20227  tapex = apex(*searchtet);
20228  if (tapex == tend) {
20229  return LEFTCOLLINEAR;
20230  }
20231 
20232  ori1 = orient3d(tstart, tdest, tapex, tend);
20233  if (ori1 > 0.0) {
20234  // 'tend' is below the face, get the neighbor of this side.
20235  sym(*searchtet, neightet);
20236  if (neightet.tet != dummytet) {
20237  findorg(&neightet, tstart);
20238  adjustedgering(neightet, CCW);
20239  if (org(neightet) != tstart) {
20240  enextself(neightet); // keep the same origin.
20241  }
20242  // Set the changed configuratiuon.
20243  *searchtet = neightet;
20244  ori1 = -1.0;
20245  tdest = dest(*searchtet);
20246  tapex = apex(*searchtet);
20247  } else {
20248  // A hull face. Only possible for a nonconvex mesh.
20249 #ifdef SELF_CHECK
20250  assert(nonconvex);
20251 #endif
20252  return BELOWHULL;
20253  }
20254  }
20255 
20256  // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until
20257  // find a tetrahedron contains 'tend' or is crossed by the line segment
20258  // from 'tstart' to 'tend'.
20259  tetnumber = 0l;
20260  while ((maxtetnumber > 0) && (tetnumber <= maxtetnumber)) {
20261  tetnumber++;
20262  toppo = oppo(*searchtet);
20263  if (toppo == tend) {
20264  return TOPCOLLINEAR;
20265  }
20266  ori2 = orient3d(tstart, toppo, tdest, tend);
20267  if (ori2 > 0.0) {
20268  // 'tend' is below the face, get the neighbor at this side.
20269  fnext(*searchtet, neightet);
20270  symself(neightet);
20271  if (neightet.tet != dummytet) {
20272  findorg(&neightet, tstart);
20273  adjustedgering(neightet, CCW);
20274  if (org(neightet) != tstart) {
20275  enextself(neightet); // keep the same origin.
20276  }
20277  // Set the changed configuration.
20278  *searchtet = neightet;
20279  ori1 = -1.0;
20280  tdest = dest(*searchtet);
20281  tapex = apex(*searchtet);
20282  // Continue the search from the changed 'searchtet'.
20283  continue;
20284  } else {
20285  // A hull face. Only possible for a nonconvex mesh.
20286 #ifdef SELF_CHECK
20287  assert(nonconvex);
20288 #endif
20289  return BELOWHULL;
20290  }
20291  }
20292  ori3 = orient3d(tapex, toppo, tstart, tend);
20293  if (ori3 > 0.0) {
20294  // 'tend' is below the face, get the neighbor at this side.
20295  enext2fnext(*searchtet, neightet);
20296  symself(neightet);
20297  if (neightet.tet != dummytet) {
20298  findorg(&neightet, tstart);
20299  adjustedgering(neightet, CCW);
20300  if (org(neightet) != tstart) {
20301  enextself(neightet); // keep the same origin.
20302  }
20303  // Set the changed configuration.
20304  *searchtet = neightet;
20305  ori1 = -1.0;
20306  tdest = dest(*searchtet);
20307  tapex = apex(*searchtet);
20308  // Continue the search from the changed 'searchtet'.
20309  continue;
20310  } else {
20311  // A hull face. Only possible for a nonconvex mesh.
20312 #ifdef SELF_CHECK
20313  assert(nonconvex);
20314 #endif
20315  return BELOWHULL;
20316  }
20317  }
20318  // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0;
20319  if (ori1 < 0.0) {
20320  // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR.
20321  if (ori2 < 0.0) {
20322  if (ori3 < 0.0) {
20323  return ACROSSFACE;
20324  } else { // ori3 == 0.0;
20325  // Cross edge (apex, oppo)
20326  enext2fnextself(*searchtet);
20327  esymself(*searchtet); // org(*searchtet) == tstart;
20328  return ACROSSEDGE;
20329  }
20330  } else { // ori2 == 0.0;
20331  if (ori3 < 0.0) {
20332  // Cross edge (dest, oppo)
20333  fnextself(*searchtet);
20334  esymself(*searchtet);
20335  enextself(*searchtet); // org(*searchtet) == tstart;
20336  return ACROSSEDGE;
20337  } else { // ori3 == 0.0;
20338  // Collinear with edge (org, oppo)
20339  return TOPCOLLINEAR;
20340  }
20341  }
20342  } else { // ori1 == 0.0;
20343  // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE.
20344  if (ori2 < 0.0) {
20345  if (ori3 < 0.0) {
20346  // Cross edge (tdest, tapex)
20347  return ACROSSEDGE;
20348  } else { // ori3 == 0.0
20349  // Collinear with edge (torg, tapex)
20350  return LEFTCOLLINEAR;
20351  }
20352  } else { // ori2 == 0.0;
20353 #ifdef SELF_CHECK
20354  assert(ori3 != 0.0);
20355 #endif
20356  // Collinear with edge (torg, tdest)
20357  return RIGHTCOLLINEAR;
20358  }
20359  }
20360  }
20361  // Loop breakout. It may happen when the mesh is non-Delaunay.
20362  return BELOWHULL;
20363 }
20364 
20366 // //
20367 // getsearchtet() Find a tetrahedron whose origin is either 'p1' or 'p2'. //
20368 // //
20369 // On return, the origin of 'searchtet' is either 'p1' or 'p2', and 'tend' //
20370 // returns the other point. 'searchtet' serves as the starting tetrahedron //
20371 // for searching of the line segment from 'p1' to 'p2' or vice versa. //
20372 // //
20374 
20375 void tetgenmesh::getsearchtet(point p1, point p2, triface* searchtet,
20376  point* tend)
20377 {
20378  tetrahedron encodedtet1, encodedtet2;
20379 
20380  // Is there a valid handle provided by the user?
20381  if ((searchtet->tet != (tetrahedron *) NULL) && !isdead(searchtet)) {
20382  // Find which endpoint the handle holds.
20383  if (findorg(searchtet, p1)) {
20384  *tend = p2;
20385  return;
20386  } else {
20387  if (findorg(searchtet, p2)) {
20388  *tend = p1;
20389  return;
20390  }
20391  }
20392  }
20393  // If not, search the tet handle stored in 'p1' or 'p2'.
20394  *tend = (point) NULL;
20395  encodedtet1 = point2tet(p1);
20396  encodedtet2 = point2tet(p2);
20397  if (encodedtet1 != (tetrahedron) NULL) {
20398  decode(encodedtet1, *searchtet);
20399  // Be careful, here 'searchtet' may be dead.
20400  if (findorg(searchtet, p1)) {
20401  *tend = p2;
20402  }
20403  } else if (encodedtet2 != (tetrahedron) NULL) {
20404  decode(encodedtet2, *searchtet);
20405  // Be careful, here 'searchtet' may be dead.
20406  if (findorg(searchtet, p2)) {
20407  *tend = p1;
20408  }
20409  }
20410  // If still not, perform a full point location. The starting tet is
20411  // chosen as follows: Use the handle stored in 'p1' or 'p2' if it is
20412  // alive; otherwise, start from a tet on the convex hull.
20413  if (*tend == (point) NULL) {
20414  if (encodedtet1 != (tetrahedron) NULL) {
20415  decode(encodedtet1, *searchtet);
20416  // Be careful, here 'searchtet' may be dead.
20417  }
20418  if (isdead(searchtet)) {
20419  if (encodedtet2 != (tetrahedron) NULL) {
20420  decode(encodedtet2, *searchtet);
20421  // Be careful, here 'searchtet' may be dead.
20422  }
20423  if (isdead(searchtet)) {
20424  searchtet->tet = dummytet;
20425  searchtet->loc = 0;
20426  symself(*searchtet);
20427  }
20428 #ifdef SELF_CHECK
20429  assert(!isdead(searchtet));
20430 #endif
20431  }
20432  if (locate(p1, searchtet) != ONVERTEX) {
20433  printf("Internal error in getsearchtet(): Failed to locate point\n");
20434  internalerror();
20435  }
20436  // Remember this handle in 'p1' to enhance the search speed.
20437  setpoint2tet(p1, encode(*searchtet));
20438  *tend = p2;
20439  }
20440 }
20441 
20443 // //
20444 // isedgeencroached() Check whether or not a subsegment is encroached. //
20445 // //
20446 // A segment with endpoints 'p1' and 'p2' is encroached by the point 'testpt'//
20447 // if it lies in the diametral sphere of this segment. The degenerate case //
20448 // that 'testpt' lies on the sphere is treated as encroached if 'degflag' is //
20449 // set to be TRUE. //
20450 // //
20452 
20453 bool tetgenmesh::isedgeencroached(point p1, point p2, point testpt,
20454  bool degflag)
20455 {
20456  REAL dotproduct;
20457 
20458  // Check if the segment is facing an angle larger than 90 degree?
20459  dotproduct = (p1[0] - testpt[0]) * (p2[0] - testpt[0])
20460  + (p1[1] - testpt[1]) * (p2[1] - testpt[1])
20461  + (p1[2] - testpt[2]) * (p2[2] - testpt[2]);
20462  if (dotproduct < 0) {
20463  return true;
20464  } else if (dotproduct == 0 && degflag) {
20465  return true;
20466  } else {
20467  return false;
20468  }
20469 }
20470 
20472 // //
20473 // scoutrefpoint() Search the reference point of a missing segment. //
20474 // //
20475 // A segment S is missing in current Delaunay tetrahedralization DT and will //
20476 // be split by inserting a point V in it. The two end points of S are the //
20477 // origin of 'searchtet' and 'tend'. And we know that S is crossing the face //
20478 // of 'searchtet' opposite to its origin (may be intersecting with the edge //
20479 // from the destination to the apex of the 'searchtet'). The search of P is //
20480 // completed by walking through all faces of DT across by S. //
20481 // //
20482 // Warning: This routine is correct when the tetrahedralization is Delaunay //
20483 // and convex. Otherwise, the search loop may not terminate. //
20484 // //
20486 
20487 tetgenmesh::point tetgenmesh::scoutrefpoint(triface* searchtet, point tend)
20488 {
20489  triface checkface;
20490  point tstart, testpt, refpoint;
20491  REAL cent[3], radius, largest;
20492  REAL ahead;
20493  bool ncollinear;
20494  int sides;
20495 
20496  if (b->verbose > 2) {
20497  printf(" Scout the reference point of segment (%d, %d).\n",
20498  pointmark(org(*searchtet)), pointmark(tend));
20499  }
20500 
20501  tstart = org(*searchtet);
20502  refpoint = (point) NULL;
20503  largest = 0; // avoid compile warning.
20504 
20505  // Check the three vertices of the crossing face.
20506  testpt = apex(*searchtet);
20507  if (isedgeencroached(tstart, tend, testpt, true)) {
20508  ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20509 #ifdef SELF_CHECK
20510  assert(ncollinear);
20511 #endif
20512  refpoint = testpt;
20513  largest = radius;
20514  }
20515  testpt = dest(*searchtet);
20516  if (isedgeencroached(tstart, tend, testpt, true)) {
20517  ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20518 #ifdef SELF_CHECK
20519  assert(ncollinear);
20520 #endif
20521  if (refpoint == (point) NULL) {
20522  refpoint = testpt;
20523  largest = radius;
20524  } else {
20525  if (radius > largest) {
20526  refpoint = testpt;
20527  largest = radius;
20528  }
20529  }
20530  }
20531  testpt = oppo(*searchtet);
20532  if (isedgeencroached(tstart, tend, testpt, true)) {
20533  ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20534 #ifdef SELF_CHECK
20535  assert(ncollinear);
20536 #endif
20537  if (refpoint == (point) NULL) {
20538  refpoint = testpt;
20539  largest = radius;
20540  } else {
20541  if (radius > largest) {
20542  refpoint = testpt;
20543  largest = radius;
20544  }
20545  }
20546  }
20547  // Check the opposite vertex of the neighboring tet in case the segment
20548  // crosses the edge (leftpoint, rightpoint) of the crossing face.
20549  sym(*searchtet, checkface);
20550  if (checkface.tet != dummytet) {
20551  testpt = oppo(checkface);
20552  if (isedgeencroached(tstart, tend, testpt, true)) {
20553  ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20554 #ifdef SELF_CHECK
20555  assert(ncollinear);
20556 #endif
20557  if (refpoint == (point) NULL) {
20558  refpoint = testpt;
20559  largest = radius;
20560  } else {
20561  if (radius > largest) {
20562  refpoint = testpt;
20563  largest = radius;
20564  }
20565  }
20566  }
20567  }
20568 
20569  // Walk through all crossing faces.
20570  enextfnext(*searchtet, checkface);
20571  sym(checkface, *searchtet);
20572  while (true) {
20573  // Check if we are reaching the boundary of the triangulation.
20574 #ifdef SELF_CHECK
20575  assert(searchtet->tet != dummytet);
20576 #endif
20577  // Search for an adjoining tetrahedron we can walk through.
20578  searchtet->ver = 0;
20579  // 'testpt' is the shared vertex for the following orientation tests.
20580  testpt = oppo(*searchtet);
20581  if (testpt == tend) {
20582  // The searching is finished.
20583  break;
20584  } else {
20585  // 'testpt' may encroach the segment.
20586  if ((testpt != tstart) && (testpt != refpoint)) {
20587  if (isedgeencroached(tstart, tend, testpt, true)) {
20588  ncollinear = circumsphere(tstart, tend, testpt, NULL, cent, &radius);
20589  if (!ncollinear) {
20590  // 'testpt' is collinear with the segment. It may happen when a
20591  // set of collinear and continuous segments is defined by two
20592  // extreme endpoints. In this case, we should choose 'testpt'
20593  // as the splitting point immediately. No new point should be
20594  // created.
20595  refpoint = testpt;
20596  break;
20597  }
20598  if (refpoint == (point) NULL) {
20599  refpoint = testpt;
20600  largest = radius;
20601  } else {
20602  if (radius > largest) {
20603  refpoint = testpt;
20604  largest = radius;
20605  }
20606  }
20607  }
20608  }
20609  }
20610  // Check three side-faces of 'searchtet' to find the one through
20611  // which we can walk next.
20612  for (sides = 0; sides < 3; sides++) {
20613  fnext(*searchtet, checkface);
20614  ahead = orient3d(org(checkface), dest(checkface), testpt, tend);
20615  if (ahead < 0.0) {
20616  // We can walk through this face and continue the searching.
20617  sym(checkface, *searchtet);
20618  break;
20619  }
20620  enextself(*searchtet);
20621  }
20622 #ifdef SELF_CHECK
20623  assert (sides < 3);
20624 #endif
20625  }
20626 
20627 #ifdef SELF_CHECK
20628  assert(refpoint != (point) NULL);
20629 #endif
20630  return refpoint;
20631 }
20632 
20634 // //
20635 // getsegmentorigin() Return the origin of the (unsplit) segment. //
20636 // //
20637 // After a segment (or a subsegment) is split. Two resulting subsegments are //
20638 // connecting each other through the pointers saved in their data fields. //
20639 // With these pointers, the whole (unsplit) segment can be found. 'splitseg' //
20640 // may be a split subsegment. Returns the origin of the unsplit segment. //
20641 // //
20643 
20644 tetgenmesh::point tetgenmesh::getsegmentorigin(face* splitseg)
20645 {
20646  face workseg;
20647  point farorg;
20648 
20649  farorg = sorg(*splitseg);
20650  if ((pointtype(farorg) != ACUTEVERTEX) &&
20651  (pointtype(farorg) != NACUTEVERTEX)) {
20652  workseg = *splitseg;
20653  do {
20654  senext2self(workseg);
20655  spivotself(workseg);
20656  if (workseg.sh != dummysh) {
20657  workseg.shver = 0; // It's a subsegment.
20658  if (sdest(workseg) != farorg) {
20659  sesymself(workseg);
20660 #ifdef SELF_CHECK
20661  assert(sdest(workseg) == farorg);
20662 #endif
20663  }
20664  farorg = sorg(workseg);
20665  if ((pointtype(farorg) == ACUTEVERTEX) ||
20666  (pointtype(farorg) == NACUTEVERTEX)) break;
20667  }
20668  } while (workseg.sh != dummysh);
20669  }
20670 #ifdef SELF_CHECK
20671  assert((pointtype(farorg) == ACUTEVERTEX) ||
20672  (pointtype(farorg) == NACUTEVERTEX));
20673 #endif
20674  return farorg;
20675 }
20676 
20678 // //
20679 // getsplitpoint() Get a point for splitting a segment. //
20680 // //
20681 // 'splitseg' is the segment will be split. 'refpoint' is a reference point //
20682 // for splitting this segment. Moreover, it should not collinear with the //
20683 // splitting segment. (The collinear case will be detected by iscollinear() //
20684 // before entering this routine.) The calculation of the splitting point is //
20685 // governed by three rules introduced in my paper. //
20686 // //
20687 // After the position is calculated, a new point is created at this location.//
20688 // The new point has one of the two pointtypes: FREESEGVERTEX indicating it //
20689 // is an inserting vertex on segment, and NACUTEVERTEX indicating it is an //
20690 // endpoint of a segment which original has type-3 now becomes type-2. //
20691 // //
20693 
20694 tetgenmesh::point tetgenmesh::getsplitpoint(face* splitseg, point refpoint)
20695 {
20696  point splitpoint;
20697  point farorg, fardest;
20698  point ei, ej, ek, c;
20699  REAL v[3], r, split;
20700  REAL d1, d2, ps, rs;
20701  bool acuteorg, acutedest;
20702  int stype, rule;
20703  int i;
20704 
20705  // First determine the type of the segment (type-1, type-2, or type-3).
20706  farorg = getsegmentorigin(splitseg);
20707  acuteorg = (pointtype(farorg) == ACUTEVERTEX);
20708  sesymself(*splitseg);
20709  fardest = getsegmentorigin(splitseg);
20710  acutedest = (pointtype(fardest) == ACUTEVERTEX);
20711  sesymself(*splitseg);
20712 
20713  ek = (point) NULL; // avoid a compilation warning.
20714 
20715  if (acuteorg) {
20716  if (acutedest) {
20717  stype = 3;
20718  } else {
20719  stype = 2;
20720  ek = farorg;
20721  }
20722  } else {
20723  if (acutedest) {
20724  stype = 2;
20725  // Adjust splitseg, so that its origin is acute.
20726  sesymself(*splitseg);
20727  ek = fardest;
20728  } else {
20729  stype = 1;
20730  }
20731  }
20732  ei = sorg(*splitseg);
20733  ej = sdest(*splitseg);
20734 
20735  if (b->verbose > 1) {
20736  printf(" Splitting segment (%d, %d) type-%d with refpoint %d.\n",
20737  pointmark(ei), pointmark(ej), stype, pointmark(refpoint));
20738  }
20739 
20740  if (stype == 1 || stype == 3) {
20741  // Use rule-1.
20742  REAL eij, eip, ejp;
20743  eij = distance(ei, ej);
20744  eip = distance(ei, refpoint);
20745  ejp = distance(ej, refpoint);
20746  if ((eip < ejp) && (eip < 0.5 * eij)) {
20747  c = ei;
20748  r = eip;
20749  } else if ((eip > ejp) && (ejp < 0.5 * eij)) {
20750  c = ej;
20751  ej = ei;
20752  r = ejp;
20753  } else {
20754  c = ei;
20755  r = 0.5 * eij;
20756  }
20757  split = r / eij;
20758  for (i = 0; i < 3; i++) {
20759  v[i] = c[i] + split * (ej[i] - c[i]);
20760  }
20761  rule = 1;
20762  } else {
20763  // Use rule-2 or rule-3.
20764  REAL eki, ekj, ekp, evj, evp, eiv;
20765  c = ek;
20766  eki = distance(ek, ei); // eki may equal zero.
20767  ekj = distance(ek, ej);
20768  ekp = distance(ek, refpoint);
20769  // Calculate v (the going to split position between ei, ej).
20770  r = ekp;
20771  // Check the validity of the position.
20772  if (!(eki < r && r < ekj)) {
20773  printf("Error: Invalid PLC.\n");
20774  printf(" Hint: Use -d switch to check it.\n");
20775  terminatetetgen(1);
20776  }
20777  split = r / ekj;
20778  for (i = 0; i < 3; i++) {
20779  v[i] = c[i] + split * (ej[i] - c[i]);
20780  }
20781  rule = 2;
20782  evj = ekj - r; // distance(v, ej);
20783  evp = distance(v, refpoint);
20784  if (evj < evp) {
20785  // v is rejected, use rule-3.
20786  eiv = distance(ei, v);
20787  if (evp <= 0.5 * eiv) {
20788  r = eki + eiv - evp;
20789  } else {
20790  r = eki + 0.5 * eiv;
20791  }
20792 #ifdef SELF_CHECK
20793  assert(eki < r && r < ekj);
20794 #endif
20795  split = r / ekj;
20796  for (i = 0; i < 3; i++) {
20797  v[i] = c[i] + split * (ej[i] - c[i]);
20798  }
20799  if (b->verbose > 1) {
20800  printf(" Using rule-3.\n");
20801  }
20802  rule = 3;
20803  }
20804  }
20805 
20806  // Accumulate the corresponding counters.
20807  if (rule == 1) r1count++;
20808  else if (rule == 2) r2count++;
20809  else if (rule == 3) r3count++;
20810 
20811  if (b->verbose > 1) {
20812  if (stype == 2) {
20813  printf(" Split = %.12g.\n", distance(ei, v) / distance(ei, ej));
20814  } else {
20815  printf(" Split = %.12g.\n", distance(c, v) / distance(c, ej));
20816  }
20817  }
20818 
20819  // Create the newpoint.
20820  makepoint(&splitpoint);
20821  // Add a random perturbation on splitpoint.
20822  d1 = distance(c, v);
20823  d2 = distance(refpoint, v);
20824  if (stype == 1 || stype == 3) {
20825  ps = randgenerator(d1 * 1.0e-3);
20826  } else {
20827  // For type-2 segment, add a smaller perturbation.
20828  // ps = randgenerator(d1 * 1.0e-5);
20829  // REAL d2 = distance(refpoint, v);
20830  ps = randgenerator(d2 * 1.0e-5);
20831  }
20832  rs = ps / d1;
20833  // Perturb splitpoint away from c.
20834  for (i = 0; i < 3; i++) {
20835  splitpoint[i] = c[i] + (1.0 + rs) * (v[i] - c[i]);
20836  }
20837  // for (i = 0; i < in->numberofpointattributes; i++) {
20838  // splitpoint[i + 3] = c[i + 3] + (split + rs) * (ej[i + 3] - c[i + 3]);
20839  // }
20840  if (stype == 3) {
20841  // Change a type-3 segment into two type-2 segments.
20842  setpointtype(splitpoint, NACUTEVERTEX);
20843  } else {
20844  // Set it's type be FREESEGVERTEX.
20845  setpointtype(splitpoint, FREESEGVERTEX);
20846  }
20847  setpoint2sh(splitpoint, sencode(*splitseg));
20848 
20849  return splitpoint;
20850 }
20851 
20853 // //
20854 // insertsegment() Insert segment into DT. Queue it if it does not exist. //
20855 // //
20857 
20858 bool tetgenmesh::insertsegment(face *insseg, list *misseglist)
20859 {
20860  badface *misseg;
20861  triface searchtet, spintet;
20862  point tend, checkpoint;
20863  point p1, p2;
20864  enum finddirectionresult collinear;
20865  int hitbdry;
20866 
20867  // Search segment ab in DT.
20868  p1 = (point) insseg->sh[3];
20869  p2 = (point) insseg->sh[4];
20870  getsearchtet(p1, p2, &searchtet, &tend);
20871  collinear = finddirection(&searchtet, tend, tetrahedrons->items);
20872  if (collinear == LEFTCOLLINEAR) {
20873  checkpoint = apex(searchtet);
20874  enext2self(searchtet);
20875  esymself(searchtet);
20876  } else if (collinear == RIGHTCOLLINEAR) {
20877  checkpoint = dest(searchtet);
20878  } else if (collinear == TOPCOLLINEAR) {
20879  checkpoint = oppo(searchtet);
20880  fnextself(searchtet);
20881  enext2self(searchtet);
20882  esymself(searchtet);
20883  } else {
20884  // assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
20885  checkpoint = (point) NULL;
20886  }
20887  if (checkpoint == tend) {
20888  // Segment exist. Bond it to all tets containing it.
20889  hitbdry = 0;
20890  adjustedgering(searchtet, CCW);
20891  fnextself(searchtet);
20892  spintet = searchtet;
20893  do {
20894  tssbond1(spintet, *insseg);
20895  if (!fnextself(spintet)) {
20896  hitbdry++;
20897  if (hitbdry < 2) {
20898  esym(searchtet, spintet);
20899  if (!fnextself(spintet)) {
20900  hitbdry++;
20901  }
20902  }
20903  }
20904  } while ((apex(spintet) != apex(searchtet)) && (hitbdry < 2));
20905  return true;
20906  } else {
20907  // Segment is missing.
20908  if (misseglist != (list *) NULL) {
20909  if (b->verbose > 2) {
20910  printf(" Queuing missing segment (%d, %d).\n", pointmark(p1),
20911  pointmark(p2));
20912  }
20913  misseg = (badface *) misseglist->append(NULL);
20914  misseg->ss = *insseg;
20915  misseg->forg = p1;
20916  misseg->fdest = p2;
20917  misseg->foppo = (point) NULL; // Not used.
20918  // setshell2badface(misseg->ss, misseg);
20919  }
20920  return false;
20921  }
20922 }
20923 
20925 // //
20926 // tallmissegs() Find and queue all missing segments in DT. //
20927 // //
20929 
20930 void tetgenmesh::tallmissegs(list *misseglist)
20931 {
20932  face segloop;
20933 
20934  if (b->verbose) {
20935  printf(" Queuing missing segments.\n");
20936  }
20937 
20938  subsegs->traversalinit();
20939  segloop.sh = shellfacetraverse(subsegs);
20940  while (segloop.sh != (shellface *) NULL) {
20941  insertsegment(&segloop, misseglist);
20942  segloop.sh = shellfacetraverse(subsegs);
20943  }
20944 }
20945 
20947 // //
20948 // delaunizesegments() Split segments repeatedly until they appear in a //
20949 // Delaunay tetrahedralization. //
20950 // //
20951 // Given a PLC X, which has a set V of vertices and a set of segments. Start //
20952 // from a Delaunay tetrahedralization D of V, this routine recovers segments //
20953 // of X in D by incrementally inserting points on missing segments, updating //
20954 // D with the newly inserted points into D', which remains to be a Delaunay //
20955 // tetrahedralization and respects the segments of X. Hence, each segment of //
20956 // X appears as a union of edges in D'. //
20957 // //
20958 // This routine dynamically maintains two meshes, one is DT, another is the //
20959 // surface mesh F of X. DT and F have exactly the same vertices. They are //
20960 // updated simultaneously with the newly inserted points. //
20961 // //
20962 // Missing segments are found by looping the set S of segments, checking the //
20963 // existence of each segment in DT. Once a segment is found missing in DT, //
20964 // it is split into two subsegments by inserting a point into both DT and F, //
20965 // and S is updated accordingly. However, the inserted point may cause some //
20966 // other existing segments be non-Delaunay, hence are missing from the DT. //
20967 // In order to force all segments to appear in DT, we have to loop S again //
20968 // after some segments are split. (A little ugly method) Use a handle to //
20969 // remember the last segment be split in one loop, hence all segments after //
20970 // it are existing and need not be checked. //
20971 // //
20972 // In priciple, a segment on the convex hull should exist in DT. However, if //
20973 // there are four coplanar points on the convex hull, and the DT only can //
20974 // contain one diagonal edge which is unfortunately not the segment, then it //
20975 // is missing. During the recovery of the segment, it is possible that the //
20976 // calculated inserting point for recovering this convex hull segment is not //
20977 // exact enough and lies (slightly) outside the DT. In order to insert the //
20978 // point, we enlarge the convex hull of the DT, so it can contain the point //
20979 // and remains convex. 'inserthullsite()' is called for this case. //
20980 // //
20982 
20983 void tetgenmesh::delaunizesegments()
20984 {
20985  list *misseglist;
20986  queue *flipqueue;
20987  badface *misloop;
20988  tetrahedron encodedtet;
20989  triface searchtet, splittet;
20990  face splitsh, symsplitsub;
20991  face segloop, symsplitseg;
20992  point refpoint, splitpoint, sympoint;
20993  point tend, checkpoint;
20994  point p1, p2, pa;
20995  enum finddirectionresult collinear;
20996  enum insertsiteresult success;
20997  enum locateresult symloc;
20998  bool coll;
20999  long vertcount;
21000  int i, j;
21001 
21002  if (!b->quiet) {
21003  printf("Delaunizing segments.\n");
21004  }
21005 
21006  // Construct a map from points to tets for speeding point location.
21007  makepoint2tetmap();
21008  // Initialize a flipqueue.
21009  flipqueue = new queue(sizeof(badface));
21010  // Initialize the pool of missing segments.
21011  misseglist = new list(sizeof(badface), NULL, SUBPERBLOCK);
21012  // Looking for missing segments.
21013  tallmissegs(misseglist);
21014  // The DT contains segments now.
21015  checksubsegs = 1;
21016  // Remember the current number of points.
21017  vertcount = points->items;
21018  // Initialize the counters.
21019  r1count = r2count = r3count = 0l;
21020 
21021  // Loop until 'misseglist' is empty.
21022  while (misseglist->items > 0) {
21023  // Randomly pick a missing segment to recover.
21024  i = randomnation(misseglist->items);
21025  misloop = (badface *)(* misseglist)[i];
21026  segloop = misloop->ss;
21027  // Fill the "hole" in the list by filling the last one.
21028  *misloop = *(badface *)(* misseglist)[misseglist->items - 1];
21029  misseglist->items--;
21030  // Now recover the segment.
21031  p1 = (point) segloop.sh[3];
21032  p2 = (point) segloop.sh[4];
21033  if (b->verbose > 1) {
21034  printf(" Recover segment (%d, %d).\n", pointmark(p1), pointmark(p2));
21035  }
21036  getsearchtet(p1, p2, &searchtet, &tend);
21037  collinear = finddirection(&searchtet, tend, tetrahedrons->items);
21038  if (collinear == LEFTCOLLINEAR) {
21039  checkpoint = apex(searchtet);
21040  } else if (collinear == RIGHTCOLLINEAR) {
21041  checkpoint = dest(searchtet);
21042  } else if (collinear == TOPCOLLINEAR) {
21043  checkpoint = oppo(searchtet);
21044  } else {
21045 #ifdef SELF_CHECK
21046  assert(collinear == ACROSSFACE || collinear == ACROSSEDGE);
21047 #endif
21048  checkpoint = (point) NULL;
21049  }
21050  if (checkpoint != tend) {
21051  // ab is missing.
21052  splitpoint = (point) NULL;
21053  if (checkpoint != (point) NULL) {
21054  // An existing point c is found on the segment. It can happen when
21055  // ab is defined by a long segment with c inside it. Use c to
21056  // split ab. No new point is created.
21057  splitpoint = checkpoint;
21058  if (pointtype(checkpoint) == FREEVOLVERTEX) {
21059  // c is not a segment vertex yet. It becomes NACUTEVERTEX.
21060  setpointtype(splitpoint, NACUTEVERTEX);
21061  } else if (pointtype(checkpoint) == ACUTEVERTEX) {
21062  // c is an acute vertex. The definition of PLC is wrong.
21063  } else if (pointtype(checkpoint) == NACUTEVERTEX) {
21064  // c is an nonacute vertex. The definition of PLC is wrong.
21065  } else {
21066  // assert(0);
21067  }
21068  } else {
21069  // Find a reference point p of ab.
21070  refpoint = scoutrefpoint(&searchtet, tend);
21071  if (pointtype(refpoint) == FREEVOLVERTEX) {
21072  // p is an input point, check if it is nearly collinear with ab.
21073  coll = iscollinear(p1, p2, refpoint, b->epsilon);
21074  if (coll) {
21075  // a, b, and p are collinear. We insert p into ab. p becomes
21076  // a segment vertex with type NACUTEVERTEX.
21077  splitpoint = refpoint;
21078  setpointtype(splitpoint, NACUTEVERTEX);
21079  }
21080  }
21081  if (splitpoint == (point) NULL) {
21082  // Calculate a split point v using rule 1, or 2, or 3.
21083  splitpoint = getsplitpoint(&segloop, refpoint);
21084 
21085  // Is there periodic boundary conditions?
21086  if (checkpbcs) {
21087  // Yes! Insert points on other segments of incident pbcgroups.
21088  i = shellmark(segloop) - 1;
21089  for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
21090  makepoint(&sympoint);
21091  symloc = getsegpbcsympoint(splitpoint, &segloop, sympoint,
21092  &symsplitseg, segpglist[j]);
21093 #ifdef SELF_CHECK
21094  assert(symloc != OUTSIDE);
21095 #endif
21096  if ((symloc == ONEDGE) && (symsplitseg.sh != segloop.sh)) {
21097 #ifdef SELF_CHECK
21098  assert(symsplitseg.sh != dummysh);
21099 #endif
21100  setpointtype(sympoint, FREESEGVERTEX);
21101  setpoint2sh(sympoint, sencode(symsplitseg));
21102  // Insert sympoint into DT.
21103  pa = sorg(symsplitseg);
21104  splittet.tet = dummytet;
21105  // Find a good start point to search.
21106  encodedtet = point2tet(pa);
21107  if (encodedtet != (tetrahedron) NULL) {
21108  decode(encodedtet, splittet);
21109  if (isdead(&splittet)) {
21110  splittet.tet = dummytet;
21111  }
21112  }
21113  // Locate sympoint in DT. Do exact location.
21114  success = insertsite(sympoint, &splittet, false, flipqueue);
21115 #ifdef SELF_CHECK
21116  assert(success != DUPLICATEPOINT);
21117 #endif
21118  if (success == OUTSIDEPOINT) {
21119  inserthullsite(sympoint, &splittet, flipqueue);
21120  }
21121  if (steinerleft > 0) steinerleft--;
21122  // Let sympoint remember splittet.
21123  setpoint2tet(sympoint, encode(splittet));
21124  // Do flip in DT.
21125  lawson(misseglist, flipqueue);
21126  // Insert sympoint into F.
21127  symsplitseg.shver = 0;
21128  spivot(symsplitseg, symsplitsub);
21129  // sympoint should on the edge of symsplitsub.
21130  splitsubedge(sympoint, &symsplitsub, flipqueue);
21131  // Do flip in facet.
21132  flipsub(flipqueue);
21133  // Insert the two subsegments.
21134  symsplitseg.shver = 0;
21135  insertsegment(&symsplitseg, misseglist);
21136  senextself(symsplitseg);
21137  spivotself(symsplitseg);
21138  symsplitseg.shver = 0;
21139  insertsegment(&symsplitseg, misseglist);
21140  } else { // if (symloc == ONVERTEX) {
21141  // The sympoint already exists. It is possible when two
21142  // pbc groups are exactly the same. Omit this point.
21143  pointdealloc(sympoint);
21144  }
21145  }
21146  }
21147 
21148  // Insert 'splitpoint' into DT.
21149  if (isdead(&searchtet)) searchtet.tet = dummytet;
21150  success = insertsite(splitpoint, &searchtet, false, flipqueue);
21151  if (success == OUTSIDEPOINT) {
21152  // A convex hull edge is missing, and the inserting point lies
21153  // (slightly) outside the convex hull due to the significant
21154  // digits lost in the calculation. Enlarge the convex hull.
21155  inserthullsite(splitpoint, &searchtet, flipqueue);
21156  }
21157  if (steinerleft > 0) steinerleft--;
21158  // Remember a handle in 'splitpoint' to enhance the speed of
21159  // consequent point location.
21160  setpoint2tet(splitpoint, encode(searchtet));
21161  // Maintain Delaunayness in DT.
21162  lawson(misseglist, flipqueue);
21163  }
21164  }
21165  // Insert 'splitpoint' into F.
21166  spivot(segloop, splitsh);
21167  splitsubedge(splitpoint, &splitsh, flipqueue);
21168  flipsub(flipqueue);
21169  // Insert the two subsegments.
21170  segloop.shver = 0;
21171  insertsegment(&segloop, misseglist);
21172  senextself(segloop);
21173  spivotself(segloop);
21174  segloop.shver = 0;
21175  insertsegment(&segloop, misseglist);
21176  }
21177  }
21178 
21179  // Detach all segments from tets.
21180  tetrahedrons->traversalinit();
21181  searchtet.tet = tetrahedrontraverse();
21182  while (searchtet.tet != (tetrahedron *) NULL) {
21183  for (i = 0; i < 6; i++) {
21184  searchtet.tet[8 + i] = (tetrahedron) dummysh;
21185  }
21186  searchtet.tet = tetrahedrontraverse();
21187  }
21188  // No segments now.
21189  checksubsegs = 0;
21190 
21191  if (b->verbose > 0) {
21192  printf(" %ld protect points.\n", points->items - vertcount);
21193  printf(" R1: %ld, R2: %ld, R3: %ld.\n", r1count, r2count, r3count);
21194  }
21195 
21196  delete flipqueue;
21197  delete misseglist;
21198 }
21199 
21200 //
21201 // End of segments recovery routines
21202 //
21203 
21204 //
21205 // Begin of facet recovery routines
21206 //
21207 
21209 // //
21210 // insertsubface() Fix a subface in place. //
21211 // //
21212 // Search a subface s in current tetrahedralization T. If s is found a face //
21213 // face of T, it is inserted into T. Return FALSE if s is not found in T. //
21214 // //
21216 
21217 bool tetgenmesh::insertsubface(face* insertsh, triface* searchtet)
21218 {
21219  triface spintet, symtet;
21220  face testsh, testseg;
21221  face spinsh, casin, casout;
21222  point tapex, checkpoint;
21223  enum finddirectionresult collinear;
21224  int hitbdry;
21225 
21226  // Search an edge of s.
21227  getsearchtet(sorg(*insertsh), sdest(*insertsh), searchtet, &checkpoint);
21228  collinear = finddirection(searchtet, checkpoint, tetrahedrons->items);
21229  if (collinear == LEFTCOLLINEAR) {
21230  enext2self(*searchtet);
21231  esymself(*searchtet);
21232  } else if (collinear == TOPCOLLINEAR) {
21233  fnextself(*searchtet);
21234  enext2self(*searchtet);
21235  esymself(*searchtet);
21236  }
21237  if (dest(*searchtet) != checkpoint) {
21238  // The edge doesn't exist => s is missing.
21239  return false;
21240  }
21241 
21242  // Search s by spinning faces around the edge.
21243  tapex = sapex(*insertsh);
21244  spintet = *searchtet;
21245  hitbdry = 0;
21246  do {
21247  if (apex(spintet) == tapex) {
21248  // Found s in T. Check if s has already been inserted.
21249  tspivot(spintet, testsh);
21250  if (testsh.sh == dummysh) {
21251  adjustedgering(spintet, CCW);
21252  findedge(insertsh, org(spintet), dest(spintet));
21253  tsbond(spintet, *insertsh);
21254  sym(spintet, symtet); // 'symtet' maybe outside, use it anyway.
21255  sesymself(*insertsh);
21256  tsbond(symtet, *insertsh);
21257  } else {
21258  // Found a duplicated subface (due to the redundant input).
21259  if (!b->quiet) {
21260  printf("Warning: Two subfaces are found duplicated at ");
21261  printf("(%d, %d, %d)\n", pointmark(sorg(testsh)),
21262  pointmark(sdest(testsh)), pointmark(sapex(testsh)));
21263  printf(" Subface of facet #%d is deleted.\n", shellmark(*insertsh));
21264  // printf(" Hint: -d switch can find all duplicated facets.\n");
21265  }
21266  shellfacedealloc(subfaces, insertsh->sh);
21267  }
21268  return true;
21269  }
21270  if (!fnextself(spintet)) {
21271  hitbdry ++;
21272  if (hitbdry < 2) {
21273  esym(*searchtet, spintet);
21274  if (!fnextself(spintet)) {
21275  hitbdry ++;
21276  }
21277  }
21278  }
21279  } while (hitbdry < 2 && apex(spintet) != apex(*searchtet));
21280 
21281  // s is missing.
21282  return false;
21283 }
21284 
21286 // //
21287 // tritritest() Test if two triangles are intersecting in their interior. //
21288 // //
21289 // One triangle t1 is the face of 'checktet', the other t2 is given by three //
21290 // corners 'p1', 'p2' and 'p3'. This routine calls tri_tri_inter() to detect //
21291 // whether t1 and t2 exactly intersect in their interior. Cases like share a //
21292 // vertex, share an edge, or coincidence are considered not intersect. //
21293 // //
21295 
21296 bool tetgenmesh::tritritest(triface* checktet, point p1, point p2, point p3)
21297 {
21298  point forg, fdest, fapex;
21299  enum interresult intersect;
21300 
21301  forg = org(*checktet);
21302  fdest = dest(*checktet);
21303  fapex = apex(*checktet);
21304 
21305 #ifdef SELF_CHECK
21306  REAL ax, ay, az, bx, by, bz;
21307  REAL n[3];
21308  // face (torg, tdest, tapex) should not be degenerate. However p1, p2,
21309  // and p3 may be collinear. Check it.
21310  ax = forg[0] - fdest[0];
21311  ay = forg[1] - fdest[1];
21312  az = forg[2] - fdest[2];
21313  bx = forg[0] - fapex[0];
21314  by = forg[1] - fapex[1];
21315  bz = forg[2] - fapex[2];
21316  n[0] = ay * bz - by * az;
21317  n[1] = az * bx - bz * ax;
21318  n[2] = ax * by - bx * ay;
21319  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
21320  // The components of n should not smaller than the machine epsilon.
21321 
21322  ax = p1[0] - p2[0];
21323  ay = p1[1] - p2[1];
21324  az = p1[2] - p2[2];
21325  bx = p1[0] - p3[0];
21326  by = p1[1] - p3[1];
21327  bz = p1[2] - p3[2];
21328  n[0] = ay * bz - by * az;
21329  n[1] = az * bx - bz * ax;
21330  n[2] = ax * by - bx * ay;
21331  assert(fabs(n[0]) + fabs(n[1]) + fabs(n[2]) > 0.0);
21332  // The components of n should not smaller than the machine epsilon.
21333 #endif
21334 
21335  intersect = tri_tri_inter(forg, fdest, fapex, p1, p2, p3);
21336  return intersect == INTERSECT;
21337 }
21338 
21340 // //
21341 // initializecavity() Initialize the cavity. //
21342 // //
21343 // A cavity C is bounded by a list of faces, called fronts. Each front f is //
21344 // hold by a tet t adjacent to C, t is not in C (uninfected). If f is a hull //
21345 // face, t does't exist, a fake tet t' is created to hold f. t' has the same //
21346 // vertices as f but no opposite. t' will be removed automatically after C //
21347 // is filled with new tets (by carvecavity()). //
21348 // //
21349 // The faces of C are given in two lists. 'floorlist' is a set of subfaces, //
21350 // each subface has been oriented to face to the inside of C. 'ceillist' is //
21351 // a set of tetrahedral faces. 'frontlist' returns the initialized fronts. //
21352 // //
21354 
21355 void tetgenmesh::initializecavity(list* floorlist, list* ceillist,
21356  list* frontlist)
21357 {
21358  triface neightet, casingtet;
21359  triface faketet;
21360  face worksh;
21361  int i;
21362 
21363  // Initialize subfaces of C.
21364  for (i = 0; i < floorlist->len(); i++) {
21365  // Get a subface s.
21366  worksh = * (face *)(* floorlist)[i];
21367 #ifdef SELF_CHECK
21368  // Current side of s should be empty.
21369  stpivot(worksh, neightet);
21370  assert(neightet.tet == dummytet);
21371 #endif
21372  // Get the adjacent tet t.
21373  sesymself(worksh);
21374  stpivot(worksh, casingtet);
21375  // Does t exist?
21376  if (casingtet.tet == dummytet) {
21377  // Create a fake tet t' to hold f temporarily.
21378  maketetrahedron(&faketet);
21379  setorg(faketet, sorg(worksh));
21380  setdest(faketet, sdest(worksh));
21381  setapex(faketet, sapex(worksh));
21382  setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21383  tsbond(faketet, worksh);
21384  frontlist->append(&faketet);
21385  } else {
21386  frontlist->append(&casingtet);
21387  }
21388  }
21389  // Initialize tet faces of C.
21390  for (i = 0; i < ceillist->len(); i++) {
21391  // Get a tet face c.
21392  neightet = * (triface *) (* ceillist)[i];
21393 #ifdef SELF_CHECK
21394  // The tet of c must be inside C (going to be deleted).
21395  assert(infected(neightet));
21396 #endif
21397  // Get the adjacent tet t.
21398  sym(neightet, casingtet);
21399  // Does t exist?
21400  if (casingtet.tet == dummytet) {
21401  // No. Create a fake tet t' to hold f temporarily.
21402  maketetrahedron(&faketet);
21403  // Be sure that the vertices of t' are CCW oriented.
21404  adjustedgering(neightet, CW); // CW edge ring.
21405  setorg(faketet, org(neightet));
21406  setdest(faketet, dest(neightet));
21407  setapex(faketet, apex(neightet));
21408  setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21409  // Bond t' to a subface if it exists.
21410  tspivot(neightet, worksh);
21411  if (worksh.sh != dummysh) {
21412  sesymself(worksh);
21413  tsbond(faketet, worksh);
21414  }
21415  // Bond c <--> t'. So we're able to find t' and remove it.
21416  bond(faketet, neightet);
21417  // c may become uninfected due to the bond().
21418  infect(neightet);
21419  frontlist->append(&faketet);
21420  } else {
21421  frontlist->append(&casingtet);
21422  }
21423  }
21424 }
21425 
21427 // //
21428 // retrievenewtets() Retrieve the newly created tets. //
21429 // //
21430 // On input, 'newtetlist' contains at least one alive new tet. From this tet,//
21431 // other new tets can be found by a broadth-first searching. //
21432 // //
21434 
21435 void tetgenmesh::retrievenewtets(list* newtetlist)
21436 {
21437  triface searchtet, casingtet;
21438  int i;
21439 
21440  // There may be dead tets due to flip32(). Delete them first.
21441  for (i = 0; i < newtetlist->len(); i++) {
21442  searchtet = * (triface *)(* newtetlist)[i];
21443  if (isdead(&searchtet)) {
21444  newtetlist->del(i, 0); i--;
21445  continue;
21446  }
21447  infect(searchtet);
21448  }
21449  // Find all new tets.
21450  for (i = 0; i < newtetlist->len(); i++) {
21451  searchtet = * (triface *)(* newtetlist)[i];
21452  for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) {
21453  sym(searchtet, casingtet);
21454  if ((casingtet.tet != dummytet) && !infected(casingtet)) {
21455  infect(casingtet);
21456  newtetlist->append(&casingtet);
21457  }
21458  }
21459  }
21460  // Uninfect new tets.
21461  for (i = 0; i < newtetlist->len(); i++) {
21462  searchtet = * (triface *)(* newtetlist)[i];
21463  uninfect(searchtet);
21464  }
21465 }
21466 
21468 // //
21469 // delaunizecavvertices() Form a DT of the vertices of a cavity. //
21470 // //
21471 // 'floorptlist' and 'ceilptlist' are the vertices of the cavity. //
21472 // //
21473 // The tets of the DT are created directly in the pool 'tetrahedrons', i.e., //
21474 // no auxiliary data structure and memory are required. The trick is at the //
21475 // time they're created, there are no connections between them to the other //
21476 // tets in the pool. You can imagine they form an ioslated island. //
21477 // //
21479 
21480 void tetgenmesh::delaunizecavvertices(triface* oldtet, list* floorptlist,
21481  list* ceilptlist, list* newtetlist, queue* flipque)
21482 {
21483  point *insertarray;
21484  triface bakhulltet, newtet;
21485  long bakhullsize;
21486  long arraysize;
21487  int bakchksub;
21488  int i, j;
21489 
21490  // Prepare the array of points for inserting.
21491  arraysize = floorptlist->len();
21492  if (ceilptlist != (list *) NULL) {
21493  arraysize += ceilptlist->len();
21494  }
21495  insertarray = new point[arraysize];
21496  for (i = 0; i < floorptlist->len(); i++) {
21497  insertarray[i] = * (point *)(* floorptlist)[i];
21498  }
21499  if (ceilptlist != (list *) NULL) {
21500  for (j = 0; j < ceilptlist->len(); j++) {
21501  insertarray[i + j] = * (point *)(* ceilptlist)[j];
21502  }
21503  }
21504 
21505  // The incrflipdelaunay() is re-used. Backup global variables.
21506  decode(dummytet[0], bakhulltet);
21507  bakhullsize = hullsize;
21508  bakchksub = checksubfaces;
21509  checksubfaces = 0;
21510  b->verbose--;
21511 
21512  // Form the DT by incremental flip Delaunay algorithm. Do not jump for
21513  // point location, do not merge points.
21514  incrflipdelaunay(oldtet, insertarray, arraysize, false, false, 0.0, flipque);
21515 
21516  // Get a tet in D.
21517  decode(dummytet[0], newtet);
21518  newtetlist->append(&newtet);
21519  // Get all tets of D.
21520  retrievenewtets(newtetlist);
21521 
21522  // Restore global variables.
21523  dummytet[0] = encode(bakhulltet);
21524  hullsize = bakhullsize;
21525  checksubfaces = bakchksub;
21526  b->verbose++;
21527 
21528  delete [] insertarray;
21529 }
21530 
21532 // //
21533 // insertauxsubface() Fix an auxilary subface in place. //
21534 // //
21535 // An auxilary subface s is fixed in D as it is a real subface, but s has no //
21536 // vertices and neighbors. It has two uses: (1) it protects an identfied //
21537 // front f in D; (2) it serves the link to bond a tet in C and f later. The //
21538 // first neighbor of s (s->sh[0]) stores a pointer to f. //
21539 // //
21540 // 'front' is a front f of C. idfront' t is a tet in D where f is identified //
21541 // be a face of it. s will be fixed between t and its neighbor. //
21542 // //
21544 
21545 void tetgenmesh::insertauxsubface(triface* front, triface* idfront)
21546 {
21547  triface neightet;
21548  face auxsh;
21549 
21550  // Create the aux subface s.
21551  makeshellface(subfaces, &auxsh);
21552  // Bond s <--> t.
21553  tsbond(*idfront, auxsh);
21554  // Does t's neighbor n exist?
21555  sym(*idfront, neightet);
21556  if (neightet.tet != dummytet) {
21557  // Bond s <--> n.
21558  sesymself(auxsh);
21559  tsbond(neightet, auxsh);
21560  }
21561  // Let s remember f.
21562  auxsh.sh[0] = (shellface) encode(*front);
21563 }
21564 
21566 // //
21567 // scoutfront() Scout a face in D. //
21568 // //
21569 // Search a 'front' f in D. If f is found, return TRUE and the face of D is //
21570 // returned in 'idfront'. Otherwise, return FALSE. //
21571 // //
21573 
21574 bool tetgenmesh::scoutfront(triface* front, triface* idfront, list* newtetlist)
21575 {
21576  triface spintet;
21577  point pa, pb, pc;
21578  enum locateresult loc;
21579  enum finddirectionresult col;
21580  int hitbdry;
21581  int i;
21582 
21583  // Let the front we're searching is abc.
21584  pa = org(*front);
21585  pb = dest(*front);
21586  // Get a tet in D for searching.
21587  *idfront = recenttet;
21588  // Make sure the tet is valid (it may be killed by flips).
21589  if (isdead(idfront)) {
21590  // The tet is dead. Search a live tet in D. !!!
21591  for (i = 0; i < newtetlist->len(); i++) {
21592  recenttet = * (triface *)(* newtetlist)[i];
21593  if (!isdead(&recenttet)) break;
21594  }
21595  assert(i < newtetlist->len());
21596  }
21597 
21598  // Search a tet having vertex a.
21599  loc = preciselocate(pa, idfront, (long) newtetlist->len());
21600  UNUSED_OPT(loc);
21601  assert(loc == ONVERTEX);
21602  recenttet = *idfront;
21603  // Search a tet having edge ab.
21604  col = finddirection(idfront, pb, (long) newtetlist->len());
21605  if (col == RIGHTCOLLINEAR) {
21606  // b is just the destination.
21607  } else if (col == LEFTCOLLINEAR) {
21608  enext2self(*idfront);
21609  esymself(*idfront);
21610  } else if (col == TOPCOLLINEAR) {
21611  fnextself(*idfront);
21612  enext2self(*idfront);
21613  esymself(*idfront);
21614  }
21615 
21616  if (dest(*idfront) == pb) {
21617  // Search a tet having face abc
21618  pc = apex(*front);
21619  spintet = *idfront;
21620  hitbdry = 0;
21621  do {
21622  if (apex(spintet) == pc) {
21623  // Found abc. Insert an auxilary subface s at idfront.
21624  // insertauxsubface(front, &spintet);
21625  *idfront = spintet;
21626  return true;
21627  }
21628  if (!fnextself(spintet)) {
21629  hitbdry ++;
21630  if (hitbdry < 2) {
21631  esym(*idfront, spintet);
21632  if (!fnextself(spintet)) {
21633  hitbdry ++;
21634  }
21635  }
21636  }
21637  if (apex(spintet) == apex(*idfront)) break;
21638  } while (hitbdry < 2);
21639  }
21640 
21641  // f is missing in D.
21642  if (b->verbose > 2) {
21643  printf(" Front (%d, %d, %d) is missing.\n", pointmark(pa),
21644  pointmark(pb), pointmark(apex(*front)));
21645  }
21646  return false;
21647 }
21648 
21650 // //
21651 // gluefronts() Glue two fronts together. //
21652 // //
21653 // This is a support routine for identifyfront(). Two fronts f and f1 are //
21654 // found indentical. This is caused by the non-coplanarity of vertices of a //
21655 // facet. Hence f and f1 are a subface and a tet. They are not fronts of the //
21656 // cavity anymore. This routine glues f and f1 together. //
21657 // //
21659 
21660 void tetgenmesh::gluefronts(triface* front, triface* front1)
21661 {
21662  face consh;
21663 
21664  // Glue f and f1 together. There're four cases:
21665  // (1) both f and f1 are not fake;
21666  // (2) f is not fake, f1 is fake;
21667  // (3) f is fake and f1 is not fake;
21668  // (4) both f and f1 are fake.
21669  // Case (4) should be not possible.
21670 
21671  // Is there a concrete subface c at f.
21672  tspivot(*front, consh);
21673  if (consh.sh != dummysh) {
21674  sesymself(consh);
21675  tsbond(*front1, consh); // Bond: f1 <--> c.
21676  sesymself(consh);
21677  }
21678  // Does f hold by a fake tet.
21679  if (oppo(*front) == (point) NULL) {
21680  // f is fake. Case (3) or (4).
21681  assert(oppo(*front1) != (point) NULL); // Eliminate (4).
21682  // Case (3).
21683  if (consh.sh != dummysh) {
21684  stdissolve(consh); // Dissolve: c -x-> f.
21685  }
21686  // Dealloc f.
21687  tetrahedrondealloc(front->tet);
21688  // f1 becomes a hull. let 'dummytet' bond to it.
21689  dummytet[0] = encode(*front1);
21690  } else {
21691  // Case (1) or (2).
21692  bond(*front, *front1); // Bond f1 <--> f.
21693  }
21694  // Is f a fake tet?
21695  if (!isdead(front)) {
21696  // No. Check for case (2).
21697  tspivot(*front1, consh);
21698  // Is f1 fake?
21699  if (oppo(*front1) == (point) NULL) {
21700  // Case (2) or (4)
21701  assert(oppo(*front) != (point) NULL); // Eliminate (4).
21702  // Case (2).
21703  if (consh.sh != dummysh) {
21704  stdissolve(consh); // Dissolve: c -x-> f1.
21705  sesymself(consh); // Bond: f <--> c.
21706  tsbond(*front, consh);
21707  }
21708  // Dissolve: f -x->f1.
21709  dissolve(*front);
21710  // Dealloc f1.
21711  tetrahedrondealloc(front1->tet);
21712  // f becomes a hull. let 'dummytet' bond to it.
21713  dummytet[0] = encode(*front);
21714  } else {
21715  // Case (1).
21716  if (consh.sh != dummysh) {
21717  sesymself(consh);
21718  tsbond(*front, consh); // Bond: f <--> c.
21719  }
21720  }
21721  }
21722 }
21723 
21725 // //
21726 // identifyfronts() Identify cavity faces in D. //
21727 // //
21728 // 'frontlist' are fronts of C need indentfying. This routine searches each //
21729 // front f in D. Once f is found, an auxilary subface s is inserted in D at //
21730 // the face. If f is not found in D, remove it from frontlist and save it in //
21731 // 'misfrontlist'. //
21732 // //
21734 
21735 bool tetgenmesh::identifyfronts(list* frontlist, list* misfrontlist,
21736  list* newtetlist)
21737 {
21738  triface front, front1, tfront;
21739  triface idfront, neightet;
21740  face auxsh;
21741  int len, i, j;
21742 
21743  misfrontlist->clear();
21744  // Set a new tet in D for searching.
21745  recenttet = * (triface *)(* newtetlist)[0];
21746 
21747  // Identify all fronts in D.
21748  for (i = 0; i < frontlist->len(); i++) {
21749  // Get a front f.
21750  front = * (triface *)( *frontlist)[i];
21751  if (scoutfront(&front, &idfront, newtetlist)) {
21752  // Found f. Insert an aux subface s.
21753  assert((idfront.tet != dummytet) && !isdead(&idfront));
21754  // Does s already exist?
21755  tspivot(idfront, auxsh);
21756  if (auxsh.sh != dummysh) {
21757  // There're two identical fronts, f (front) and f1 (s.sh[0])!
21758  decode((tetrahedron) auxsh.sh[0], front1);
21759  assert((front1.tet != dummytet) && !infected(front1));
21760  // Detach s in D.
21761  tsdissolve(idfront);
21762  sym(idfront, neightet);
21763  if (neightet.tet != dummytet) {
21764  tsdissolve(neightet);
21765  }
21766  // s has fulfilled its duty. Can be deleted.
21767  shellfacedealloc(subfaces, auxsh.sh);
21768  // Remove f from frontlist.
21769  frontlist->del(i, 1); i--;
21770  // Remove f1 from frontlist.
21771  len = frontlist->len();
21772  for (j = 0; j < frontlist->len(); j++) {
21773  tfront = * (triface *)(* frontlist)[j];
21774  if ((tfront.tet == front1.tet) && (tfront.loc == front1.loc)) {
21775  // Found f1 in list. Check f1 != f.
21776  assert((tfront.tet != front.tet) || (tfront.loc != front.loc));
21777  frontlist->del(j, 1); i--;
21778  break;
21779  }
21780  }
21781  assert((frontlist->len() + 1) == len);
21782  UNUSED_OPT(len);
21783  // Glue f and f1 together.
21784  gluefronts(&front, &front1);
21785  } else {
21786  // Insert an aux subface to protect f in D.
21787  insertauxsubface(&front, &idfront);
21788  }
21789  } else {
21790  // f is missing.
21791  frontlist->del(i, 1); i--;
21792  // Are there two identical fronts, f (front) and f1 (front1)?
21793  for (j = 0; j < misfrontlist->len(); j++) {
21794  front1 = * (triface *)(* misfrontlist)[j];
21795  if (isfacehaspoint(&front1, org(front)) &&
21796  isfacehaspoint(&front1, dest(front)) &&
21797  isfacehaspoint(&front1, apex(front))) break;
21798  }
21799  if (j < misfrontlist->len()) {
21800  // Found an identical front f1. Remove f1 from the list.
21801  misfrontlist->del(j, 1);
21802  // Glue f and f1 together.
21803  gluefronts(&front, &front1);
21804  } else {
21805  // Add f into misfrontlist.
21806  misfrontlist->append(&front);
21807  }
21808  }
21809  }
21810  return misfrontlist->len() == 0;
21811 }
21812 
21814 // //
21815 // detachauxsubfaces() Detach auxilary subfaces in D. //
21816 // //
21817 // This is a reverse routine of identifyfronts(). Some fronts are missing in //
21818 // D. C can not be easily tetrahedralized. It needs remediation (expansion, //
21819 // or constrained flips, or adding a Steiner point). This routine detaches //
21820 // the auxilary subfaces have been inserted in D and delete them. //
21821 // //
21823 
21824 void tetgenmesh::detachauxsubfaces(list* newtetlist)
21825 {
21826  triface newtet, neightet;
21827  face auxsh;
21828  int i;
21829 
21830  for (i = 0; i < newtetlist->len(); i++) {
21831  // Get a new tet t.
21832  newtet = * (triface *)(* newtetlist)[i];
21833  // t may e dead due to flips.
21834  if (isdead(&newtet)) continue;
21835  assert(!infected(newtet));
21836  // Check the four faces of t.
21837  for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
21838  tspivot(newtet, auxsh);
21839  if (auxsh.sh != dummysh) {
21840  // An auxilary subface s.
21841  assert(sorg(auxsh) == (point) NULL);
21842  tsdissolve(newtet); // t -x-> s.
21843  sym(newtet, neightet);
21844  if (neightet.tet != dummytet) {
21845  assert(!isdead(&neightet));
21846  tsdissolve(neightet); // n -x-> s.
21847  }
21848  // Delete s.
21849  shellfacedealloc(subfaces, auxsh.sh);
21850  }
21851  }
21852  }
21853 }
21854 
21856 // //
21857 // expandcavity() Expand the cavity by adding new fronts. //
21858 // //
21859 // This is the support routine for delaunizecavity(). Some fronts of C are //
21860 // missing in D since they're not strongly Delaunay. Such fronts are removed //
21861 // and the faces of the tets abutting to them are added. C is then expanded. //
21862 // Some removed faces may be subfaces, they're queued to recover later. D is //
21863 // expanded simultaneously with the new vertices of the new fronts. //
21864 // //
21866 
21867 void tetgenmesh::expandcavity(list* frontlist, list* misfrontlist,
21868  list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
21869 {
21870  triface misfront, newfront, casingtet, crosstet;
21871  triface searchtet, faketet, bakhulltet;
21872  face checksh;
21873  point pd;
21874  enum insertsiteresult success;
21875  long bakhullsize;
21876  int bakchksub;
21877  int i, j, k;
21878 
21879  if (b->verbose > 1) {
21880  printf(" Expand cavity (%d missing fronts).\n", misfrontlist->len());
21881  }
21882  // Increase the number of expanded times.
21883  expcavcount++;
21884  // The incrflipdelaunay() is re-used. Backup global variables.
21885  decode(dummytet[0], bakhulltet);
21886  bakhullsize = hullsize;
21887  bakchksub = checksubfaces;
21888  checksubfaces = 0;
21889  b->verbose--;
21890 
21891  // Choose a tet in D for searching.
21892  recenttet = * (triface *)(* newtetlist)[0];
21893  assert((recenttet.tet != dummytet) && !isdead(&recenttet));
21894 
21895  // Loop through 'misfrontlist'.
21896  for (i = 0; i < misfrontlist->len(); i++) {
21897  // Get a missing front f.
21898  misfront = * (triface *)(* misfrontlist)[i];
21899  // C will be expanded at f.
21900  if (b->verbose > 1) {
21901  printf(" Get misfront (%d, %d, %d).\n", pointmark(org(misfront)),
21902  pointmark(dest(misfront)), pointmark(apex(misfront)));
21903  }
21904  // Is f has a subface s?
21905  tspivot(misfront, checksh);
21906  if (checksh.sh != dummysh) {
21907  // A subface s is found. Check whether f is expandable at s.
21908  sym(misfront, crosstet);
21909  if (!infected(crosstet)) {
21910  // f is not expandable. In principle is should not happen. However,
21911  // it can happen when PBC is in use.
21912  assert(checkpbcs);
21913  // Skip expanding f. It will be processed later.
21914  continue;
21915  }
21916  // Temporarily remove s. Queue and recover it later.
21917  if (b->verbose > 1) {
21918  printf(" Queuing subface (%d, %d, %d).\n",
21919  pointmark(sorg(checksh)), pointmark(sdest(checksh)),
21920  pointmark(sapex(checksh)));
21921  }
21922  // Detach s from tets at its both sides.
21923  tsdissolve(misfront);
21924  tsdissolve(crosstet);
21925  // Detach tets at from s.
21926  stdissolve(checksh);
21927  sesymself(checksh);
21928  stdissolve(checksh);
21929  // Mark and queue it.
21930  sinfect(checksh);
21931  missingshqueue->push(&checksh);
21932  }
21933  // f may already be processed (become a cross tet of C).
21934  if (infected(misfront)) continue;
21935  // Get the point p = oppo(t), t is the tet holds f.
21936  pd = oppo(misfront);
21937 #ifdef SELF_CHECK
21938  // t must not be fake.
21939  assert(pd != (point) NULL);
21940 #endif
21941  // Insert p in D. p may not be inserted if it is one of the two cases:
21942  // (1) p is already a vertex of D;
21943  // (2) p lies outside the CH of D;
21944  searchtet = recenttet;
21945  // Make sure the tet is valid (it may be killed by flips).
21946  if (isdead(&searchtet)) {
21947  // The tet is dead. Get a live tet in D. !!!
21948  for (j = 0; j < newtetlist->len(); j++) {
21949  recenttet = * (triface *)(* newtetlist)[j];
21950  if (!isdead(&recenttet)) break;
21951  }
21952  assert(j < newtetlist->len());
21953  searchtet = recenttet;
21954  }
21955  success = insertsite(pd, &searchtet, false, flipque);
21956  if (success == OUTSIDEPOINT) {
21957  // case (2). Insert p onto CH of D.
21958  inserthullsite(pd, &searchtet, flipque);
21959  }
21960  if (success != DUPLICATEPOINT) {
21961  // p is inserted. Recover Delaunness of D by flips.
21962  flip(flipque, NULL);
21963  }
21964  // Expand C by adding new fronts. The three faces of t which have p as a
21965  // vertex become new fronts. However, if a new front is coincident with
21966  // an old front of C, it is not added and the old front is removed.
21967  adjustedgering(misfront, CCW);
21968  for (j = 0; j < 3; j++) {
21969  // Notice: Below I mis-used the names. 'newfront' is not exactly a new
21970  // front, instead the 'casingtet' should be called new front.
21971  // Get a new front f_n.
21972  fnext(misfront, newfront);
21973  // Get the neighbor tet n at f_n.
21974  sym(newfront, casingtet);
21975  // Is n a cross tet?
21976  if (!infected(casingtet)) {
21977  // f_n becomes a new front of C.
21978  // Does n exist?
21979  if (casingtet.tet == dummytet) {
21980  // Create a fake tet n' to hold f_n temporarily.
21981  maketetrahedron(&faketet);
21982  // Be sure that the vertices of fake tet are CCW oriented.
21983  adjustedgering(newfront, CW); // CW edge ring.
21984  setorg(faketet, org(newfront));
21985  setdest(faketet, dest(newfront));
21986  setapex(faketet, apex(newfront));
21987  setoppo(faketet, (point) NULL); // Indicates it is 'fake'.
21988  // Bond n' to a subface if it exists.
21989  tspivot(newfront, checksh);
21990  if (checksh.sh != dummysh) {
21991  sesymself(checksh);
21992  tsbond(faketet, checksh);
21993  }
21994  // Bond f_n <--> n'. So we're able to find n' and remove it.
21995  bond(faketet, newfront);
21996  frontlist->append(&faketet);
21997  } else {
21998  // Add n to frontlist.
21999  frontlist->append(&casingtet);
22000  }
22001  } else {
22002  // f_n is coincident with an existing front f' of C. f' is no longer
22003  // a front, remove it from frontlist. Use the inverse order to
22004  // search f' (most likely, a newly added front may be f').
22005  for (k = frontlist->len() - 1; k >= 0; k--) {
22006  searchtet = * (triface *)(* frontlist)[k];
22007  if ((newfront.tet == searchtet.tet) &&
22008  (newfront.loc == searchtet.loc)) {
22009  frontlist->del(k, 0);
22010  break;
22011  }
22012  }
22013  // Is f_n a subface?
22014  tspivot(newfront, checksh);
22015  if (checksh.sh != dummysh) {
22016  // Temporarily remove checksh. Make it missing. recover it later.
22017  if (b->verbose > 2) {
22018  printf(" Queuing subface (%d, %d, %d).\n",
22019  pointmark(sorg(checksh)), pointmark(sdest(checksh)),
22020  pointmark(sapex(checksh)));
22021  }
22022  tsdissolve(newfront);
22023  tsdissolve(casingtet);
22024  // Detach tets at the both sides of checksh.
22025  stdissolve(checksh);
22026  sesymself(checksh);
22027  stdissolve(checksh);
22028  sinfect(checksh);
22029  missingshqueue->push(&checksh);
22030  }
22031  }
22032  enextself(misfront);
22033  }
22034  // C has been expanded at f. t becomes a cross tet.
22035  if (!infected(misfront)) {
22036  // t will be deleted, queue it.
22037  infect(misfront);
22038  crosstetlist->append(&misfront);
22039  }
22040  }
22041 
22042  // Loop through misfrontlist, remove infected misfronts.
22043  for (i = 0; i < misfrontlist->len(); i++) {
22044  misfront = * (triface *)(* misfrontlist)[i];
22045  if (infected(misfront)) {
22046  // Remove f, keep original list order.
22047  misfrontlist->del(i, 1);
22048  i--;
22049  }
22050  }
22051 
22052  // Are we done?
22053  if (misfrontlist->len() > 0) {
22054  // No. There are unexpandable fronts.
22055  // expandcavity_sos(misfrontlist);
22056  assert(0); // Not done yet.
22057  }
22058 
22059  // D has been updated (by added new tets or dead tets) (due to flips).
22060  retrievenewtets(newtetlist);
22061 
22062  // Restore global variables.
22063  dummytet[0] = encode(bakhulltet);
22064  hullsize = bakhullsize;
22065  checksubfaces = bakchksub;
22066  b->verbose++;
22067 }
22068 
22070 // //
22071 // carvecavity() Remove redundant (outside) tetrahedra from D. //
22072 // //
22073 // The fronts of C have been identified in D. Hence C can be tetrahedralized //
22074 // by removing the tets outside C. The CDT is then updated by filling C with //
22075 // the remaining tets (inside C) of D. //
22076 // //
22077 // Each front is protected by an auxilary subface s in D. s has a pointer to //
22078 // f (s.sh[0]). f can be used to classified the in- and out- tets of C (the //
22079 // CW orientation of f faces to the inside of C). The classified out-tets of //
22080 // C are marked (infected) for removing. //
22081 // //
22082 // Notice that the out-tets may not only the tets on the CH of C, but also //
22083 // tets completely inside D, eg., there is a "hole" in D. Such tets must be //
22084 // marked during classification. The hole tets are poped up and removed too. //
22085 // //
22087 
22088 void tetgenmesh::carvecavity(list* newtetlist, list* outtetlist,
22089  queue* flipque)
22090 {
22091  triface newtet, neightet, front, outtet;
22092  face auxsh, consh;
22093  point pointptr;
22094  REAL ori;
22095  int i;
22096 
22097  // Clear work list.
22098  outtetlist->clear();
22099 
22100  // Classify in- and out- tets in D. Mark and queue classified out-tets.
22101  for (i = 0; i < newtetlist->len(); i++) {
22102  // Get a new tet t.
22103  newtet = * (triface *)(* newtetlist)[i];
22104  assert(!isdead(&newtet));
22105  // Look for aux subfaces attached at t.
22106  for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
22107  tspivot(newtet, auxsh);
22108  if (auxsh.sh != dummysh) {
22109  // Has this side a neighbor n?
22110  sym(newtet, neightet);
22111  if (neightet.tet != dummytet) {
22112  // Classify t and n (one is "in" and another is "out").
22113  // Get the front f.
22114  decode((tetrahedron) auxsh.sh[0], front);
22115  // Let f face to the inside of C.
22116  adjustedgering(front, CW);
22117  ori = orient3d(org(front), dest(front), apex(front), oppo(newtet));
22118  assert(ori != 0.0);
22119  if (ori < 0.0) {
22120  // t is in-tet. n is out-tet.
22121  outtet = neightet;
22122  } else {
22123  // n is in-tet. t is out-tet.
22124  outtet = newtet;
22125  }
22126  // Add the out-tet into list.
22127  if (!infected(outtet)) {
22128  infect(outtet);
22129  outtetlist->append(&outtet);
22130  }
22131  }
22132  }
22133  }
22134  }
22135 
22136  // Find and mark all out-tets.
22137  for (i = 0; i < outtetlist->len(); i++) {
22138  outtet = * (triface *)(* outtetlist)[i];
22139  for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
22140  sym(outtet, neightet);
22141  // Does the neighbor exist and unmarked?
22142  if ((neightet.tet != dummytet) && !infected(neightet)) {
22143  // Is it protected by an aux subface?
22144  tspivot(outtet, auxsh);
22145  if (auxsh.sh == dummysh) {
22146  // It's an out-tet.
22147  infect(neightet);
22148  outtetlist->append(&neightet);
22149  }
22150  }
22151  }
22152  }
22153 
22154  // Remove the out- (and hole) tets.
22155  for (i = 0; i < outtetlist->len(); i++) {
22156  // Get an out-tet t.
22157  outtet = * (triface *)(* outtetlist)[i];
22158  // Detach t from the in-tets.
22159  for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) {
22160  // Is there an aux subface s?
22161  tspivot(outtet, auxsh);
22162  if (auxsh.sh != dummysh) {
22163  // Get the neighbor n.
22164  sym(outtet, neightet);
22165  assert(!infected(neightet)); // t must be in-tet.
22166  // Detach n -x-> t.
22167  dissolve(neightet);
22168  }
22169  }
22170  // Dealloc the tet.
22171  tetrahedrondealloc(outtet.tet);
22172  }
22173 
22174  // Connect the in-tets of C to fronts. Remove aux subfaces and fake tets.
22175  for (i = 0; i < newtetlist->len(); i++) {
22176  // Get a new tet t.
22177  newtet = * (triface *)(* newtetlist)[i];
22178  // t may be an out-tet and has got deleted.
22179  if (isdead(&newtet)) continue;
22180  // t is an in-tet. Look for aux subfaces attached at t.
22181  for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) {
22182  // Is there an aux subface s?
22183  tspivot(newtet, auxsh);
22184  if (auxsh.sh != dummysh) {
22185  // Get the front f.
22186  decode((tetrahedron) auxsh.sh[0], front);
22187  assert((front.tet != dummytet) && !infected(front));
22188  // s has fulfilled its duty. Can be deleted.
22189  tsdissolve(newtet); // dissolve: t -x-> s.
22190  // Delete s.
22191  shellfacedealloc(subfaces, auxsh.sh);
22192  // Connect the newtet t and front f.
22193  // Is there a concrete subface c at f.
22194  tspivot(front, consh);
22195  if (consh.sh != dummysh) {
22196  sesymself(consh);
22197  // Bond: t <--> c.
22198  tsbond(newtet, consh);
22199  }
22200  // Does f hold by a fake tet.
22201  if (oppo(front) == (point) NULL) {
22202  // f is fake.
22203  if (consh.sh != dummysh) {
22204  sesymself(consh);
22205  // Dissolve: c -x-> f.
22206  stdissolve(consh);
22207  }
22208  // Dealloc f.
22209  tetrahedrondealloc(front.tet);
22210  // f becomes a hull. let 'dummytet' bond to it.
22211  dummytet[0] = encode(newtet);
22212  } else {
22213  // Bond t <--> f.
22214  bond(newtet, front);
22215  }
22216  // t may be non-locally Delaunay and flipable.
22217  if (flipque != (queue *) NULL) {
22218  enqueueflipface(newtet, flipque);
22219  }
22220  }
22221  }
22222  // Let the corners of t2 point to it for fast searching.
22223  pointptr = org(newtet);
22224  setpoint2tet(pointptr, encode(newtet));
22225  pointptr = dest(newtet);
22226  setpoint2tet(pointptr, encode(newtet));
22227  pointptr = apex(newtet);
22228  setpoint2tet(pointptr, encode(newtet));
22229  pointptr = oppo(newtet);
22230  setpoint2tet(pointptr, encode(newtet));
22231  }
22232  // The cavity has been re-tetrahedralized.
22233 }
22234 
22236 // //
22237 // delaunizecavity() Tetrahedralize a cavity by Delaunay tetrahedra. //
22238 // //
22239 // The cavity C is bounded by a set of triangles in 'floorlist' (a list of //
22240 // coplanar subfaces) and 'ceillist' (a list of tetrahedral faces lie above //
22241 // the subfaces). 'floorptlist' and 'ceilptlist' are the vertices of C. //
22242 // //
22244 
22245 void tetgenmesh::delaunizecavity(list* floorlist, list* ceillist,
22246  list* ceilptlist, list* floorptlist, list* frontlist, list* misfrontlist,
22247  list* newtetlist, list* crosstetlist, queue* missingshqueue, queue* flipque)
22248 {
22249  int vertnum;
22250 
22251  vertnum = floorptlist->len();
22252  vertnum += (ceilptlist != (list *) NULL ? ceilptlist->len() : 0);
22253  if (b->verbose > 1) {
22254  printf(" Delaunizing cavity (%d floors, %d ceilings, %d vertices).\n",
22255  floorlist->len(), ceillist->len(), vertnum);
22256  }
22257  // Save the size of the largest cavity.
22258  if ((floorlist->len() + ceillist->len()) > maxcavfaces) {
22259  maxcavfaces = floorlist->len() + ceillist->len();
22260  }
22261  if (vertnum > maxcavverts) {
22262  maxcavverts = vertnum;
22263  }
22264 
22265  // Clear these lists.
22266  frontlist->clear();
22267  misfrontlist->clear();
22268  newtetlist->clear();
22269 
22270  // Initialize the cavity C.
22271  initializecavity(floorlist, ceillist, frontlist);
22272  // Form the D of the vertices of C.
22273  delaunizecavvertices(NULL, floorptlist, ceilptlist, newtetlist, flipque);
22274  // Identify faces of C in D.
22275  while (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
22276  // Remove protecting subfaces, keep new tets.
22277  detachauxsubfaces(newtetlist);
22278  // Expand C and updateing D.
22279  expandcavity(frontlist, misfrontlist, newtetlist, crosstetlist,
22280  missingshqueue, flipque);
22281  }
22282  // All fronts have identified in D. Get the shape of C by removing out
22283  // tets of C. 'misfrontlist' is reused for removing out tets.
22284  carvecavity(newtetlist, misfrontlist, NULL);
22285 }
22286 
22288 // //
22289 // formmissingregion() Form the missing region. //
22290 // //
22291 // 'missingsh' is a missing subface. Start from it we can form the missing //
22292 // region R (a set of connected missing subfaces). Because all missing sub- //
22293 // faces have been marked (infected) before. R can be formed by checking the //
22294 // neighbors of 'missingsh', and the neighbors of the neighbors, and so on. //
22295 // Stop checking further at either a segment or an unmarked subface. //
22296 // //
22297 // 'missingshlist' returns R. The edge ring of subfaces of R are oriented in //
22298 // the same direction. 'equatptlist' returns the vertices of R, each vertex //
22299 // is marked with '1' (in 'worklist'). //
22300 // //
22302 
22303 void tetgenmesh::formmissingregion(face* missingsh, list* missingshlist,
22304  list* equatptlist, int* worklist)
22305 {
22306  face neighsh, worksh, workseg;
22307  point workpt[3];
22308  int idx, i, j;
22309 
22310  // Add 'missingsh' into 'missingshlist'.
22311  missingshlist->append(missingsh);
22312  // Save and mark its three vertices.
22313  workpt[0] = sorg(*missingsh);
22314  workpt[1] = sdest(*missingsh);
22315  workpt[2] = sapex(*missingsh);
22316  for (i = 0; i < 3; i++) {
22317  idx = pointmark(workpt[i]) - in->firstnumber;
22318  worklist[idx] = 1;
22319  equatptlist->append(&workpt[i]);
22320  }
22321  // Temporarily uninfect it (avoid to save it again).
22322  suninfect(*missingsh);
22323 
22324  // Find the other missing subfaces.
22325  for (i = 0; i < missingshlist->len(); i++) {
22326  // Get a missing subface.
22327  worksh = * (face *)(* missingshlist)[i];
22328  // Check three neighbors of this face.
22329  for (j = 0; j < 3; j++) {
22330  sspivot(worksh, workseg);
22331  if (workseg.sh == dummysh) {
22332  spivot(worksh, neighsh);
22333  if (sinfected(neighsh)) {
22334  // Find a missing subface, adjust the face orientation.
22335  if (sorg(neighsh) != sdest(worksh)) {
22336  sesymself(neighsh);
22337  }
22338  if (b->verbose > 2) {
22339  printf(" Add missing subface (%d, %d, %d).\n",
22340  pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
22341  pointmark(sapex(neighsh)));
22342  }
22343  missingshlist->append(&neighsh);
22344  // Save and mark its apex.
22345  workpt[0] = sapex(neighsh);
22346  idx = pointmark(workpt[0]) - in->firstnumber;
22347  // Has workpt[0] been added?
22348  if (worklist[idx] == 0) {
22349  worklist[idx] = 1;
22350  equatptlist->append(&workpt[0]);
22351  }
22352  // Temporarily uninfect it (avoid to save it again).
22353  suninfect(neighsh);
22354  }
22355  }
22356  senextself(worksh);
22357  }
22358  }
22359 
22360  // R has been formed. Infect missing subfaces again.
22361  for (i = 0; i < missingshlist->len(); i++) {
22362  worksh = * (face *)(* missingshlist)[i];
22363  sinfect(worksh);
22364  }
22365 }
22366 
22368 // //
22369 // rearrangesubfaces() Rearrange the set of subfaces of a missing region //
22370 // so that they conform to the faces of DT. //
22371 // //
22372 // The missing region formed by subfaces of 'missingshlist' contains a set //
22373 // of degenerate vertices, hence the set of subfaces don't match the set of //
22374 // faces in DT. Instead of forcing them to present in DT, we re-arrange the //
22375 // connection of them so that the new subfaces conform to the faces of DT. //
22376 // 'boundedgelist' is a set of boundary edges of the region, these edges(may //
22377 // be subsegments) must exist in DT. //
22378 // //
22379 // On completion, we have created and inserted a set of new subfaces which //
22380 // conform to faces of DT. The set of old subfaces in 'missingshlist' are //
22381 // deleted. The region vertices in 'equatptlist' are unmarked. //
22382 // //
22384 
22385 void tetgenmesh::rearrangesubfaces(list* missingshlist, list* boundedgelist,
22386  list* equatptlist, int* worklist)
22387 {
22388  link *boundedgelink;
22389  link *newshlink;
22390  triface starttet, spintet, neightet, worktet;
22391  face shloop, newsh, neighsh, spinsh, worksh;
22392  face workseg, casingin, casingout;
22393  point torg, tdest, workpt;
22394  point spt1, spt2, spt3;
22395  enum finddirectionresult collinear;
22396  enum shestype shtype;
22397  REAL area;
22398  bool matchflag, finishflag;
22399  int shmark, pbcgp, idx, hitbdry;
22400  int i, j;
22401 
22402  // Initialize the boundary edge link.
22403  boundedgelink = new link(sizeof(face), NULL, 256);
22404  // Initialize the new subface link.
22405  newshlink = new link(sizeof(face), NULL, 256);
22406  // Remember the type (skinny or not) of replaced subfaces. They should
22407  // all have the same type since there is no segment inside the region.
22408  worksh = * (face *)(* missingshlist)[0];
22409  shtype = shelltype(worksh);
22410  // The following loop is only for checking purpose.
22411  for (i = 1; i < missingshlist->len(); i++) {
22412  worksh = * (face *)(* missingshlist)[i];
22413  assert(shelltype(worksh) == shtype);
22414  }
22415  // To avoid compilation warnings.
22416  shmark = pbcgp = 0;
22417  area = 0.0;
22418 
22419  // Create an initial boundary link.
22420  for (i = 0; i < boundedgelist->len(); i++) {
22421  shloop = * (face *)(* boundedgelist)[i];
22422  if (i == 0) {
22423  // 'shmark' will be set to all new created subfaces.
22424  shmark = shellmark(shloop);
22425  if (b->quality && varconstraint) {
22426  // area will be copied to all new created subfaces.
22427  area = areabound(shloop);
22428  }
22429  if (checkpbcs) {
22430  // pbcgp will be copied to all new created subfaces.
22431  pbcgp = shellpbcgroup(shloop);
22432  }
22433  // Get the abovepoint of this facet.
22434  abovepoint = facetabovepointarray[shellmark(shloop)];
22435  if (abovepoint == (point) NULL) {
22436  getfacetabovepoint(&shloop);
22437  }
22438  }
22439  sspivot(shloop, workseg);
22440  if (workseg.sh == dummysh) {
22441  // This edge is an interior edge.
22442  spivot(shloop, neighsh);
22443  boundedgelink->add(&neighsh);
22444  } else {
22445  // This side has a segment, the edge exists.
22446  boundedgelink->add(&shloop);
22447  }
22448  }
22449 
22450  // Each edge ab of boundedgelink will be finished by finding a vertex c
22451  // which is a vertex of the missing region, such that:
22452  // (1) abc is inside the missing region, i.e., abc intersects at least
22453  // one of missing subfaces (saved in missingshlist);
22454  // (2) abc is not intersect with any previously created new subfaces
22455  // in the missing region (saved in newshlink).
22456  // After abc is created, it will be inserted into both the surface mesh
22457  // and the DT. The boundedgelink will be updated, ab is removed, bc and
22458  // ca will be added if they are open.
22459 
22460  while (boundedgelink->len() > 0) {
22461  // Remove an edge (ab) from the link.
22462  shloop = * (face *) boundedgelink->del(1);
22463  // 'workseg' indicates it is a segment or not.
22464  sspivot(shloop, workseg);
22465  torg = sorg(shloop); // torg = a;
22466  tdest = sdest(shloop); // tdest = b;
22467  // Find a tetrahedron containing ab.
22468  getsearchtet(torg, tdest, &starttet, &workpt);
22469  collinear = finddirection(&starttet, workpt, tetrahedrons->items);
22470  if (collinear == LEFTCOLLINEAR) {
22471  enext2self(starttet);
22472  esymself(starttet);
22473  } else if (collinear == TOPCOLLINEAR) {
22474  fnextself(starttet);
22475  enext2self(starttet);
22476  esymself(starttet);
22477  }
22478  assert(dest(starttet) == workpt);
22479  // Checking faces around ab until a valid face is found.
22480  matchflag = false;
22481  spintet = starttet;
22482  hitbdry = 0;
22483  do {
22484  workpt = apex(spintet);
22485  idx = pointmark(workpt) - in->firstnumber;
22486  if (worklist[idx] == 1) {
22487  // (trog, tdest, workpt) is on the facet. Check if it satisfies (1).
22488  finishflag = false;
22489  for (i = 0; i < missingshlist->len(); i++) {
22490  worksh = * (face *)(* missingshlist)[i];
22491  spt1 = sorg(worksh);
22492  spt2 = sdest(worksh);
22493  spt3 = sapex(worksh);
22494  // Does bc intersect the face?
22495  if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
22496  == INTERSECT) {
22497  finishflag = true; break;
22498  }
22499  // Does ca intersect the face?
22500  if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
22501  == INTERSECT) {
22502  finishflag = true; break;
22503  }
22504  // Does c inside the face?
22505  if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
22506  == INTERSECT) {
22507  finishflag = true; break;
22508  }
22509  }
22510  if (finishflag) {
22511  // Satisfying (1). Check if it satisfies (2).
22512  matchflag = true;
22513  for (i = 0; i < newshlink->len() && matchflag; i++) {
22514  worksh = * (face *) newshlink->getnitem(i + 1);
22515  spt1 = sorg(worksh);
22516  spt2 = sdest(worksh);
22517  spt3 = sapex(worksh);
22518  // Does bc intersect the face?
22519  if (tri_edge_cop_inter(spt1, spt2, spt3, tdest, workpt, abovepoint)
22520  == INTERSECT) {
22521  matchflag = false; break;
22522  }
22523  // Does ca intersect the face?
22524  if (tri_edge_cop_inter(spt1, spt2, spt3, workpt, torg, abovepoint)
22525  == INTERSECT) {
22526  matchflag = false; break;
22527  }
22528  // Does c inside the face?
22529  if (tri_vert_cop_inter(spt1, spt2, spt3, workpt, abovepoint)
22530  == INTERSECT) {
22531  matchflag = false; break;
22532  }
22533  }
22534  }
22535  if (matchflag == true) {
22536  // Satisfying both (1) and (2). Find abc.
22537  break;
22538  }
22539  }
22540  if (!fnextself(spintet)) {
22541  hitbdry ++;
22542  if (hitbdry < 2) {
22543  esym(starttet, spintet);
22544  if (!fnextself(spintet)) {
22545  hitbdry ++;
22546  }
22547  }
22548  }
22549  } while (hitbdry < 2 && apex(spintet) != apex(starttet));
22550  assert(matchflag == true);
22551  tspivot(spintet, neighsh);
22552  if (neighsh.sh != dummysh) {
22553  printf("Error: Invalid PLC.\n");
22554  printf(" Facet #%d and facet #%d overlap each other.\n",
22555  shellmark(neighsh), shellmark(shloop));
22556  printf(" It might be caused by a facet is defined more than once.\n");
22557  printf(" Hint: Use -d switch to find all overlapping facets.\n");
22558  exit(1);
22559  }
22560  // The side of 'spintet' is at which a new subface will be attached.
22561  adjustedgering(spintet, CCW);
22562  // Create the new subface.
22563  makeshellface(subfaces, &newsh);
22564  setsorg(newsh, org(spintet));
22565  setsdest(newsh, dest(spintet));
22566  setsapex(newsh, apex(spintet));
22567  if (b->quality && varconstraint) {
22568  setareabound(newsh, area);
22569  }
22570  if (checkpbcs) {
22571  setshellpbcgroup(newsh, pbcgp);
22572  }
22573  setshellmark(newsh, shmark);
22574  setshelltype(newsh, shtype); // It may be a skinny subface.
22575  // Add newsh into newshlink for intersecting checking.
22576  newshlink->add(&newsh);
22577  // Insert it into the current mesh.
22578  tsbond(spintet, newsh);
22579  sym(spintet, neightet);
22580  if (neightet.tet != dummytet) {
22581  sesym(newsh, neighsh);
22582  tsbond(neightet, neighsh);
22583  }
22584  // Insert it into the surface mesh.
22585  sspivot(shloop, workseg);
22586  if (workseg.sh == dummysh) {
22587  sbond(shloop, newsh);
22588  } else {
22589  // There is a subsegment, 'shloop' is the subface which is going to
22590  // die. Insert the 'newsh' at the place of 'shloop' into its face
22591  // link, so as to dettach 'shloop'. The original connection is:
22592  // -> casingin -> shloop -> casingout ->, it will be changed with:
22593  // -> casingin -> newsh -> casingout ->. Pay attention to the
22594  // case when this subsegment is dangling in the mesh, i.e., 'shloop'
22595  // is bonded to itself.
22596  spivot(shloop, casingout);
22597  if (shloop.sh != casingout.sh) {
22598  // 'shloop' is not bonded to itself.
22599  spinsh = casingout;
22600  do {
22601  casingin = spinsh;
22602  spivotself(spinsh);
22603  } while (sapex(spinsh) != sapex(shloop));
22604  assert(casingin.sh != shloop.sh);
22605  // Bond casingin -> newsh -> casingout.
22606  sbond1(casingin, newsh);
22607  sbond1(newsh, casingout);
22608  } else {
22609  // Bond newsh -> newsh.
22610  sbond(newsh, newsh);
22611  }
22612  // Bond the segment.
22613  ssbond(newsh, workseg);
22614  }
22615  // Check other two sides of this new subface. If a side is not bonded
22616  // to any edge in the link, it will be added to the link.
22617  for (i = 0; i < 2; i++) {
22618  if (i == 0) {
22619  senext(newsh, worksh);
22620  } else {
22621  senext2(newsh, worksh);
22622  }
22623  torg = sorg(worksh);
22624  tdest = sdest(worksh);
22625  finishflag = false;
22626  for (j = 0; j < boundedgelink->len() && !finishflag; j++) {
22627  neighsh = * (face *) boundedgelink->getnitem(j + 1);
22628  if ((sorg(neighsh) == torg && sdest(neighsh) == tdest) ||
22629  (sorg(neighsh) == tdest && sdest(neighsh) == torg)) {
22630  // Find a boundary edge. Bond them and exit the loop.
22631  sspivot(neighsh, workseg);
22632  if (workseg.sh == dummysh) {
22633  sbond(neighsh, worksh);
22634  } else {
22635  // There is a subsegment, 'neighsh' is the subface which is
22636  // going to die. Do the same as above for 'worksh'.
22637  spivot(neighsh, casingout);
22638  if (neighsh.sh != casingout.sh) {
22639  // 'neighsh' is not bonded to itself.
22640  spinsh = casingout;
22641  do {
22642  casingin = spinsh;
22643  spivotself(spinsh);
22644  } while (sapex(spinsh) != sapex(neighsh));
22645  assert(casingin.sh != neighsh.sh);
22646  // Bond casingin -> worksh -> casingout.
22647  sbond1(casingin, worksh);
22648  sbond1(worksh, casingout);
22649  } else {
22650  // Bond worksh -> worksh.
22651  sbond(worksh, worksh);
22652  }
22653  // Bond the segment.
22654  ssbond(worksh, workseg);
22655  }
22656  // Remove this boundary edge from the link.
22657  boundedgelink->del(j + 1);
22658  finishflag = true;
22659  }
22660  }
22661  if (!finishflag) {
22662  // It's a new boundary edge, add it to link.
22663  boundedgelink->add(&worksh);
22664  }
22665  }
22666  }
22667 
22668  // Deallocate the set of old missing subfaces.
22669  for (i = 0; i < missingshlist->len(); i++) {
22670  worksh = * (face *)(* missingshlist)[i];
22671  shellfacedealloc(subfaces, worksh.sh);
22672  }
22673  // Unmark region vertices in 'worklist'.
22674  for (i = 0; i < equatptlist->len(); i++) {
22675  workpt = * (point *)(* equatptlist)[i];
22676  idx = pointmark(workpt) - in->firstnumber;
22677  worklist[idx] = 0;
22678  }
22679 
22680  delete boundedgelink;
22681  delete newshlink;
22682 }
22683 
22685 // //
22686 // scoutcrossingedge() Search an edge crossing the missing region. //
22687 // //
22688 // 'missingshlist' forms the missing region R. This routine searches for an //
22689 // edge crossing R. It first forms a 'boundedgelist' consisting of the //
22690 // boundary edges of R. Such edges are existing in CDT. A crossing edge is //
22691 // found by rotating faces around one of the boundary edges. It is possible //
22692 // there is no edge crosses R (e.g. R has a degenerate point set). //
22693 // //
22694 // If find a croosing edge, return TRUE, 'crossedgelist' contains this edge. //
22695 // Otherwise, return FALSE. //
22696 // //
22698 
22699 bool tetgenmesh::scoutcrossingedge(list* missingshlist, list* boundedgelist,
22700  list* crossedgelist, int* worklist)
22701 {
22702  triface starttet, spintet, worktet;
22703  face startsh, neighsh, worksh, workseg;
22704  point torg, tdest, tapex;
22705  point workpt[3], pa, pb, pc;
22706  enum finddirectionresult collinear;
22707  REAL ori1, ori2;
22708  bool crossflag;
22709  int hitbdry;
22710  int i, j, k;
22711 
22712  // Form the 'boundedgelist'. Loop through 'missingshlist', check each
22713  // edge of these subfaces. If an edge is a segment or the neighbor
22714  // subface is uninfected, add it to 'boundedgelist'.
22715  for (i = 0; i < missingshlist->len(); i++) {
22716  worksh = * (face *)(* missingshlist)[i];
22717  for (j = 0; j < 3; j++) {
22718  sspivot(worksh, workseg);
22719  if (workseg.sh == dummysh) {
22720  spivot(worksh, neighsh);
22721  if (!sinfected(neighsh)) {
22722  boundedgelist->append(&worksh);
22723  }
22724  } else {
22725  boundedgelist->append(&worksh);
22726  }
22727  senextself(worksh);
22728  }
22729  }
22730 
22731  crossflag = false;
22732  // Find a crossing edge. It is possible there is no such edge. We need to
22733  // loop through all edges of 'boundedgelist' for sure we don't miss any.
22734  for (i = 0; i < boundedgelist->len() && !crossflag; i++) {
22735  startsh = * (face *)(* boundedgelist)[i];
22736  // 'startsh' (abc) holds an existing edge of the DT, find it.
22737  torg = sorg(startsh);
22738  tdest = sdest(startsh);
22739  tapex = sapex(startsh);
22740  getsearchtet(torg, tdest, &starttet, &workpt[0]);
22741  collinear = finddirection(&starttet, workpt[0], tetrahedrons->items);
22742  if (collinear == LEFTCOLLINEAR) {
22743  enext2self(starttet);
22744  esymself(starttet);
22745  } else if (collinear == TOPCOLLINEAR) {
22746  fnextself(starttet);
22747  enext2self(starttet);
22748  esymself(starttet);
22749  }
22750 #ifdef SELF_CHECK
22751  assert(dest(starttet) == workpt[0]);
22752 #endif
22753  // Now starttet holds edge ab. Find is edge de crossing R.
22754  spintet = starttet;
22755  hitbdry = 0;
22756  do {
22757  if (fnextself(spintet)) {
22758  // splittet = abde. Check if de crosses abc.
22759  workpt[1] = apex(spintet); // workpt[1] = d.
22760  workpt[2] = oppo(spintet); // workpt[2] = e.
22761  j = pointmark(workpt[1]) - in->firstnumber;
22762  k = pointmark(workpt[2]) - in->firstnumber;
22763  if (worklist[j] == 1) {
22764  ori1 = 0.0; // d is a vertex of the missing region.
22765  } else {
22766  // Get the orientation of d wrt. abc.
22767  ori1 = orient3d(torg, tdest, tapex, workpt[1]);
22768  }
22769  if (worklist[k] == 1) {
22770  ori2 = 0.0; // e is a vertex of the missing region.
22771  } else {
22772  // Get the orientation of e wrt. abc.
22773  ori2 = orient3d(torg, tdest, tapex, workpt[2]);
22774  }
22775  // Only do check if d and e locate on different sides of abc.
22776  if (ori1 * ori2 < 0.0) {
22777  // Check if de crosses any subface of R.
22778  for (j = 0; j < missingshlist->len(); j++) {
22779  worksh = * (face *)(* missingshlist)[j];
22780  pa = sorg(worksh);
22781  pb = sdest(worksh);
22782  pc = sapex(worksh);
22783  crossflag = (tri_tri_inter(pa, pb, pc, workpt[0], workpt[1],
22784  workpt[2]) == INTERSECT);
22785  if (crossflag) {
22786  // Find a crossing edge. We're done.
22787  worktet = spintet;
22788  adjustedgering(worktet, CCW);
22789  enextfnextself(worktet);
22790  enextself(worktet);
22791  // Add this edge (worktet) into 'crossedgelist'.
22792  crossedgelist->append(&worktet);
22793  break;
22794  }
22795  }
22796  if (crossflag) break;
22797  }
22798  if (apex(spintet) == apex(starttet)) break;
22799  } else {
22800  hitbdry++;
22801  // It is only possible to hit boundary once.
22802  if (hitbdry < 2) {
22803  esym(starttet, spintet);
22804  }
22805  }
22806  } while (hitbdry < 2);
22807  }
22808 
22809  return crossflag;
22810 }
22811 
22813 // //
22814 // formcavity() Form the cavity for recovering the missing region. //
22815 // //
22816 // The cavity C is bounded by faces of current CDT. All tetrahedra inside C //
22817 // will be removed, intead a set of constrained Delaunay tetrahedra will be //
22818 // filled in and the missing region are recovered. //
22819 // //
22820 // 'missingshlist' contains a set of subfaces forming the missing region R. //
22821 // C is formed by first finding all the tetrahedra in CDT that intersect the //
22822 // relative interior of R; then deleting them from the CDT, this will form C //
22823 // inside the CDT. At the beginning, 'crossedgelist' contains an edge which //
22824 // is crossing R. All tets containing this edge must cross R. Start from it, //
22825 // other crossing edges can be found incrementally. The discovered crossing //
22826 // tets are saved in 'crosstetlist'. //
22827 // //
22828 // Notice that not all tets in 'crosstetlist' are crossing R. The discovered //
22829 // tets are connected each other. However, there may be other tets crossing //
22830 // R but disjoint with the found tets. Due to this fact we need to check the //
22831 // 'missingshlist' once more. Only recover those subfaces which are crossed //
22832 // by the set of discovered tets, i.e., R may be shrinked to conform the set //
22833 // of discovered tets. The extra subfaces of R will be recovered later. //
22834 // //
22835 // Notice that some previous recovered subfaces may completely included in C.//
22836 // This can happen when R is very big and these subfaces lie above R and so //
22837 // close to it. Such subfaces have to be queued (and sinfected()) to recover //
22838 // them later. Otherwise, we lost the connection to these subfaces forever. //
22839 // //
22841 
22842 void tetgenmesh::formcavity(list* missingshlist, list* crossedgelist,
22843  list* equatptlist, list* crossshlist, list* crosstetlist,
22844  list* belowfacelist, list* abovefacelist, list* horizptlist,
22845  list* belowptlist, list* aboveptlist, queue* missingshqueue, int* worklist)
22846 {
22847  triface starttet, spintet, neightet, worktet;
22848  face startsh, neighsh, worksh, workseg;
22849  point torg, tdest, tapex, workpt[3];
22850  REAL checksign, orgori, destori;
22851  bool crossflag, inlistflag;
22852  bool belowflag, aboveflag;
22853  int idx, share;
22854  int i, j, k;
22855 
22856  // Get a face at horizon.
22857  startsh = * (face *)(* missingshlist)[0];
22858  torg = sorg(startsh);
22859  tdest = sdest(startsh);
22860  tapex = sapex(startsh);
22861 
22862  // Collect the set of crossing tetrahedra by rotating crossing edges.
22863  for (i = 0; i < crossedgelist->len(); i++) {
22864  // Get a tet abcd, ab is a crossing edge.
22865  starttet = * (triface *)(* crossedgelist)[i];
22866  adjustedgering(starttet, CCW);
22867  if (b->verbose > 2) {
22868  printf(" Collect tets containing edge (%d, %d).\n",
22869  pointmark(org(starttet)), pointmark(dest(starttet)));
22870  }
22871  orgori = orient3d(torg, tdest, tapex, org(starttet));
22872  destori = orient3d(torg, tdest, tapex, dest(starttet));
22873  UNUSED_OPT(destori);
22874 #ifdef SELF_CHECK
22875  assert(orgori * destori < 0.0);
22876 #endif
22877  spintet = starttet;
22878  do {
22879  // The face rotation should not meet boundary.
22880  fnextself(spintet);
22881  // Check the validity of the PLC.
22882  tspivot(spintet, worksh);
22883  if (worksh.sh != dummysh) {
22884  printf("Error: Invalid PLC.\n");
22885  printf(" Two subfaces (%d, %d, %d) and (%d, %d, %d)\n",
22886  pointmark(torg), pointmark(tdest), pointmark(tapex),
22887  pointmark(sorg(worksh)), pointmark(sdest(worksh)),
22888  pointmark(sapex(worksh)));
22889  printf(" are found intersecting each other.\n");
22890  printf(" Hint: Use -d switch to find all intersecting facets.\n");
22891  terminatetetgen(1);
22892  }
22893  if (!infected(spintet)) {
22894  if (b->verbose > 2) {
22895  printf(" Add crossing tet (%d, %d, %d, %d).\n",
22896  pointmark(org(spintet)), pointmark(dest(spintet)),
22897  pointmark(apex(spintet)), pointmark(oppo(spintet)));
22898  }
22899  infect(spintet);
22900  crosstetlist->append(&spintet);
22901  }
22902  // Check whether other two edges of 'spintet' is a crossing edge.
22903  // It can be quickly checked from the apex of 'spintet', if it is
22904  // not on the facet, then there exists a crossing edge.
22905  workpt[0] = apex(spintet);
22906  idx = pointmark(workpt[0]) - in->firstnumber;
22907  if (worklist[idx] != 1) {
22908  // Either edge (dest, apex) or edge (apex, org) crosses.
22909  checksign = orient3d(torg, tdest, tapex, workpt[0]);
22910 #ifdef SELF_CHECK
22911  assert(checksign != 0.0);
22912 #endif
22913  if (checksign * orgori < 0.0) {
22914  enext2(spintet, worktet); // edge (apex, org).
22915  workpt[1] = org(spintet);
22916  } else {
22917 //#ifdef SELF_CHECK // commented out to get gcc 4.6 working
22918  assert(checksign * destori < 0.0);
22919 //#endif
22920  enext(spintet, worktet); // edge (dest, apex).
22921  workpt[1] = dest(spintet);
22922  }
22923  // 'worktet' represents the crossing edge. Add it into list only
22924  // it doesn't exist in 'crossedgelist'.
22925  inlistflag = false;
22926  for (j = 0; j < crossedgelist->len() && !inlistflag; j++) {
22927  neightet = * (triface *)(* crossedgelist)[j];
22928  if (org(neightet) == workpt[0]) {
22929  if (dest(neightet) == workpt[1]) inlistflag = true;
22930  } else if (org(neightet) == workpt[1]) {
22931  if (dest(neightet) == workpt[0]) inlistflag = true;
22932  }
22933  }
22934  if (!inlistflag) {
22935  crossedgelist->append(&worktet);
22936  }
22937  }
22938  } while (apex(spintet) != apex(starttet));
22939  }
22940 
22941  // Identifying the boundary faces and vertices of C. Sort them into
22942  // 'abovefacelist', 'aboveptlist, 'belowfacelist', and 'belowptlist',
22943  // respectively. "above" and "below" are wrt.(torg, tdest, tapex).
22944  for (i = 0; i < crosstetlist->len(); i++) {
22945  // Get a tet abcd, ab is the crossing edge.
22946  starttet = * (triface *)(* crosstetlist)[i];
22947 #ifdef SELF_CHECK
22948  assert(infected(starttet));
22949 #endif
22950  adjustedgering(starttet, CCW);
22951  // abc and abd are sharing the crossing edge, the two neighbors must
22952  // be crossing tetrahedra too. They can't be boundaries of C.
22953  for (j = 0; j < 2; j++) {
22954  if (j == 0) {
22955  enextfnext(starttet, worktet); // Check bcd.
22956  } else {
22957  enext2fnext(starttet, worktet); // Check acd.
22958  }
22959  sym(worktet, neightet);
22960  // If the neighbor doesn't exist or exists but doesn't be infected,
22961  // it's a boundary face of C, save it.
22962  if ((neightet.tet == dummytet) || !infected(neightet)) {
22963  workpt[0] = org(worktet);
22964  workpt[1] = dest(worktet);
22965  workpt[2] = apex(worktet);
22966  belowflag = aboveflag = false;
22967  share = 0;
22968  for (k = 0; k < 3; k++) {
22969  idx = pointmark(workpt[k]) - in->firstnumber;
22970  if (worklist[idx] == 0) {
22971  // It's not a vertices of facet, find which side it lies.
22972  checksign = orient3d(torg, tdest, tapex, workpt[k]);
22973 #ifdef SELF_CHECK
22974  assert(checksign != 0.0);
22975 #endif
22976  if (checksign > 0.0) {
22977  // It lies "below" the facet wrt. 'startsh'.
22978  worklist[idx] = 2;
22979  belowptlist->append(&workpt[k]);
22980  } else if (checksign < 0.0) {
22981  // It lies "above" the facet wrt. 'startsh'.
22982  worklist[idx] = 3;
22983  aboveptlist->append(&workpt[k]);
22984  }
22985  }
22986  if (worklist[idx] == 2) {
22987  // This face lies "below" the facet wrt. 'startsh'.
22988  belowflag = true;
22989  } else if (worklist[idx] == 3) {
22990  // This face lies "above" the facet wrt. 'startsh'.
22991  aboveflag = true;
22992  } else {
22993 #ifdef SELF_CHECK
22994  // In degenerate case, this face may just be the equator.
22995  assert(worklist[idx] == 1);
22996 #endif
22997  share++;
22998  }
22999  }
23000 #ifdef SELF_CHECK
23001  // The degenerate case has been ruled out.
23002  assert(share < 3);
23003  // Only one flag is possible for a cavity face.
23004  assert(belowflag ^ aboveflag);
23005 #endif
23006  if (belowflag) {
23007  belowfacelist->append(&worktet);
23008  } else if (aboveflag) {
23009  abovefacelist->append(&worktet);
23010  }
23011  }
23012  }
23013  }
23014 
23015  // Shrink R if not all its subfaces are crossing by the discovered tets.
23016  // 'crossshlist' and 'horizptlist' represent the set of subfaces and
23017  // vertices of the shrinked missing region, respectively.
23018  for (i = 0; i < missingshlist->len(); i++) {
23019  worksh = * (face *)(* missingshlist)[i];
23020 #ifdef SELF_CHECK
23021  assert(sinfected(worksh));
23022 #endif
23023  workpt[0] = sorg(worksh);
23024  workpt[1] = sdest(worksh);
23025  workpt[2] = sapex(worksh);
23026  crossflag = false;
23027  for (j = 0; j < crosstetlist->len() && !crossflag; j++) {
23028  // Get a tet abcd, ab is a crossing edge.
23029  starttet = * (triface *)(* crosstetlist)[j];
23030  adjustedgering(starttet, CCW);
23031  // Only need to check two sides of worktet.
23032  for (k = 0; k < 2 && !crossflag; k++) {
23033  if (k == 0) {
23034  worktet = starttet; // Check abc.
23035  } else {
23036  fnext(starttet, worktet); // Check abd.
23037  }
23038  crossflag = tritritest(&worktet, workpt[0], workpt[1], workpt[2]);
23039  }
23040  }
23041  if (crossflag) {
23042  // 'worksh' is crossed by 'worktet', uninfect it.
23043  suninfect(worksh);
23044  crossshlist->append(&worksh);
23045  // Add its corners into 'horizptlist'.
23046  for (k = 0; k < 3; k++) {
23047  idx = pointmark(workpt[k]) - in->firstnumber;
23048  if (worklist[idx] != 4) {
23049  worklist[idx] = 4;
23050  horizptlist->append(&workpt[k]);
23051  }
23052  }
23053  }
23054  }
23055 
23056  // Check 'crossingtetlist'. Queue subfaces inside them.
23057  for (i = 0; i < crosstetlist->len(); i++) {
23058  starttet = * (triface *)(* crosstetlist)[i];
23059  for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) {
23060  sym(starttet, neightet);
23061  // If the neighbor exist and is infected, check it.
23062  if ((neightet.tet != dummytet) && infected(neightet)) {
23063  tspivot(starttet, worksh);
23064  if (worksh.sh != dummysh) {
23065  // Temporarily remove worksh. Make it missing. recover it later.
23066  if (b->verbose > 2) {
23067  printf(" Queuing subface (%d, %d, %d).\n",
23068  pointmark(sorg(worksh)), pointmark(sdest(worksh)),
23069  pointmark(sapex(worksh)));
23070  }
23071  tsdissolve(neightet);
23072  tsdissolve(starttet);
23073  // Detach tets at the both sides of this subface.
23074  stdissolve(worksh);
23075  sesymself(worksh);
23076  stdissolve(worksh);
23077  sinfect(worksh);
23078  missingshqueue->push(&worksh);
23079  }
23080  }
23081  }
23082  }
23083 
23084  // Clear flags set in 'worklist'.
23085  for (i = 0; i < equatptlist->len(); i++) {
23086  workpt[0] = * (point *)(* equatptlist)[i];
23087  idx = pointmark(workpt[0]) - in->firstnumber;
23088 #ifdef SELF_CHECK
23089  assert((worklist[idx] == 1) || (worklist[idx] == 4));
23090 #endif
23091  worklist[idx] = 0;
23092  }
23093  for (i = 0; i < belowptlist->len(); i++) {
23094  workpt[0] = * (point *)(* belowptlist)[i];
23095  idx = pointmark(workpt[0]) - in->firstnumber;
23096 #ifdef SELF_CHECK
23097  assert(worklist[idx] == 2);
23098 #endif
23099  worklist[idx] = 0;
23100  }
23101  for (i = 0; i < aboveptlist->len(); i++) {
23102  workpt[0] = * (point *)(* aboveptlist)[i];
23103  idx = pointmark(workpt[0]) - in->firstnumber;
23104 #ifdef SELF_CHECK
23105  assert(worklist[idx] == 3);
23106 #endif
23107  worklist[idx] = 0;
23108  }
23109 }
23110 
23112 // //
23113 // insertallsubfaces() Insert all subfaces, queue missing subfaces. //
23114 // //
23115 // Loop through all subfaces, insert each into the DT. If one already exists,//
23116 // bond it to the tetrahedra having it. Otherwise, it is missing, infect it //
23117 // and save it in 'missingshqueue'. //
23118 // //
23120 
23121 void tetgenmesh::insertallsubfaces(queue* missingshqueue)
23122 {
23123  triface searchtet;
23124  face subloop;
23125 
23126  searchtet.tet = (tetrahedron *) NULL;
23127  subfaces->traversalinit();
23128  subloop.sh = shellfacetraverse(subfaces);
23129  while (subloop.sh != (shellface *) NULL) {
23130  if (!insertsubface(&subloop, &searchtet)) {
23131  if (b->verbose > 1) {
23132  printf(" Queuing subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
23133  pointmark(sdest(subloop)), pointmark(sapex(subloop)));
23134  }
23135  sinfect(subloop);
23136  missingshqueue->push(&subloop);
23137  }
23138  subloop.sh = shellfacetraverse(subfaces);
23139  }
23140 }
23141 
23143 // //
23144 // constrainedfacets() Recover subfaces in a Delaunay tetrahedralization. //
23145 // //
23146 // This routine creates a CDT by incrementally updating a DT D into a CDT T. //
23147 // The process of recovering facets can be imagined by "merging" the surface //
23148 // mesh F into D. At the beginning, F and D are completely seperated. Some //
23149 // faces of them are matching some are not because they are crossed by some //
23150 // tetrahedra of D. The non-matching subfaces will be forced to appear in T //
23151 // by locally retetrahedralizing the regions where F and D are intersecting. //
23152 // //
23153 // When a subface s of F is found missing in D, probably some other subfaces //
23154 // near to s are missing too. The set of adjoining coplanar missing faces //
23155 // forms a missing region R (R may not simply connected). //
23156 // //
23157 // There are two possibilities can result a mssing region R: (1) Some edges //
23158 // of D cross R; (2) No edge of D crosses R, but some faces of D spans R, ie,//
23159 // D is locally degenerate at R. In case (1), D is modified so that it resp- //
23160 // ects R (done by a cavity retetrahedralization algorithm). In case (2), F //
23161 // is modified so that the set of subfaces of R matches faces in D (done by //
23162 // a face rearrangment algorithm). //
23163 // //
23165 
23166 void tetgenmesh::constrainedfacets()
23167 {
23168  queue *missingshqueue, *flipque;
23169  list *missingshlist, *equatptlist;
23170  list *boundedgelist, *crossedgelist, *crosstetlist;
23171  list *crossshlist, *belowfacelist, *abovefacelist;
23172  list *horizptlist, *belowptlist, *aboveptlist;
23173  list *frontlist, *misfrontlist, *newtetlist;
23174  triface searchtet, worktet;
23175  face subloop, worksh;
23176  int *worklist;
23177  int i;
23178 
23179  if (!b->quiet) {
23180  printf("Constraining facets.\n");
23181  }
23182 
23183  // Initialize queues.
23184  missingshqueue = new queue(sizeof(face));
23185  flipque = new queue(sizeof(badface));
23186  // Initialize the working lists.
23187  missingshlist = new list(sizeof(face), NULL);
23188  boundedgelist = new list(sizeof(face), NULL);
23189  crossedgelist = new list(sizeof(triface), NULL);
23190  equatptlist = new list((char*) "point *");
23191  crossshlist = new list(sizeof(face), NULL);
23192  crosstetlist = new list(sizeof(triface), NULL);
23193  belowfacelist = new list(sizeof(triface), NULL);
23194  abovefacelist = new list(sizeof(triface), NULL);
23195  horizptlist = new list((char*)"point *");
23196  belowptlist = new list((char*)"point *");
23197  aboveptlist = new list((char*)"point *");
23198  frontlist = new list(sizeof(triface), NULL);
23199  misfrontlist = new list(sizeof(triface), NULL);
23200  newtetlist = new list(sizeof(triface), NULL);
23201  // Initialize the array for marking vertices.
23202  worklist = new int[points->items + 1];
23203  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
23204 
23205  // Compute a mapping from points to tetrahedra for fast searching.
23206  makepoint2tetmap();
23207 
23208  // Match subfaces in D, queue all missing subfaces.
23209  insertallsubfaces(missingshqueue);
23210 
23211  // Recover all missing subfaces.
23212  while (!missingshqueue->empty()) {
23213  // Get a queued face s.
23214  subloop = * (face *) missingshqueue->pop();
23215  // s may have been deleted in a face rearrangment operation.
23216  if (isdead(&subloop)) continue;
23217  // s may have been recovered in a previous missing region.
23218  if (!sinfected(subloop)) continue;
23219  // s may match a face in D now due to previous transformations.
23220  if (insertsubface(&subloop, &searchtet)) {
23221  suninfect(subloop);
23222  continue;
23223  }
23224  if (b->verbose > 1) {
23225  printf(" Recover subface (%d, %d, %d).\n", pointmark(sorg(subloop)),
23226  pointmark(sdest(subloop)), pointmark(sapex(subloop)));
23227  }
23228  // Form the missing region R containing s.
23229  formmissingregion(&subloop, missingshlist, equatptlist, worklist);
23230  // Is R crossing by any tetrahedron?
23231  if (scoutcrossingedge(missingshlist, boundedgelist, crossedgelist,
23232  worklist)) {
23233  // Form the cavity C containing R.
23234  formcavity(missingshlist, crossedgelist, equatptlist, crossshlist,
23235  crosstetlist, belowfacelist, abovefacelist, horizptlist,
23236  belowptlist, aboveptlist, missingshqueue, worklist);
23237  // Recover the above part of C.
23238  delaunizecavity(crossshlist, abovefacelist, aboveptlist, horizptlist,
23239  frontlist, misfrontlist, newtetlist, crosstetlist,
23240  missingshqueue, flipque);
23241  // Inverse the direction of subfaces in R.
23242  for (i = 0; i < crossshlist->len(); i++) {
23243  worksh = * (face *)(* crossshlist)[i];
23244  sesymself(worksh);
23245  * (face *)(* crossshlist)[i] = worksh;
23246  }
23247  // Recover the below part of C.
23248  delaunizecavity(crossshlist, belowfacelist, belowptlist, horizptlist,
23249  frontlist, misfrontlist, newtetlist, crosstetlist,
23250  missingshqueue, flipque);
23251  // Delete tetrahedra in C.
23252  for (i = 0; i < crosstetlist->len(); i++) {
23253  worktet = * (triface *)(* crosstetlist)[i];
23254  tetrahedrondealloc(worktet.tet);
23255  }
23256  // There may have some un-recovered subfaces of R. Put them back into
23257  // queue. Otherwise, they will be missing on the boundary.
23258  for (i = 0; i < missingshlist->len(); i++) {
23259  worksh = * (face *)(* missingshlist)[i];
23260  if (sinfected(worksh)) {
23261  // An unrecovered subface, put it back into queue.
23262  missingshqueue->push(&worksh);
23263  }
23264  }
23265  crossshlist->clear();
23266  belowfacelist->clear();
23267  abovefacelist->clear();
23268  horizptlist->clear();
23269  belowptlist->clear();
23270  aboveptlist->clear();
23271  crosstetlist->clear();
23272  } else {
23273  // No. Rearrange subfaces of F conforming to that of D in R. It can
23274  // happen when the facet has non-coplanar vertices.
23275  rearrangesubfaces(missingshlist, boundedgelist, equatptlist, worklist);
23276  }
23277  // Clear all working lists.
23278  missingshlist->clear();
23279  boundedgelist->clear();
23280  crossedgelist->clear();
23281  equatptlist->clear();
23282  }
23283 
23284  // Subfaces have been merged into D.
23285  checksubfaces = 1;
23286 
23287  if (b->verbose > 0) {
23288  printf(" The biggest cavity: %d faces, %d vertices\n", maxcavfaces,
23289  maxcavverts);
23290  printf(" Enlarged %d times\n", expcavcount);
23291  }
23292 
23293  delete missingshqueue;
23294  delete flipque;
23295  delete missingshlist;
23296  delete boundedgelist;
23297  delete crossedgelist;
23298  delete equatptlist;
23299  delete crossshlist;
23300  delete crosstetlist;
23301  delete belowfacelist;
23302  delete abovefacelist;
23303  delete horizptlist;
23304  delete belowptlist;
23305  delete aboveptlist;
23306  delete frontlist;
23307  delete misfrontlist;
23308  delete newtetlist;
23309  delete [] worklist;
23310 }
23311 
23312 //
23313 // End of facet recovery routines
23314 //
23315 
23316 //
23317 // Begin of carving out holes and concavities routines
23318 //
23319 
23321 // //
23322 // infecthull() Virally infect all of the tetrahedra of the convex hull //
23323 // that are not protected by subfaces. Where there are //
23324 // subfaces, set boundary markers as appropriate. //
23325 // //
23326 // Memorypool 'viri' is used to return all the infected tetrahedra. //
23327 // //
23329 
23330 void tetgenmesh::infecthull(memorypool *viri)
23331 {
23332  triface tetloop, tsymtet;
23333  tetrahedron **deadtet;
23334  face hullface;
23335  // point horg, hdest, hapex;
23336 
23337  if (b->verbose > 0) {
23338  printf(" Marking concavities for elimination.\n");
23339  }
23340  tetrahedrons->traversalinit();
23341  tetloop.tet = tetrahedrontraverse();
23342  while (tetloop.tet != (tetrahedron *) NULL) {
23343  // Is this tetrahedron on the hull?
23344  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
23345  sym(tetloop, tsymtet);
23346  if (tsymtet.tet == dummytet) {
23347  // Is the tetrahedron protected by a subface?
23348  tspivot(tetloop, hullface);
23349  if (hullface.sh == dummysh) {
23350  // The tetrahedron is not protected; infect it.
23351  if (!infected(tetloop)) {
23352  infect(tetloop);
23353  deadtet = (tetrahedron **) viri->alloc();
23354  *deadtet = tetloop.tet;
23355  break; // Go and get next tet.
23356  }
23357  } else {
23358  // The tetrahedron is protected; set boundary markers if appropriate.
23359  if (shellmark(hullface) == 0) {
23360  setshellmark(hullface, 1);
23361  /*
23362  horg = sorg(hullface);
23363  hdest = sdest(hullface);
23364  hapex = sapex(hullface);
23365  if (pointmark(horg) == 0) {
23366  setpointmark(horg, 1);
23367  }
23368  if (pointmark(hdest) == 0) {
23369  setpointmark(hdest, 1);
23370  }
23371  if (pointmark(hapex) == 0) {
23372  setpointmark(hapex, 1);
23373  }
23374  */
23375  }
23376  }
23377  }
23378  }
23379  tetloop.tet = tetrahedrontraverse();
23380  }
23381 }
23382 
23384 // //
23385 // plague() Spread the virus from all infected tets to any neighbors not //
23386 // protected by subfaces. //
23387 // //
23388 // This routine identifies all the tetrahedra that will die, and marks them //
23389 // as infected. They are marked to ensure that each tetrahedron is added to //
23390 // the virus pool only once, so the procedure will terminate. 'viri' returns //
23391 // all infected tetrahedra which are outside the domian. //
23392 // //
23394 
23395 void tetgenmesh::plague(memorypool *viri)
23396 {
23397  tetrahedron **virusloop;
23398  tetrahedron **deadtet;
23399  triface testtet, neighbor;
23400  face neighsh, testseg;
23401  face spinsh, casingin, casingout;
23402  int firstdadsub;
23403  int i;
23404 
23405  if (b->verbose > 0) {
23406  printf(" Marking neighbors of marked tetrahedra.\n");
23407  }
23408  firstdadsub = 0;
23409  // Loop through all the infected tetrahedra, spreading the virus to
23410  // their neighbors, then to their neighbors' neighbors.
23411  viri->traversalinit();
23412  virusloop = (tetrahedron **) viri->traverse();
23413  while (virusloop != (tetrahedron **) NULL) {
23414  testtet.tet = *virusloop;
23415  // Temporarily uninfect this tetrahedron, not necessary.
23416  uninfect(testtet);
23417  // Check each of the tetrahedron's four neighbors.
23418  for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23419  // Find the neighbor.
23420  sym(testtet, neighbor);
23421  // Check for a shell between the tetrahedron and its neighbor.
23422  tspivot(testtet, neighsh);
23423  // Check if the neighbor is nonexistent or already infected.
23424  if ((neighbor.tet == dummytet) || infected(neighbor)) {
23425  if (neighsh.sh != dummysh) {
23426  // There is a subface separating the tetrahedron from its neighbor,
23427  // but both tetrahedra are dying, so the subface dies too.
23428  // Before deallocte this subface, dissolve the connections between
23429  // other subfaces, subsegments and tetrahedra.
23430  neighsh.shver = 0;
23431  if (!firstdadsub) {
23432  firstdadsub = 1; // Report the problem once.
23433  if (!b->quiet) {
23434  printf("Warning: Detecting an open face (%d, %d, %d).\n",
23435  pointmark(sorg(neighsh)), pointmark(sdest(neighsh)),
23436  pointmark(sapex(neighsh)));
23437  }
23438  }
23439  // For keep the same enext() direction.
23440  findedge(&testtet, sorg(neighsh), sdest(neighsh));
23441  for (i = 0; i < 3; i++) {
23442  sspivot(neighsh, testseg);
23443  if (testseg.sh != dummysh) {
23444  // A subsegment is found at this side, dissolve this subface
23445  // from the face link of this subsegment.
23446  testseg.shver = 0;
23447  spinsh = neighsh;
23448  if (sorg(spinsh) != sorg(testseg)) {
23449  sesymself(spinsh);
23450  }
23451  spivot(spinsh, casingout);
23452  if (casingout.sh == spinsh.sh) {
23453  // This is a trivial face link, only 'neighsh' itself,
23454  // the subsegment at this side is also died.
23455  shellfacedealloc(subsegs, testseg.sh);
23456  } else {
23457  spinsh = casingout;
23458  do {
23459  casingin = spinsh;
23460  spivotself(spinsh);
23461  } while (spinsh.sh != neighsh.sh);
23462  // Set the link casingin->casingout.
23463  sbond1(casingin, casingout);
23464  // Bond the subsegment anyway.
23465  ssbond(casingin, testseg);
23466  }
23467  }
23468  senextself(neighsh);
23469  enextself(testtet);
23470  }
23471  if (neighbor.tet != dummytet) {
23472  // Make sure the subface doesn't get deallocated again later
23473  // when the infected neighbor is visited.
23474  tsdissolve(neighbor);
23475  }
23476  // This subface has been separated.
23477  if (in->mesh_dim > 2) {
23478  shellfacedealloc(subfaces, neighsh.sh);
23479  } else {
23480  // Dimension is 2. keep it for output.
23481  // Dissolve tets at both sides of this subface.
23482  stdissolve(neighsh);
23483  sesymself(neighsh);
23484  stdissolve(neighsh);
23485  }
23486  }
23487  } else { // The neighbor exists and is not infected.
23488  if (neighsh.sh == dummysh) {
23489  // There is no subface protecting the neighbor, infect it.
23490  infect(neighbor);
23491  // Ensure that the neighbor's neighbors will be infected.
23492  deadtet = (tetrahedron **) viri->alloc();
23493  *deadtet = neighbor.tet;
23494  } else { // The neighbor is protected by a subface.
23495  // Remove this tetrahedron from the subface.
23496  stdissolve(neighsh);
23497  // The subface becomes a boundary. Set markers accordingly.
23498  if (shellmark(neighsh) == 0) {
23499  setshellmark(neighsh, 1);
23500  }
23501  // This side becomes hull. Update the handle in dummytet.
23502  dummytet[0] = encode(neighbor);
23503  }
23504  }
23505  }
23506  // Remark the tetrahedron as infected, so it doesn't get added to the
23507  // virus pool again.
23508  infect(testtet);
23509  virusloop = (tetrahedron **) viri->traverse();
23510  }
23511 }
23512 
23514 // //
23515 // regionplague() Spread regional attributes and/or volume constraints //
23516 // (from a .poly file) throughout the mesh. //
23517 // //
23518 // This procedure operates in two phases. The first phase spreads an attri- //
23519 // bute and/or a volume constraint through a (facet-bounded) region. The //
23520 // second phase uninfects all infected tetrahedra, returning them to normal. //
23521 // //
23523 
23524 void tetgenmesh::
23525 regionplague(memorypool *regionviri, REAL attribute, REAL volume)
23526 {
23527  tetrahedron **virusloop;
23528  tetrahedron **regiontet;
23529  triface testtet, neighbor;
23530  face neighsh;
23531 
23532  if (b->verbose > 1) {
23533  printf(" Marking neighbors of marked tetrahedra.\n");
23534  }
23535  // Loop through all the infected tetrahedra, spreading the attribute
23536  // and/or volume constraint to their neighbors, then to their neighbors'
23537  // neighbors.
23538  regionviri->traversalinit();
23539  virusloop = (tetrahedron **) regionviri->traverse();
23540  while (virusloop != (tetrahedron **) NULL) {
23541  testtet.tet = *virusloop;
23542  // Temporarily uninfect this tetrahedron, not necessary.
23543  uninfect(testtet);
23544  if (b->regionattrib) {
23545  // Set an attribute.
23546  setelemattribute(testtet.tet, in->numberoftetrahedronattributes,
23547  attribute);
23548  }
23549  if (b->varvolume) {
23550  // Set a volume constraint.
23551  setvolumebound(testtet.tet, volume);
23552  }
23553  // Check each of the tetrahedron's four neighbors.
23554  for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23555  // Find the neighbor.
23556  sym(testtet, neighbor);
23557  // Check for a subface between the tetrahedron and its neighbor.
23558  tspivot(testtet, neighsh);
23559  // Make sure the neighbor exists, is not already infected, and
23560  // isn't protected by a subface, or is protected by a nonsolid
23561  // subface.
23562  if ((neighbor.tet != dummytet) && !infected(neighbor)
23563  && (neighsh.sh == dummysh)) {
23564  // Infect the neighbor.
23565  infect(neighbor);
23566  // Ensure that the neighbor's neighbors will be infected.
23567  regiontet = (tetrahedron **) regionviri->alloc();
23568  *regiontet = neighbor.tet;
23569  }
23570  }
23571  // Remark the tetrahedron as infected, so it doesn't get added to the
23572  // virus pool again.
23573  infect(testtet);
23574  virusloop = (tetrahedron **) regionviri->traverse();
23575  }
23576 
23577  // Uninfect all tetrahedra.
23578  if (b->verbose > 1) {
23579  printf(" Unmarking marked tetrahedra.\n");
23580  }
23581  regionviri->traversalinit();
23582  virusloop = (tetrahedron **) regionviri->traverse();
23583  while (virusloop != (tetrahedron **) NULL) {
23584  testtet.tet = *virusloop;
23585  uninfect(testtet);
23586  virusloop = (tetrahedron **) regionviri->traverse();
23587  }
23588  // Empty the virus pool.
23589  regionviri->restart();
23590 }
23591 
23593 // //
23594 // removeholetets() Remove tetrahedra which are outside the domain. //
23595 // //
23597 
23598 void tetgenmesh::removeholetets(memorypool* viri)
23599 {
23600  tetrahedron **virusloop;
23601  triface testtet, neighbor;
23602  point checkpt;
23603  int *tetspernodelist;
23604  int i, j;
23605 
23606  if (b->verbose > 0) {
23607  printf(" Deleting marked tetrahedra.\n");
23608  }
23609 
23610  // Create and initialize 'tetspernodelist'.
23611  tetspernodelist = new int[points->items + 1];
23612  for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0;
23613 
23614  // Loop the tetrahedra list, counter the number of tets sharing each node.
23615  tetrahedrons->traversalinit();
23616  testtet.tet = tetrahedrontraverse();
23617  while (testtet.tet != (tetrahedron *) NULL) {
23618  // Increment the number of sharing tets for each endpoint.
23619  for (i = 0; i < 4; i++) {
23620  j = pointmark((point) testtet.tet[4 + i]);
23621  tetspernodelist[j]++;
23622  }
23623  testtet.tet = tetrahedrontraverse();
23624  }
23625 
23626  viri->traversalinit();
23627  virusloop = (tetrahedron **) viri->traverse();
23628  while (virusloop != (tetrahedron **) NULL) {
23629  testtet.tet = *virusloop;
23630  // Record changes in the number of boundary faces, and disconnect
23631  // dead tetrahedra from their neighbors.
23632  for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) {
23633  sym(testtet, neighbor);
23634  if (neighbor.tet == dummytet) {
23635  // There is no neighboring tetrahedron on this face, so this face
23636  // is a boundary face. This tetrahedron is being deleted, so this
23637  // boundary face is deleted.
23638  hullsize--;
23639  } else {
23640  // Disconnect the tetrahedron from its neighbor.
23641  dissolve(neighbor);
23642  // There is a neighboring tetrahedron on this face, so this face
23643  // becomes a boundary face when this tetrahedron is deleted.
23644  hullsize++;
23645  }
23646  }
23647  // Check the four corners of this tet if they're isolated.
23648  for (i = 0; i < 4; i++) {
23649  checkpt = (point) testtet.tet[4 + i];
23650  j = pointmark(checkpt);
23651  tetspernodelist[j]--;
23652  if (tetspernodelist[j] == 0) {
23653  // If it is added volume vertex or '-j' is not used, delete it.
23654  if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) {
23655  setpointtype(checkpt, UNUSEDVERTEX);
23656  unuverts++;
23657  }
23658  }
23659  }
23660  // Return the dead tetrahedron to the pool of tetrahedra.
23661  tetrahedrondealloc(testtet.tet);
23662  virusloop = (tetrahedron **) viri->traverse();
23663  }
23664 
23665  delete [] tetspernodelist;
23666 }
23667 
23669 // //
23670 // assignregionattribs() Assign each tetrahedron a region number. //
23671 // //
23672 // This routine is called when '-AA' switch is specified. Every tetrahedron //
23673 // of a (bounded) region will get a integer number to that region. Default, //
23674 // regions are numbered as 1, 2, 3, etc. However, if a number has already //
23675 // been used (set by user in the region section in .poly or .smesh), it is //
23676 // skipped and the next available number will be used. //
23677 // //
23679 
23680 void tetgenmesh::assignregionattribs()
23681 {
23682  list *regionnumlist;
23683  list *regiontetlist;
23684  triface tetloop, regiontet, neightet;
23685  face checksh;
23686  bool flag;
23687  int regionnum, num;
23688  int attridx, count;
23689  int i;
23690 
23691  if (b->verbose > 0) {
23692  printf(" Assign region numbers.\n");
23693  }
23694 
23695  regionnumlist = new list(sizeof(int), NULL, 256);
23696  regiontetlist = new list(sizeof(triface), NULL, 1024);
23697  attridx = in->numberoftetrahedronattributes;
23698 
23699  // Loop through all tets. Infect tets which already have a region number,
23700  // and save the used numbers in 'regionnumlist'.
23701  tetrahedrons->traversalinit();
23702  tetloop.tet = tetrahedrontraverse();
23703  while (tetloop.tet != (tetrahedron *) NULL) {
23704  if (!infected(tetloop)) {
23705  regionnum = (int) elemattribute(tetloop.tet, attridx);
23706  if (regionnum != 0.0) {
23707  // Found a numbered region tet.
23708  infect(tetloop);
23709  regiontetlist->append(&tetloop);
23710  // Found and infect all tets in this region.
23711  for (i = 0; i < regiontetlist->len(); i++) {
23712  regiontet = * (triface *)(* regiontetlist)[i];
23713  for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
23714  // Is there a boundary face?
23715  tspivot(regiontet, checksh);
23716  if (checksh.sh == dummysh) {
23717  sym(regiontet, neightet);
23718  if ((neightet.tet != dummytet) && !infected(neightet)) {
23719 #ifdef SELF_CHECK
23720  // neightet should have the same region number. Check it.
23721  num = (int) elemattribute(neightet.tet, attridx);
23722  assert(num == regionnum);
23723 #endif
23724  infect(neightet);
23725  regiontetlist->append(&neightet);
23726  }
23727  }
23728  }
23729  }
23730  // Add regionnum to list if it is not exist.
23731  flag = false;
23732  for (i = 0; i < regionnumlist->len() && !flag; i++) {
23733  num = * (int *)(* regionnumlist)[i];
23734  flag = (num == regionnum);
23735  }
23736  if (!flag) regionnumlist->append(&regionnum);
23737  // Clear list for the next region.
23738  regiontetlist->clear();
23739  }
23740  }
23741  tetloop.tet = tetrahedrontraverse();
23742  }
23743 
23744  if (b->verbose > 0) {
23745  printf(" %d user-specified regions.\n", regionnumlist->len());
23746  }
23747 
23748  // Now loop the tets again. Assign region numbers to uninfected tets.
23749  tetrahedrons->traversalinit();
23750  tetloop.tet = tetrahedrontraverse();
23751  regionnum = 1; // Start region number.
23752  count = 0;
23753  while (tetloop.tet != (tetrahedron *) NULL) {
23754  if (!infected(tetloop)) {
23755  // An unassigned region tet.
23756  count++;
23757  do {
23758  flag = false;
23759  // Check if the region number has been used.
23760  for (i = 0; i < regionnumlist->len() && !flag; i++) {
23761  num = * (int *)(* regionnumlist)[i];
23762  flag = (num == regionnum);
23763  }
23764  if (flag) regionnum++;
23765  } while (flag);
23766  setelemattribute(tetloop.tet, attridx, (REAL) regionnum);
23767  infect(tetloop);
23768  regiontetlist->append(&tetloop);
23769  // Found and infect all tets in this region.
23770  for (i = 0; i < regiontetlist->len(); i++) {
23771  regiontet = * (triface *)(* regiontetlist)[i];
23772  for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) {
23773  // Is there a boundary face?
23774  tspivot(regiontet, checksh);
23775  if (checksh.sh == dummysh) {
23776  sym(regiontet, neightet);
23777  if ((neightet.tet != dummytet) && !infected(neightet)) {
23778 #ifdef SELF_CHECK
23779  // neightet should have not been assigned yet. Check it.
23780  num = (int) elemattribute(neightet.tet, attridx);
23781  assert(num == 0);
23782 #endif
23783  setelemattribute(neightet.tet, attridx, (REAL) regionnum);
23784  infect(neightet);
23785  regiontetlist->append(&neightet);
23786  }
23787  }
23788  }
23789  }
23790  regiontetlist->clear();
23791  regionnum++; // The next region number.
23792  }
23793  tetloop.tet = tetrahedrontraverse();
23794  }
23795 
23796  // Uninfect all tets.
23797  tetrahedrons->traversalinit();
23798  tetloop.tet = tetrahedrontraverse();
23799  while (tetloop.tet != (tetrahedron *) NULL) {
23800 #ifdef SELF_CHECK
23801  assert(infected(tetloop));
23802 #endif
23803  uninfect(tetloop);
23804  tetloop.tet = tetrahedrontraverse();
23805  }
23806 
23807  if (b->verbose > 0) {
23808  printf(" %d regions are numbered.\n", count);
23809  }
23810 
23811  delete regionnumlist;
23812  delete regiontetlist;
23813 }
23814 
23816 // //
23817 // carveholes() Find the holes and infect them. Find the volume //
23818 // constraints and infect them. Infect the convex hull. //
23819 // Spread the infection and kill tetrahedra. Spread the //
23820 // volume constraints. //
23821 // //
23822 // This routine mainly calls other routines to carry out all these functions.//
23823 // //
23825 
23826 void tetgenmesh::carveholes()
23827 {
23828  memorypool *holeviri, *regionviri;
23829  tetrahedron *tptr, **holetet, **regiontet;
23830  triface searchtet, *holetets, *regiontets;
23831  enum locateresult intersect;
23832  int i;
23833 
23834  if (!b->quiet) {
23835  printf("Removing unwanted tetrahedra.\n");
23836  if (b->verbose && (in->numberofholes > 0)) {
23837  printf(" Marking holes for elimination.\n");
23838  }
23839  }
23840 
23841  // Initialize a pool of viri to be used for holes, concavities.
23842  holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
23843  // Mark as infected any unprotected tetrahedra on the boundary.
23844  infecthull(holeviri);
23845 
23846  if (in->numberofholes > 0) {
23847  // Allocate storage for the tetrahedra in which hole points fall.
23848  holetets = (triface *) new triface[in->numberofholes];
23849  // Infect each tetrahedron in which a hole lies.
23850  for (i = 0; i < 3 * in->numberofholes; i += 3) {
23851  // Ignore holes that aren't within the bounds of the mesh.
23852  if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax)
23853  && (in->holelist[i + 1] >= ymin)
23854  && (in->holelist[i + 1] <= ymax)
23855  && (in->holelist[i + 2] >= zmin)
23856  && (in->holelist[i + 2] <= zmax)) {
23857  searchtet.tet = dummytet;
23858  // Find a tetrahedron that contains the hole.
23859  intersect = locate(&in->holelist[i], &searchtet);
23860  if ((intersect != OUTSIDE) && (!infected(searchtet))) {
23861  // Record the tetrahedron for processing carve hole.
23862  holetets[i / 3] = searchtet;
23863  }
23864  }
23865  }
23866  // Infect the hole tetrahedron. This is done by marking the tet as
23867  // infected and including the tetrahedron in the virus pool.
23868  for (i = 0; i < in->numberofholes; i++) {
23869  infect(holetets[i]);
23870  holetet = (tetrahedron **) holeviri->alloc();
23871  *holetet = holetets[i].tet;
23872  }
23873  // Free up memory.
23874  delete [] holetets;
23875  }
23876 
23877  // Mark as infected all tets of the holes and concavities.
23878  plague(holeviri);
23879  // The virus pool contains all outside tets now.
23880 
23881  // Is -A switch in use.
23882  if (b->regionattrib) {
23883  // Assign every tetrahedron a regional attribute of zero.
23884  tetrahedrons->traversalinit();
23885  tptr = tetrahedrontraverse();
23886  while (tptr != (tetrahedron *) NULL) {
23887  setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0);
23888  tptr = tetrahedrontraverse();
23889  }
23890  }
23891 
23892  if (in->numberofregions > 0) {
23893  if (!b->quiet) {
23894  if (b->regionattrib) {
23895  if (b->varvolume) {
23896  printf("Spreading regional attributes and volume constraints.\n");
23897  } else {
23898  printf("Spreading regional attributes.\n");
23899  }
23900  } else {
23901  printf("Spreading regional volume constraints.\n");
23902  }
23903  }
23904  // Allocate storage for the tetrahedra in which region points fall.
23905  regiontets = (triface *) new triface[in->numberofregions];
23906  // Find the starting tetrahedron for each region.
23907  for (i = 0; i < in->numberofregions; i++) {
23908  regiontets[i].tet = dummytet;
23909  // Ignore region points that aren't within the bounds of the mesh.
23910  if ((in->regionlist[5 * i] >= xmin)
23911  && (in->regionlist[5 * i] <= xmax)
23912  && (in->regionlist[5 * i + 1] >= ymin)
23913  && (in->regionlist[5 * i + 1] <= ymax)
23914  && (in->regionlist[5 * i + 2] >= zmin)
23915  && (in->regionlist[5 * i + 2] <= zmax)) {
23916  searchtet.tet = dummytet;
23917  // Find a tetrahedron that contains the region point.
23918  intersect = locate(&in->regionlist[5 * i], &searchtet);
23919  if ((intersect != OUTSIDE) && (!infected(searchtet))) {
23920  // Record the tetrahedron for processing after the
23921  // holes have been carved.
23922  regiontets[i] = searchtet;
23923  }
23924  }
23925  }
23926  // Initialize a pool to be used for regional attrs, and/or regional
23927  // volume constraints.
23928  regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0);
23929  // Find and set all regions.
23930  for (i = 0; i < in->numberofregions; i++) {
23931  if (regiontets[i].tet != dummytet) {
23932  // Make sure the tetrahedron under consideration still exists.
23933  // It may have been eaten by the virus.
23934  if (!isdead(&(regiontets[i]))) {
23935  // Put one tetrahedron in the virus pool.
23936  infect(regiontets[i]);
23937  regiontet = (tetrahedron **) regionviri->alloc();
23938  *regiontet = regiontets[i].tet;
23939  // Apply one region's attribute and/or volume constraint.
23940  regionplague(regionviri, in->regionlist[5 * i + 3],
23941  in->regionlist[5 * i + 4]);
23942  // The virus pool should be empty now.
23943  }
23944  }
23945  }
23946  // Free up memory.
23947  delete [] regiontets;
23948  delete regionviri;
23949  }
23950 
23951  // Now acutually remove the outside and hole tets.
23952  removeholetets(holeviri);
23953  // The mesh is nonconvex now.
23954  nonconvex = 1;
23955 
23956  if (b->regionattrib) {
23957  if (b->regionattrib > 1) {
23958  // -AA switch. Assign each tet a region number (> 0).
23959  assignregionattribs();
23960  }
23961  // Note the fact that each tetrahedron has an additional attribute.
23962  in->numberoftetrahedronattributes++;
23963  }
23964 
23965  // Free up memory.
23966  delete holeviri;
23967 }
23968 
23969 //
23970 // End of carving out holes and concavities routines
23971 //
23972 
23973 //
23974 // Begin of boundary Steiner points removing routines
23975 //
23976 
23978 // //
23979 // replacepolygonsubs() Substitute the subfaces of a polygon. //
23980 // //
23981 // 'oldshlist' (T_old) contains the old subfaces of P. It will be replaced //
23982 // by 'newshlist' (T_new) of new subfaces. Each boundary edge of P is bonded //
23983 // to 'dummysh' in T_new. //
23984 // //
23985 // Notice that Not every boundary edge of T_new is able to bond to a subface,//
23986 // e.g., when it is a segment recovered by removing a Steiner point in it. //
23987 // //
23989 
23990 void tetgenmesh::replacepolygonsubs(list* oldshlist, list* newshlist)
23991 {
23992  face newsh, oldsh, spinsh;
23993  face casingout, casingin;
23994  face checkseg;
23995  point pa, pb;
23996  int i, j, k, l;
23997 
23998  for (i = 0; i < newshlist->len(); i++) {
23999  // Get a new subface s.
24000  newsh = * (face *)(* newshlist)[i];
24001  // Check the three edges of s.
24002  for (k = 0; k < 3; k++) {
24003  spivot(newsh, casingout);
24004  // Is it a boundary edge?
24005  if (casingout.sh == dummysh) {
24006  // Find the old subface s_o having the same edge as s.
24007  pa = sorg(newsh);
24008  pb = sdest(newsh);
24009  for (j = 0; j < oldshlist->len(); j++) {
24010  oldsh = * (face *)(* oldshlist)[j];
24011  for (l = 0; l < 3; l++) {
24012  if (((sorg(oldsh) == pa) && (sdest(oldsh) == pb)) ||
24013  ((sorg(oldsh) == pb) && (sdest(oldsh) == pa))) break;
24014  senextself(oldsh);
24015  }
24016  if (l < 3) break;
24017  }
24018  // Is there a matched edge?
24019  if (j < oldshlist->len()) {
24020  // Get the neighbor subface s_out.
24021  spivot(oldsh, casingout);
24022  sspivot(oldsh, checkseg);
24023  if (checkseg.sh != dummysh) {
24024  // A segment. Insert s into the face ring, ie, s_in -> s -> s_out.
24025  if (oldsh.sh != casingout.sh) {
24026  // s is not bonded to itself.
24027  spinsh = casingout;
24028  do {
24029  casingin = spinsh;
24030  spivotself(spinsh);
24031  } while (sapex(spinsh) != sapex(oldsh));
24032  assert(casingin.sh != oldsh.sh);
24033  // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out).
24034  sbond1(casingin, newsh);
24035  sbond1(newsh, casingout);
24036  } else {
24037  // Bond newsh -> newsh.
24038  sbond(newsh, newsh);
24039  }
24040  // Bond the segment.
24041  ssbond(newsh, checkseg);
24042  } else {
24043  // Bond s <-> s_out (and dissolve s_out -> s_old).
24044  sbond(newsh, casingout);
24045  }
24046  // Unbound oldsh to indicate it's neighbor has been replaced.
24047  // It will be used to indentfy the edge in the inverse.
24048  sdissolve(oldsh);
24049  ssdissolve(oldsh);
24050  }
24051  }
24052  // Go to the next edge of s.
24053  senextself(newsh);
24054  }
24055  }
24056 }
24057 
24059 // //
24060 // orientnewsubs() Orient new subfaces facing to the inside of cavity. //
24061 // //
24062 // 'newshlist' contains new subfaces of the cavity C (created by re-triangu- //
24063 // lation the polygon P). They're not necessary facing to the inside of C. //
24064 // 'orientsh', faces to the inside of C, is used to adjust new subfaces. The //
24065 // normal of the new subfaces is returned in 'norm'. //
24066 // //
24068 
24069 void tetgenmesh::orientnewsubs(list* newshlist, face* orientsh, REAL* norm)
24070 {
24071  face *newsh;
24072  point pa, pb, pc;
24073  REAL ref[3], ori, len;
24074  int i;
24075 
24076  // Calculate the normal of 'orientsh'.
24077  pa = sorg(*orientsh);
24078  pb = sdest(*orientsh);
24079  pc = sapex(*orientsh);
24080  facenormal(pa, pb, pc, norm, &len);
24081  for (i = 0; i < 3; i++) ref[i] = pa[i] + norm[i];
24082  for (i = 0; i < 3; i++) norm[i] /= len;
24083 
24084  // Orient new subfaces. Let the normal above each one.
24085  for (i = 0; i < newshlist->len(); i++) {
24086  newsh = (face *)(* newshlist)[i];
24087  pa = sorg(*newsh);
24088  pb = sdest(*newsh);
24089  pc = sapex(*newsh);
24090  ori = orient3d(pa, pb, pc, ref);
24091  assert(ori != 0.0);
24092  if (ori > 0.0) {
24093  sesymself(*newsh);
24094  }
24095  }
24096 }
24097 
24099 // //
24100 // constrainedflip() Flip a non-constrained face. //
24101 // //
24102 // 'flipface' f (abc) is a face we want to flip. In addition, if 'front' is //
24103 // given (not a NULL), f is a crossface. f may not be flippable if it is one //
24104 // of the following cases: //
24105 // (1) f has an aux subface attached; //
24106 // (2) f is on the convex hull; //
24107 // (3) f is not locally Delaunay (f must be recovered by a previous flip, //
24108 // we should keep it, otherwise, we may fall into a flip loop); //
24109 // (4) f is T32 at ab, but abd or abe has an aux subface attached; //
24110 // (5) f is T22 or T44 at ab, but abd, or abe, or abf has an aux subface //
24111 // attached; //
24112 // (6) f is unflipable at ab, and abd, abe, ... are all unflippable due to //
24113 // the cases (1) - (5). //
24114 // If f is a crssface ('front' != NULL) and it is unflipable due to case (3),//
24115 // (4), (5) and (6). Try to flip the next crossing face of front first. //
24116 // //
24118 
24119 bool tetgenmesh::constrainedflip(triface* flipface, triface* front,
24120  queue* flipque)
24121 {
24122  triface symface, spintet;
24123  face checksh;
24124  point pa, pb, pc, pd, pe;
24125  enum fliptype fc;
24126  REAL sign;
24127  bool doflip;
24128  int ia, ib, ic, id, ie;
24129  int i;
24130 
24131  // (1) Is f protected by an (auxilary) subface?
24132  tspivot(*flipface, checksh);
24133  if (checksh.sh != dummysh) return false;
24134  // (2) Is f on the convex hull?
24135  sym(*flipface, symface);
24136  if (symface.tet == dummytet) return false;
24137  // (3) Is f not locally Delaunay?
24138  adjustedgering(*flipface, CCW);
24139  pa = dest(*flipface);
24140  pb = org(*flipface);
24141  pc = apex(*flipface);
24142  pd = oppo(*flipface);
24143  pe = oppo(symface);
24144  // if (symbolic) {
24145  ia = pointmark(pa);
24146  ib = pointmark(pb);
24147  ic = pointmark(pc);
24148  id = pointmark(pd);
24149  ie = pointmark(pe);
24150  sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
24151  assert(sign != 0.0);
24152  // } else {
24153  // sign = insphere(pa, pb, pc, pd, pe);
24154  // }
24155  if (sign <= 0.0) {
24156  // Get the fliptype of f.
24157  checksubfaces = 0; // switch off subface test.
24158  fc = categorizeface(*flipface);
24159  checksubfaces = 1; // switch on subface test.
24160  if (fc == T23) {
24161  doflip = true;
24162  // Avoid one tet created by the 2-3 flip is nearly degenerate.
24163  /* pc = oppo(*flipface);
24164  pd = oppo(symface);
24165  adjustedgering(*flipface, CCW);
24166  for (i = 0; i < 3; i++) {
24167  pa = org(*flipface);
24168  pb = dest(*flipface);
24169  ori = orient3d(pa, pb, pc, pd);
24170  if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
24171  doflip = false; break;
24172  }
24173  enextself(*flipface);
24174  } */
24175  if (doflip) {
24176  flip23(flipface, flipque);
24177  return true;
24178  }
24179  } else if (fc == T32) {
24180  // (4) Is abd, or abe protected?
24181  doflip = true;
24182  spintet = *flipface;
24183  for (i = 0; i < 2; i++) {
24184  fnextself(spintet);
24185  tspivot(spintet, checksh);
24186  if (checksh.sh != dummysh) {
24187  doflip = false; break; // f is protected. Unflipable.
24188  }
24189  }
24190  if (doflip) {
24191  flip32(flipface, flipque);
24192  return true;
24193  }
24194  } else if (fc == T22 || fc == T44) {
24195  // (5) Is abd, abe, or abf protected?
24196  doflip = true;
24197  if (fc == T22) {
24198  for (i = 0; i < 2; i++) {
24199  spintet = *flipface;
24200  if (i == 1) {
24201  esymself(spintet);
24202  }
24203  fnextself(spintet);
24204  tspivot(spintet, checksh);
24205  if (checksh.sh != dummysh) {
24206  doflip = false; break; // f is protected. Unflipable.
24207  }
24208  }
24209  } else if (fc == T44) {
24210  spintet = *flipface;
24211  for (i = 0; i < 3; i++) {
24212  fnextself(spintet);
24213  tspivot(spintet, checksh);
24214  if (checksh.sh != dummysh) {
24215  doflip = false; break; // f is protected. Unflipable.
24216  }
24217  }
24218  }
24219  if (doflip) {
24220  flip22(flipface, flipque);
24221  return true;
24222  }
24223  } else if (fc == N32) {
24224  // Is f a crossface?
24225  if (front != (triface *) NULL) {
24226  // (6) Is any obstacle face (abd, or abe, ...) flipable?
24227  spintet = *flipface;
24228  while (fnextself(spintet)) {
24229  if (apex(spintet) == apex(*flipface)) break;
24230  // Check if spintet is flipable, no recursive.
24231  if (constrainedflip(&spintet, NULL, flipque)) {
24232  // One obstacle face has been flipped.
24233  return true;
24234  }
24235  // Unflipable. Go to the next obstacle face.
24236  findedge(&spintet, org(*flipface), dest(*flipface));
24237  }
24238  }
24239  }
24240  }
24241 
24242  // f is unflipable. Is f a crossface?
24243  if (front != (triface *) NULL) {
24244  // Look if there is another crossface.
24245  pa = org(*front);
24246  pb = dest(*front);
24247  pc = apex(*front);
24248  // sym(*flipface, symface);
24249  // Have we reach the end of abc (We've started from edge ab).
24250  if (oppo(symface) != pc) {
24251  adjustedgering(symface, CCW);
24252  for (i = 0; i < 3; i++) {
24253  fnext(symface, spintet);
24254  // Is c ahead of this face?
24255  sign = orient3d(org(spintet), dest(spintet), apex(spintet), pc);
24256  if (sign < 0.0) {
24257  if (tritritest(&spintet, pa, pb, pc)) {
24258  if (b->verbose > 2) {
24259  printf(" Next crossface (%d, %d, %d).\n",
24260  pointmark(org(spintet)), pointmark(dest(spintet)),
24261  pointmark(apex(spintet)));
24262  }
24263  return constrainedflip(&spintet, front, flipque);
24264  // return constrainedflip(&spintet, NULL, flipque);
24265  }
24266  }
24267  enextself(symface);
24268  }
24269  }
24270  }
24271  return false;
24272 }
24273 
24275 // //
24276 // recoverfront() Recover a missing front by flips. //
24277 // //
24278 // 'front' f is missing in D - it was crossed by faces of D. The cross faces //
24279 // may be flippable, so f can be recovered by flipping them away. //
24280 // //
24282 
24283 bool tetgenmesh::recoverfront(triface* front, list* newtetlist, queue* flipque)
24284 {
24285  triface idfront, starttet, spintet;
24286  point pa, pb, pc, pd, ref;
24287  enum locateresult loc;
24288  enum finddirectionresult col;
24289  REAL ori, ori1, ori2, sign;
24290  int hitbdry;
24291  int i, j;
24292 
24293  // Find an existing edge of f in D to start with.
24294  for (i = 0; i < 3; i++) {
24295  pa = org(*front);
24296  pb = dest(*front);
24297  // Get a tet for searching.
24298  idfront = recenttet;
24299  // Make sure the tet is valid (flip32() may kill a tet).
24300  if (isdead(&idfront)) {
24301  // The tet is dead. Get a live tet in D. !!!
24302  for (j = 0; j < newtetlist->len(); j++) {
24303  recenttet = * (triface *)(* newtetlist)[j];
24304  if (!isdead(&recenttet)) break;
24305  }
24306  assert(j < newtetlist->len());
24307  }
24308  loc = preciselocate(pa, &idfront, (long) newtetlist->len());
24309  if (loc != ONVERTEX) {
24310  // Do a brute-force search in D.
24311  for (j = 0; j < newtetlist->len(); j++) {
24312  idfront = * (triface *)(* newtetlist)[j];
24313  if (isdead(&idfront)) continue;
24314  if (findorg(&idfront, pa)) break;
24315  }
24316  assert(j < newtetlist->len()); // a must belong to one tet.
24317  }
24318  recenttet = idfront;
24319  // Search for a tet having edge ab.
24320  col = finddirection(&idfront, pb, (long) newtetlist->len());
24321  if (col == BELOWHULL) {
24322  // Do a brute-force search in D.
24323  for (j = 0; j < newtetlist->len(); j++) {
24324  idfront = * (triface *)(* newtetlist)[j];
24325  if (isdead(&idfront)) continue;
24326  if (findorg(&idfront, pa)) {
24327  assert(org(idfront) == pa);
24328  if (dest(idfront) == pb) {
24329  col = RIGHTCOLLINEAR; break;
24330  } else if (apex(idfront) == pb) {
24331  col = LEFTCOLLINEAR; break;
24332  } else if (oppo(idfront) == pb) {
24333  col = TOPCOLLINEAR; break;
24334  }
24335  }
24336  }
24337  }
24338  if (col == RIGHTCOLLINEAR) {
24339  // b is just the destination.
24340  } else if (col == LEFTCOLLINEAR) {
24341  enext2self(idfront);
24342  esymself(idfront);
24343  } else if (col == TOPCOLLINEAR) {
24344  fnextself(idfront);
24345  enext2self(idfront);
24346  esymself(idfront);
24347  }
24348  if (dest(idfront) == pb) break; // Found.
24349  // Missing. Go to the next edge of f.
24350  enextself(*front);
24351  }
24352  if (i == 3) {
24353  // All three edges of f are missing - unrecoverable.
24354  return false;
24355  }
24356 
24357  // Search for a tet having f (abc).
24358  pc = apex(*front);
24359  spintet = idfront;
24360  hitbdry = 0;
24361  do {
24362  if (apex(spintet) == pc) {
24363  // Found abc. Insert an auxilary subface s at idfront.
24364  insertauxsubface(front, &spintet);
24365  return true;
24366  }
24367  if (!fnextself(spintet)) {
24368  hitbdry ++;
24369  if (hitbdry < 2) {
24370  esym(idfront, spintet);
24371  if (!fnextself(spintet)) {
24372  hitbdry ++;
24373  }
24374  }
24375  }
24376  if (apex(spintet) == apex(idfront)) break;
24377  } while (hitbdry < 2);
24378 
24379  // Search for a crossing face to flip.
24380  pd = apex(idfront);
24381  assert(pd != pc);
24382  // Decide the orientation of d with abc.
24383  ori = orient3d(pa, pb, pc, pd);
24384  if (ori < 0.0) {
24385  // d is above abc. Rotate downwards.
24386  esym(idfront, starttet);
24387  sign = -1.0;
24388  } else if (ori > 0.0) {
24389  // d is below abc. Rotate upwards.
24390  starttet = idfront;
24391  sign = 1.0;
24392  } else {
24393  assert(ori == 0.0);
24394  // d is coplanar with abc. Do abc and abd intersect?
24395  ref = oppo(idfront);
24396  ori1 = orient3d(pa, pb, ref, pc);
24397  ori2 = orient3d(pa, pb, ref, pd);
24398  assert(ori1 * ori2 != 0.0);
24399  if (ori1 * ori2 > 0) {
24400  // abc and abd intersect. There're two possible intersections:
24401  // ad and bc, or ac and bd. Find it out.
24402  ori1 = orient3d(pb, pc, ref, pd);
24403  ori2 = orient3d(pb, pc, ref, pa);
24404  assert(ori1 * ori2 != 0.0);
24405  if (ori1 * ori2 > 0) {
24406  // ac intersects bd.
24407  enextself(idfront); // go to edge bd.
24408  } else {
24409  // ad intersects bc.
24410  enext2self(idfront); // go to edge ad.
24411  }
24412  adjustedgering(idfront, CCW);
24413  fnextself(idfront); // face ade or bce need a 4-to-4 flip.
24414  if (b->verbose > 2) {
24415  printf(" Get crossface (%d, %d, %d).\n", pointmark(org(idfront)),
24416  pointmark(dest(idfront)), pointmark(apex(idfront)));
24417  }
24418  if (constrainedflip(&idfront, front, flipque)) {
24419  // A crossface has been flipped. Continue to recover f.
24420  return recoverfront(front, newtetlist, flipque);
24421  }
24422  // Unable to recover f.
24423  return false; // sign = 0.0;
24424  } else {
24425  // Not intersect. We can go either direction.
24426  starttet = idfront;
24427  if (fnextself(starttet)) {
24428  // Choose to rotate upwards.
24429  sign = 1.0;
24430  } else {
24431  // Hit convex hull. Choose to rotate downwrads.
24432  esym(idfront, starttet);
24433  sign = -1.0;
24434  }
24435  }
24436  }
24437 
24438  assert(sign != 0.0);
24439  if (sign == -1) {
24440  // The edge ab has be changed. Reverse it.
24441  pa = org(starttet);
24442  pb = dest(starttet);
24443  // The sign has been reversed as well.
24444  sign = -sign;
24445  }
24446  // Rotate face abd around edge ab. Moreover, we've chosen the rotate
24447  // direction such that no convex hull face will be reach.
24448  spintet = starttet;
24449  while (fnextself(spintet)) {
24450  pd = apex(spintet);
24451  assert(pd != pc);
24452  // Check if the orientation of d (with abc) has changed.
24453  ori = orient3d(pa, pb, pc, pd);
24454  if (ori == 0.0) {
24455  // abc and abd must coplanar intersect (4-to-4 flip is needed).
24456  ref = oppo(spintet);
24457  ori1 = orient3d(pb, pc, ref, pd);
24458  ori2 = orient3d(pb, pc, ref, pa);
24459  assert(ori1 * ori2 != 0.0);
24460  if (ori1 * ori2 > 0) {
24461  // ac intersects bd.
24462  enextself(spintet); // go to edge bd.
24463  } else {
24464  // ad intersects bc.
24465  enext2self(spintet); // go to edge ad.
24466  }
24467  adjustedgering(spintet, CCW);
24468  fnextself(spintet); // face ade or bce need a 4-to-4 flip.
24469  if (b->verbose > 2) {
24470  printf(" Get crossface (%d, %d, %d).\n", pointmark(org(spintet)),
24471  pointmark(dest(spintet)), pointmark(apex(spintet)));
24472  }
24473  if (constrainedflip(&spintet, front, flipque)) {
24474  // A crossface has been flipped. Continue to recover f.
24475  return recoverfront(front, newtetlist, flipque);
24476  }
24477  // Unable to recover f.
24478  return false; // sign = 0.0;
24479  } else if (ori * sign < 0.0) {
24480  // Sign has changed. The face dea or deb must cross abc.
24481  adjustedgering(spintet, CCW);
24482  enextself(spintet);
24483  for (i = 0; i < 2; i++) {
24484  // Get the face dea or deb.
24485  fnext(spintet, starttet);
24486  if (tritritest(&starttet, pa, pb, pc)) {
24487  if (b->verbose > 2) {
24488  printf(" Get crossface (%d, %d, %d).\n",
24489  pointmark(org(starttet)), pointmark(dest(starttet)),
24490  pointmark(apex(starttet)));
24491  }
24492  if (constrainedflip(&starttet, front, flipque)) {
24493  // A crossface has been flipped. Continue to recover f.
24494  return recoverfront(front, newtetlist, flipque);
24495  }
24496  }
24497  enextself(spintet);
24498  }
24499  // Unable to recover f.
24500  return false;
24501  }
24502  }
24503  // Impossible to be here.
24504  assert(0);
24505  return false;
24506 }
24507 
24509 // //
24510 // repairflips() Flip non-Delaunay and non-constrained faces. //
24511 // //
24513 
24514 void tetgenmesh::repairflips(queue* flipque)
24515 {
24516  badface *qface;
24517  triface flipface, symface, spintet;
24518  face checksh;
24519  point pa, pb, pc, pd, pe;
24520  enum fliptype fc;
24521  REAL sign;
24522  long flipcount;
24523  bool doflip;
24524  int ia, ib, ic, id, ie;
24525  int i;
24526 
24527  if (b->verbose > 1) {
24528  printf(" Repair flip %ld faces.\n", flipque->len());
24529  }
24530  flipcount = flip23s + flip32s + flip22s + flip44s;
24531  // Loop until the queue is empty.
24532  while (!flipque->empty()) {
24533  qface = (badface *) flipque->pop();
24534  flipface = qface->tt;
24535  // Check the validity of this face.
24536  if (isdead(&flipface) || flipface.tet == dummytet ||
24537  (org(flipface) != qface->forg) ||
24538  (dest(flipface) != qface->fdest) ||
24539  (apex(flipface) != qface->fapex) ||
24540  (oppo(flipface) == (point) NULL)) continue;
24541  // (1) Is f protected by an (auxilary) subface?
24542  tspivot(flipface, checksh);
24543  if (checksh.sh != dummysh) continue;
24544  // (2) Is f on the convex hull?
24545  sym(flipface, symface);
24546  if (symface.tet == dummytet) continue;
24547  // For positive orientation that insphere() test requires.
24548  adjustedgering(flipface, CW);
24549  pa = org(flipface);
24550  pb = dest(flipface);
24551  pc = apex(flipface);
24552  pd = oppo(flipface);
24553  pe = oppo(symface);
24554  // if (symbolic) {
24555  ia = pointmark(pa);
24556  ib = pointmark(pb);
24557  ic = pointmark(pc);
24558  id = pointmark(pd);
24559  ie = pointmark(pe);
24560  sign = insphere_sos(pa, pb, pc, pd, pe, ia, ib, ic, id, ie);
24561  assert(sign != 0.0);
24562  // } else {
24563  // sign = insphere(pa, pb, pc, pd, pe);
24564  // }
24565  if (sign > 0.0) {
24566  // f is non-lcally Delaunay. Get the fliptype of f.
24567  checksubfaces = 0; // switch off subface test.
24568  fc = categorizeface(flipface);
24569  checksubfaces = 1; // switch on subface test.
24570  if (fc == T23) {
24571  doflip = true;
24572  // Avoid to create a nearly degenerate tet.
24573  /* pc = oppo(flipface);
24574  pd = oppo(symface);
24575  adjustedgering(flipface, CCW);
24576  for (i = 0; i < 3; i++) {
24577  pa = org(flipface);
24578  pb = dest(flipface);
24579  ori = orient3d(pa, pb, pc, pd);
24580  if (iscoplanar(pa, pb, pc, pd, ori, b->epsilon)) {
24581  doflip = false; break;
24582  }
24583  enextself(flipface);
24584  } */
24585  if (doflip) {
24586  flip23(&flipface, flipque);
24587  }
24588  } else if (fc == T32) {
24589  // (4) Is abd, or abe protected?
24590  doflip = true;
24591  spintet = flipface;
24592  for (i = 0; i < 2; i++) {
24593  fnextself(spintet);
24594  tspivot(spintet, checksh);
24595  if (checksh.sh != dummysh) {
24596  doflip = false; break; // f is protected. Unflipable.
24597  }
24598  }
24599  if (doflip) {
24600  flip32(&flipface, flipque);
24601  }
24602  } else if (fc == T22 || fc == T44) {
24603  // (5) Is abd, abe, or abf protected?
24604  doflip = true;
24605  if (fc == T22) {
24606  for (i = 0; i < 2; i++) {
24607  spintet = flipface;
24608  if (i == 1) {
24609  esymself(spintet);
24610  }
24611  fnextself(spintet);
24612  tspivot(spintet, checksh);
24613  if (checksh.sh != dummysh) {
24614  doflip = false; break; // f is protected. Unflipable.
24615  }
24616  }
24617  } else if (fc == T44) {
24618  spintet = flipface;
24619  for (i = 0; i < 3; i++) {
24620  fnextself(spintet);
24621  tspivot(spintet, checksh);
24622  if (checksh.sh != dummysh) {
24623  doflip = false; break; // f is protected. Unflipable.
24624  }
24625  }
24626  }
24627  if (doflip) {
24628  flip22(&flipface, flipque);
24629  }
24630  }
24631  }
24632  }
24633  flipcount = flip23s + flip32s + flip22s + flip44s - flipcount;
24634  if (b->verbose > 1) {
24635  printf(" %ld flips.\n", flipcount);
24636  }
24637 }
24638 
24640 // //
24641 // constrainedcavity() Tetrahedralize a cavity by constrained tetrahedra. //
24642 // //
24643 // The cavity C is bounded by faces F in 'floorlist' and 'ceillist'. 'ptlist'//
24644 // V is the set of vertices of C. //
24645 // //
24647 
24648 bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist,
24649  list* ceillist, list* ptlist, list* frontlist, list* misfrontlist,
24650  list* newtetlist, queue* flipque)
24651 {
24652  triface misfront, newtet;
24653  long facenum;
24654  int i;
24655 
24656  if (b->verbose > 1) {
24657  printf(" Constrained cavity (%d floors, %d ceilings, %d vertices).\n",
24658  floorlist->len(), ceillist->len(), ptlist->len());
24659  }
24660 
24661  // symbolic = 1;
24662 
24663  // Initialize the cavity C.
24664  initializecavity(floorlist, ceillist, frontlist);
24665  // Form the D of the vertices of C.
24666  delaunizecavvertices(oldtet, ptlist, NULL, newtetlist, flipque);
24667 
24668  // Identify faces of C in D.
24669  if (!identifyfronts(frontlist, misfrontlist, newtetlist)) {
24670  // Some faces are missing.
24671  recenttet = * (triface *)(* newtetlist)[0];
24672  assert((recenttet.tet != dummytet) && !isdead(&recenttet));
24673  // Try to recover missing faces by flips.
24674  do {
24675  facenum = misfrontlist->len();
24676  for (i = 0; i < misfrontlist->len(); i++) {
24677  // Get a missing front f.
24678  misfront = * (triface *)(* misfrontlist)[i];
24679  // Let f face toward the inside of C.
24680  adjustedgering(misfront, CW);
24681  if (b->verbose > 1) {
24682  printf(" Recover face (%d, %d, %d).\n", pointmark(org(misfront)),
24683  pointmark(dest(misfront)), pointmark(apex(misfront)));
24684  }
24685  if (recoverfront(&misfront, newtetlist, flipque)) {
24686  // f has been recovered.
24687  frontlist->append(&misfront);
24688  misfrontlist->del(i, 0); i--;
24689  }
24690  // Flip non-locally non-constrained Delaunay faces.
24691  repairflips(flipque);
24692  }
24693  // Have all faces been recovered?
24694  if (misfrontlist->len() == 0) break;
24695  // No! There are still un-recovered faces. Continue the loop if any
24696  // face has been recovered.
24697  } while (misfrontlist->len() < facenum);
24698  // Retrieve new tets and purge dead tets in D.
24699  retrievenewtets(newtetlist);
24700  }
24701 
24702  // symbolic = 0;
24703 
24704  if (misfrontlist->len() == 0) {
24705  // All fronts have identified in D. Get the shape of C by removing out
24706  // tets of C. 'misfrontlist' is reused for removing out tets.
24707  // Don't do flip since the new tets may get deleted later.
24708  carvecavity(newtetlist, misfrontlist, NULL);
24709  // Recover locally Delaunay faces.
24710  // flip(flipque, NULL);
24711  return true;
24712  } else {
24713  // Fail to tetrahedralize C.
24714  // Remove aux subfaces.
24715  detachauxsubfaces(newtetlist);
24716  // Remove new tets.
24717  for (i = 0; i < newtetlist->len(); i++) {
24718  newtet = * (triface *)(* newtetlist)[i];
24719  assert(!isdead(&newtet));
24720  tetrahedrondealloc(newtet.tet);
24721  }
24722  newtetlist->clear();
24723  // Restore faces of C in frontlist.
24724  for (i = 0; i < misfrontlist->len(); i++) {
24725  misfront = * (triface *)(* misfrontlist)[i];
24726  frontlist->append(&misfront);
24727  }
24728  return false;
24729  }
24730 }
24731 
24733 // //
24734 // expandsteinercavity() Expand the cavity of a Steiner point. //
24735 // //
24736 // Expand the cavity C if there fronts (except fronts having subfaces) which //
24737 // are either (nearly) coplanar or invisible by the Steiner point. //
24738 // //
24740 
24741 void tetgenmesh::expandsteinercavity(point steinpt, REAL eps, list* frontlist,
24742  list* oldtetlist)
24743 {
24744  triface front, symfront, newfront, oldfront;
24745  face frontsh;
24746  point pa, pb, pc;
24747  REAL ori;
24748  bool expflag, newflag;
24749  int i, j;
24750 
24751  do {
24752  expflag = false;
24753  for (i = 0; i < frontlist->len(); i++) {
24754  // Get a front f.
24755  front = * (triface *)(* frontlist)[i];
24756  // f can be expanded if it is not a subface.
24757  tspivot(front, frontsh);
24758  if (frontsh.sh == dummysh) {
24759  // Let f face to the inside of C.
24760  adjustedgering(front, CW);
24761  pa = org(front);
24762  pb = dest(front);
24763  pc = apex(front);
24764  ori = orient3d(pa, pb, pc, steinpt);
24765  if (ori != 0.0) {
24766  if (iscoplanar(pa, pb, pc, steinpt, ori, eps)) {
24767  ori = 0.0; // f is nearly coplanar with p.
24768  }
24769  }
24770  if (ori >= 0.0) {
24771  // f is either invisible or coplanar with p.
24772  if (b->verbose > 2) {
24773  printf(" Remove front (%d, %d, %d).\n", pointmark(pa),
24774  pointmark(pb), pointmark(pc));
24775  }
24776  frontlist->del(i, 1);
24777  expflag = true;
24778  break;
24779  }
24780  }
24781  }
24782  if (expflag) {
24783  assert(!infected(front) && (oppo(front) != NULL));
24784  // Expand C at f by including new fronts.
24785  adjustedgering(front, CCW);
24786  for (i = 0; i < 3; i++) {
24787  newflag = true;
24788  // Get a new boundary n of the cavity.
24789  fnext(front, symfront);
24790  tspivot(symfront, frontsh);
24791  sym(symfront, newfront);
24792  if (frontsh.sh == dummysh) {
24793  assert(newfront.tet != dummytet);
24794  // Is n a front of the unexp. cavity?
24795  if (infected(newfront)) {
24796  for (j = 0; j < frontlist->len(); j++) {
24797  oldfront = * (triface *)(* frontlist)[j];
24798  if ((oldfront.tet == symfront.tet) &&
24799  (oldfront.loc == symfront.loc)) {
24800  // n is not a front anymore.
24801  if (b->verbose > 2) {
24802  printf(" Remove front (%d, %d, %d).\n",
24803  pointmark(org(oldfront)), pointmark(dest(oldfront)),
24804  pointmark(apex(oldfront)));
24805  }
24806  frontlist->del(j, 1);
24807  newflag = false;
24808  break;
24809  }
24810  }
24811  }
24812  } else {
24813  // n is a subface.
24814  if (newfront.tet == dummytet) {
24815  sesymself(frontsh);
24816  // Create a fake tet to hold n.
24817  maketetrahedron(&newfront);
24818  setorg(newfront, sorg(frontsh));
24819  setdest(newfront, sdest(frontsh));
24820  setapex(newfront, sapex(frontsh));
24821  setoppo(newfront, (point) NULL);
24822  tsbond(newfront, frontsh);
24823  } else {
24824  // n should not be a front of cavity yet.
24825  assert(!infected(newfront));
24826  }
24827  }
24828  if (newflag) {
24829  if (b->verbose > 2) {
24830  printf(" Add front (%d, %d, %d).\n", pointmark(org(newfront)),
24831  pointmark(dest(newfront)), pointmark(apex(newfront)));
24832  }
24833  frontlist->append(&newfront);
24834  }
24835  enextself(front);
24836  }
24837  // Add f into oldtetlist (to be deleted).
24838  infect(front);
24839  oldtetlist->append(&front);
24840  expcavcount++;
24841  }
24842  } while (expflag);
24843 }
24844 
24846 // //
24847 // findrelocatepoint() Find new location for relocating a point. //
24848 // //
24849 // 'frontlist' contains the boundary faces of the cavity C. Some fronts are //
24850 // visible by 'stpt' p, some are coplanar with p. //
24851 // //
24853 
24854 bool tetgenmesh::findrelocatepoint(point sp, point np, REAL* n,
24855  list* frontlist, list* oldtetlist)
24856 {
24857  triface front;
24858  point pa, pb, pc;
24859  REAL tp[3], tvol, mvol;
24860  REAL ori, eps;
24861  bool visible;
24862  int i, j, k;
24863 
24864  if (b->verbose > 1) {
24865  printf(" Find new location for point %d.\n", pointmark(sp));
24866  }
24867 
24868  // Avoid compilation warnings.
24869  tvol = mvol = 0.0;
24870  visible = false;
24871 
24872  eps = b->epsilon;
24873  // Initialize np far enough from p (outside C).
24874  for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
24875  // Let tp = np;
24876  for (i = 0; i < 3; i++) tp[i] = np[i];
24877  // Interation to adjust np until it is visible by all fronts.
24878  j = 0;
24879  do {
24880  for (i = 0; i < frontlist->len(); i++) {
24881  // Get a front face f.
24882  front = * (triface *)(* frontlist)[i];
24883  // Let f face to the interior of C.
24884  adjustedgering(front, CW);
24885  pa = org(front);
24886  pb = dest(front);
24887  pc = apex(front);
24888  ori = orient3d(pa, pb, pc, np);
24889  visible = (ori < 0.0);
24890  if (!visible) {
24891  // A front is invisible by np. Move it towards p along the normal.
24892  for (i = 0; i < 3; i++) np[i] = sp[i] + 0.5 * (sp[i] - np[i]);
24893  // Failed if tp = np.
24894  if ((tp[0] == np[0]) && (tp[1] == np[1]) && (tp[2] == np[2])) {
24895  // Try to expand the cavity.
24896  expandsteinercavity(sp, eps, frontlist, oldtetlist);
24897  eps *= 10.0;
24898  if (eps > b->epsilon * 1000.0) {
24899  // printf("Internal error: Fail to relocate pt %d.\n",pointmark(sp));
24900  // internalerror();
24901  return false;
24902  }
24903  // Restart the point relocation.
24904  for (i = 0; i < 3; i++) np[i] = sp[i] + longest * n[i];
24905  }
24906  if (j % 2) {
24907  // Set tp = np (at every 2 steps) to catch the stop state.
24908  for (i = 0; i < 3; i++) tp[i] = np[i];
24909  }
24910  break;
24911  } else {
24912  // Save the smallest volume.
24913  if (i == 0) {
24914  mvol = fabs(ori);
24915  } else {
24916  mvol = fabs(ori) < mvol ? fabs(ori) : mvol;
24917  }
24918  }
24919  }
24920  j++;
24921  } while (!visible);
24922 
24923  if (b->verbose > 1) {
24924  printf(" %d iterations. minvol = %.12g.\n", j, mvol);
24925  }
24926 
24927  // Continue to adjust np until the minimal volume of tets formed by
24928  // fronts and np doesn't increase (all fronts are visible by np).
24929  k = 0;
24930  do {
24931  j = 0;
24932  do {
24933  if (k == 0) {
24934  // Initial tp := np + 0.9 * (p - np). Move toward p.
24935  for (i = 0; i < 3; i++) tp[i] = sp[i] + 0.9 * (np[i] - sp[i]);
24936  } else {
24937  // Initial tp := np + 1.1 * (p - np). Move away from p.
24938  for (i = 0; i < 3; i++) tp[i] = sp[i] + 1.1 * (np[i] - sp[i]);
24939  }
24940  // Get the minial volume formed by tp with one of the fronts.
24941  for (i = 0; i < frontlist->len(); i++) {
24942  // Get a front face f.
24943  front = * (triface *)(* frontlist)[i];
24944  // Let f face to the interior of C.
24945  adjustedgering(front, CW);
24946  pa = org(front);
24947  pb = dest(front);
24948  pc = apex(front);
24949  ori = orient3d(pa, pb, pc, tp);
24950  visible = (ori < 0.0);
24951  if (visible) {
24952  // Save the smallest volume.
24953  if (i == 0) {
24954  tvol = fabs(ori);
24955  } else {
24956  tvol = fabs(ori) < tvol ? fabs(ori) : tvol;
24957  }
24958  } else {
24959  // A front is invisible by tp. Stop.
24960  tvol = 0.0;
24961  break;
24962  }
24963  }
24964  if (tvol > mvol) {
24965  // Get a larger minimal volume.
24966  for (i = 0; i < 3; i++) np[i] = tp[i];
24967  mvol = tvol;
24968  } else {
24969  // Minimal volume decreases. Stop.
24970  break;
24971  }
24972  // Continue to adjust np.
24973  j++;
24974  } while (true);
24975  // Has np been adjusted?
24976  if (j > 0) break;
24977  // Try to move np to anoter direction.
24978  k++;
24979  } while (k < 2);
24980 
24981  if (b->verbose > 1) {
24982  printf(" %d adjust iterations. minvol = %.12g.\n", j, mvol);
24983  }
24984  return true;
24985 }
24986 
24988 // //
24989 // relocatepoint() Relocate a point into the cavity. //
24990 // //
24991 // 'frontlist' contains the boundary faces of the cavity C. All fronts must //
24992 // be visible by 'steinpt'. Some fronts may hold by 'fake' tets (they are //
24993 // hull faces). Fake tets will be removed when they're finished. //
24994 // //
24996 
24997 void tetgenmesh::relocatepoint(point steinpt, triface* oldtet, list* frontlist,
24998  list* newtetlist, queue* flipque)
24999 {
25000  triface front, newtet, newface, neightet;
25001  face checksh;
25002  point pa, pb;
25003  REAL attrib, volume;
25004  bool bdflag;
25005  int i, j, k, l;
25006 
25007  if (b->verbose > 1) {
25008  printf(" Insert Steiner point (%.12g, %.12g, %.12g) %d.\n",
25009  steinpt[0], steinpt[1], steinpt[2], pointmark(steinpt));
25010  }
25011  // Clear the list first.
25012  newtetlist->clear();
25013 
25014  // Create the tets formed by fronts and 'steinpt'.
25015  for (i = 0; i < frontlist->len(); i++) {
25016  // Get a front f.
25017  front = * (triface *)(* frontlist)[i];
25018  // Let f face inside C. (f is a face of tet adjacent to C).
25019  adjustedgering(front, CW);
25020  if (b->verbose > 2) {
25021  printf(" Get front (%d, %d, %d).\n", pointmark(org(front)),
25022  pointmark(dest(front)), pointmark(apex(front)));
25023  }
25024  maketetrahedron(&newtet);
25025  newtetlist->append(&newtet);
25026  setorg(newtet, org(front));
25027  setdest(newtet, dest(front));
25028  setapex(newtet, apex(front));
25029  setoppo(newtet, steinpt);
25030  if (oldtet != (triface *) NULL) {
25031  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
25032  attrib = elemattribute(oldtet->tet, j);
25033  setelemattribute(newtet.tet, j, attrib);
25034  }
25035  if (b->varvolume) {
25036  volume = volumebound(oldtet->tet);
25037  setvolumebound(newtet.tet, volume);
25038  }
25039  }
25040  // 'front' may be a 'fake' tet.
25041  tspivot(front, checksh);
25042  if (oppo(front) == (point) NULL) {
25043  if (checksh.sh != dummysh) {
25044  stdissolve(checksh);
25045  }
25046  // Dealloc the 'fake' tet.
25047  tetrahedrondealloc(front.tet);
25048  // This side (newtet) is a boundary face, let 'dummytet' bond to it.
25049  // Otherwise, 'dummytet' may point to a dead tetrahedron after the
25050  // old cavity tets are removed.
25051  dummytet[0] = encode(newtet);
25052  } else {
25053  // Bond two tetrahedra, also dissolve the old bond at 'front'.
25054  bond(newtet, front);
25055  }
25056  if (checksh.sh != dummysh) {
25057  sesymself(checksh);
25058  tsbond(newtet, checksh);
25059  }
25060  if (flipque != (queue *) NULL) {
25061  // f may be non-locally Delaunay and flipable.
25062  enqueueflipface(newtet, flipque);
25063  }
25064  // The three neighbors are open. Will be finished later.
25065  }
25066 
25067  // Connect new tets in C. All connecting faces must contain 'steinpt'.
25068  for (i = 0; i < newtetlist->len(); i++) {
25069  newtet = * (triface *)(* newtetlist)[i];
25070  newtet.ver = 0;
25071  for (j = 0; j < 3; j++) {
25072  fnext(newtet, newface);
25073  sym(newface, neightet);
25074  if (neightet.tet == dummytet) {
25075  // Find a neightet to connect it.
25076  bdflag = false;
25077  pa = org(newface);
25078  pb = dest(newface);
25079  assert(apex(newface) == steinpt);
25080  for (k = i + 1; k < newtetlist->len() && !bdflag; k++) {
25081  neightet = * (triface *)(* newtetlist)[k];
25082  neightet.ver = 0;
25083  for (l = 0; l < 3; l++) {
25084  if ((org(neightet) == pa && dest(neightet) == pb) ||
25085  (org(neightet) == pb && dest(neightet) == pa)) {
25086  // Find the neighbor.
25087  fnextself(neightet);
25088  assert(apex(neightet) == steinpt);
25089  // Now neightet is a face same as newface, bond them.
25090  bond(newface, neightet);
25091  bdflag = true;
25092  break;
25093  }
25094  enextself(neightet);
25095  }
25096  }
25097  assert(bdflag);
25098  }
25099  enextself(newtet);
25100  }
25101  // Let the corners of newtet point to it for fast searching.
25102  pa = org(newtet);
25103  setpoint2tet(pa, encode(newtet));
25104  pa = dest(newtet);
25105  setpoint2tet(pa, encode(newtet));
25106  pa = apex(newtet);
25107  setpoint2tet(pa, encode(newtet));
25108  pa = oppo(newtet);
25109  setpoint2tet(pa, encode(newtet));
25110  }
25111 
25112  if (flipque != (queue *) NULL) {
25113  // Recover locally Delaunay faces.
25114  flip(flipque, NULL);
25115  }
25116 }
25117 
25119 // //
25120 // findcollapseedge() Find collapseable edge to suppress an endpoint. //
25121 // //
25123 
25124 bool tetgenmesh::findcollapseedge(point suppt, point *conpt, list* oldtetlist,
25125  list* ptlist)
25126 {
25127  triface front;
25128  point pt, pa, pb, pc;
25129  REAL *lenarray, ltmp, ori;
25130  bool visflag;
25131  int *idxarray, itmp;
25132  int n, i, j;
25133 
25134  if (b->verbose > 2) {
25135  printf(" Search an edge (in %d edges) for collapse %d.\n",
25136  ptlist->len(), pointmark(suppt));
25137  }
25138 
25139  // Candidate edges are p to the points of B(p) (in 'ptlist').
25140  n = ptlist->len();
25141  lenarray = new REAL[n];
25142  idxarray = new int[n];
25143  // Sort the points of B(p) by distance to p.
25144  for (i = 0; i < n; i++) {
25145  pt = * (point *)(* ptlist)[i];
25146  lenarray[i] = distance(suppt, pt);
25147  idxarray[i] = i;
25148  }
25149  // Bubble sort.
25150  for (i = 0; i < n - 1; i++) {
25151  for (j = 0; j < n - 1 - i; j++) {
25152  if (lenarray[j + 1] < lenarray[j]) { // compare the two neighbors
25153  ltmp = lenarray[j]; // swap a[j] and a[j + 1]
25154  lenarray[j] = lenarray[j + 1];
25155  lenarray[j + 1] = ltmp;
25156  itmp = idxarray[j]; // swap a[j] and a[j + 1]
25157  idxarray[j] = idxarray[j + 1];
25158  idxarray[j + 1] = itmp;
25159  }
25160  }
25161  }
25162  // For each point q of B(p), test if the edge (p, q) can be collapseed.
25163  for (i = 0; i < n; i++) {
25164  pt = * (point *)(* ptlist)[idxarray[i]];
25165  // Is q visible by faces of B(p) not with q as a vertex.
25166  lenarray[i] = 0.0; // zero volume.
25167  visflag = true;
25168  for (j = 0; j < oldtetlist->len() && visflag; j++) {
25169  front = * (triface *)(* oldtetlist)[j];
25170  // Let f face to inside of B(p).
25171  adjustedgering(front, CCW);
25172  pa = org(front);
25173  pb = dest(front);
25174  pc = apex(front);
25175  // Is f contains q?
25176  if ((pa != pt) && (pb != pt) && (pc != pt)) {
25177  ori = orient3d(pa, pb, pc, pt);
25178  if (ori != 0.0) {
25179  if (iscoplanar(pa, pb, pc, pt, ori, b->epsilon * 1e+2)) ori = 0.0;
25180  }
25181  visflag = ori < 0.0;
25182  if (visflag) {
25183  // Visible, set the smallest volume.
25184  if (j == 0) {
25185  lenarray[i] = fabs(ori);
25186  } else {
25187  lenarray[i] = fabs(ori) < lenarray[i] ? fabs(ori) : lenarray[i];
25188  }
25189  } else {
25190  // Invisible. Do not collapse (p, q).
25191  lenarray[i] = 0.0;
25192  }
25193  }
25194  }
25195  if ((b->verbose > 2) && visflag) {
25196  printf(" Got candidate %d vol(%g).\n", pointmark(pt), lenarray[i]);
25197  }
25198  }
25199 
25200  // Select the largest non-zero volume (result in ltmp).
25201  ltmp = lenarray[0];
25202  itmp = idxarray[0];
25203  for (i = 1; i < n; i++) {
25204  if (lenarray[i] != 0.0) {
25205  if (lenarray[i] > ltmp) {
25206  ltmp = lenarray[i];
25207  itmp = idxarray[i]; // The index to find the point.
25208  }
25209  }
25210  }
25211 
25212  delete [] lenarray;
25213  delete [] idxarray;
25214 
25215  if (ltmp == 0.0) {
25216  // No edge can be collapseed.
25217  *conpt = (point) NULL;
25218  return false;
25219  } else {
25220  pt = * (point *)(* ptlist)[itmp];
25221  *conpt = pt;
25222  return true;
25223  }
25224 }
25225 
25227 // //
25228 // collapseedge() Remove a point by edge collapse. //
25229 // //
25231 
25232 void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist,
25233  list* deadtetlist)
25234 {
25235  triface oldtet, deadtet;
25236  triface adjtet1, adjtet2;
25237  face adjsh;
25238  point pa, pb, pc;
25239  int i, j;
25240 
25241  if (b->verbose > 2) {
25242  printf(" Collapse edge (%d,%d).\n", pointmark(suppt), pointmark(conpt));
25243  }
25244 
25245  // Loop in B(p), replace p with np, queue dead tets, uninfect old tets.
25246  for (i = 0; i < oldtetlist->len(); i++) {
25247  oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet));
25248  uninfect(oldtet);
25249  pa = org(oldtet);
25250  pb = dest(oldtet);
25251  pc = apex(oldtet);
25252  assert(oppo(oldtet) == suppt);
25253  setoppo(oldtet, conpt);
25254  if ((pa == conpt) || (pb == conpt) || (pc == conpt)) {
25255  deadtetlist->append(&oldtet); // a collpased tet.
25256  }
25257  }
25258  // Loop in deadtetlist, glue adjacent tets of dead tets.
25259  for (i = 0; i < deadtetlist->len(); i++) {
25260  deadtet = * (triface *)(* deadtetlist)[i];
25261  // Get the adjacent tet n1 (outside B(p)).
25262  sym(deadtet, adjtet1);
25263  tspivot(deadtet, adjsh);
25264  // Find the edge in deadtet opposite to conpt.
25265  adjustedgering(deadtet, CCW);
25266  for (j = 0; j < 3; j++) {
25267  if (apex(deadtet) == conpt) break;
25268  enextself(deadtet);
25269  }
25270  assert(j < 3);
25271  // Get another adjacent tet n2.
25272  fnext(deadtet, adjtet2);
25273  symself(adjtet2);
25274  assert(adjtet2.tet != dummytet); // n2 is inside B(p).
25275  if (adjtet1.tet != dummytet) {
25276  bond(adjtet1, adjtet2); // Bond n1 <--> n2.
25277  } else {
25278  dissolve(adjtet2); // Dissolve at n2.
25279  dummytet[0] = encode(adjtet2); // Let dummytet holds n2.
25280  }
25281  if (adjsh.sh != dummysh) {
25282  tsbond(adjtet2, adjsh); // Bond s <--> n2.
25283  }
25284  // Collapse deadtet.
25285  tetrahedrondealloc(deadtet.tet);
25286  }
25287  deadtetlist->clear();
25288 }
25289 
25291 // //
25292 // deallocfaketets() Deleted fake tets at fronts. //
25293 // //
25294 // This routine is only called when the findrelocatepoint() routine fails. //
25295 // In other cases, the fake tets are removed automatically in carvecavity() //
25296 // or relocatepoint(). //
25297 // //
25299 
25300 void tetgenmesh::deallocfaketets(list* frontlist)
25301 {
25302  triface front, neightet;
25303  face checksh;
25304  bool infectflag;
25305  int i;
25306 
25307  for (i = 0; i < frontlist->len(); i++) {
25308  // Get a front f.
25309  front = * (triface *)(* frontlist)[i];
25310  // Let f face inside C. (f is a face of tet adjacent to C).
25311  adjustedgering(front, CW);
25312  sym(front, neightet);
25313  tspivot(front, checksh);
25314  if (oppo(front) == (point) NULL) {
25315  if (b->verbose > 2) {
25316  printf(" Get fake tet (%d, %d, %d).\n", pointmark(org(front)),
25317  pointmark(dest(front)), pointmark(apex(front)));
25318  }
25319  if (neightet.tet != dummytet) {
25320  // The neightet may be infected. After dissolve it, the infect flag
25321  // will be lost. Save the flag and restore it later.
25322  infectflag = infected(neightet);
25323  dissolve(neightet);
25324  if (infectflag) {
25325  infect(neightet);
25326  }
25327  }
25328  if (checksh.sh != dummysh) {
25329  infectflag = sinfected(checksh);
25330  stdissolve(checksh);
25331  if (infectflag) {
25332  sinfect(checksh);
25333  }
25334  }
25335  // Dealloc the 'fake' tet.
25336  tetrahedrondealloc(front.tet);
25337  // If 'neightet' is a hull face, let 'dummytet' bond to it. It is
25338  // a 'dummytet' when this front was created from a new subface.
25339  // In such case, it should not be bounded.
25340  if (neightet.tet != dummytet) {
25341  dummytet[0] = encode(neightet);
25342  }
25343  }
25344  }
25345 }
25346 
25348 // //
25349 // restorepolyhedron() Restore the tetrahedralization in a polyhedron. //
25350 // //
25351 // This routine is only called when the operation of suppressing a point is //
25352 // aborted (eg., findrelocatepoint() routine fails). The polyhedron has been //
25353 // remeshed by new tets. This routine restore the old tets in it. //
25354 // //
25355 // 'oldtetlist' contains the list of old tets. Each old tet t_o assumes that //
25356 // it still connects to a tet t_b of the mesh, however, t_b does not connect //
25357 // to t_o, this routine resets the connection such that t_b <--> t_o. //
25358 // //
25360 
25361 void tetgenmesh::restorepolyhedron(list* oldtetlist)
25362 {
25363  triface oldtet, neightet, neineitet;
25364  face checksh;
25365  int i;
25366 
25367  for (i = 0; i < oldtetlist->len(); i++) {
25368  // Get an old tet t_o.
25369  oldtet = * (triface *)(* oldtetlist)[i];
25370  // Check the four sides of t_o.
25371  for (oldtet.loc = 0; oldtet.loc < 4; oldtet.loc++) {
25372  sym(oldtet, neightet);
25373  tspivot(oldtet, checksh);
25374  if (neightet.tet != dummytet) {
25375  sym(neightet, neineitet);
25376  if (neineitet.tet != oldtet.tet) {
25377  // This face of t_o is a boundary of P.
25378  bond(neightet, oldtet);
25379  if (checksh.sh != dummysh) {
25380  tsbond(oldtet, checksh);
25381  }
25382  }
25383  } else {
25384  // t_o has a hull face. It should be the boundary of P.
25385 #ifdef SELF_CHECK
25386  assert(checksh.sh != dummysh);
25387  stpivot(checksh, neineitet);
25388  assert(neineitet.tet != oldtet.tet);
25389 #endif
25390  tsbond(oldtet, checksh);
25391  // Let dummytet[0] points to it.
25392  dummytet[0] = encode(oldtet);
25393  }
25394  }
25395  }
25396 }
25397 
25399 // //
25400 // suppressfacetpoint() Suppress a point inside a facet. //
25401 // //
25402 // The point p inside a facet F will be suppressed from F by either being //
25403 // deleted from the mesh or being relocated into the volume. //
25404 // //
25405 // 'supsh' is a subface f of F, and p = sapex(f); the other parameters are //
25406 // working lists which are empty at the beginning and the end. //
25407 // //
25408 // 'optflag' is used for mesh optimization. If it is set, after removing p, //
25409 // test the object function on each new tet, queue bad tets. //
25410 // //
25412 
25413 bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist,
25414  list* misfrontlist, list* ptlist, list* conlist, memorypool* viri,
25415  queue* flipque, bool noreloc, bool optflag)
25416 {
25417  list *oldtetlist[2], *newtetlist[2];
25418  list *oldshlist, *newshlist;
25419  triface oldtet, newtet;
25420  face oldsh, newsh;
25421  point suppt, newpt[2];
25422  point *cons;
25423  REAL norm[3];
25424  bool success;
25425  int shmark;
25426  int i, j;
25427 
25428  suppt = sapex(*supsh);
25429  if (b->verbose > 1) {
25430  printf(" Suppress point %d in facet.\n", pointmark(suppt));
25431  }
25432 
25433  // Initialize working lists, variables.
25434  for (i = 0; i < 2; i++) {
25435  oldtetlist[i] = (list *) NULL;
25436  newtetlist[i] = (list *) NULL;
25437  newpt[i] = (point) NULL;
25438  }
25439  oldshlist = new list(sizeof(face), NULL, 256);
25440  newshlist = new list(sizeof(face), NULL, 256);
25441  success = true; // Assume p can be suppressed.
25442 
25443  // Find subs of C(p).
25444  oldshlist->append(supsh);
25445  formstarpolygon(suppt, oldshlist, ptlist);
25446  // Get the edges of C(p). They form a closed polygon.
25447  for (i = 0; i < oldshlist->len(); i++) {
25448  oldsh = * (face *)(* oldshlist)[i];
25449  cons = (point *) conlist->append(NULL);
25450  cons[0] = sorg(oldsh);
25451  cons[1] = sdest(oldsh);
25452  }
25453  // Re-triangulate the old C(p).
25454  shmark = shellmark(*supsh);
25455  triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
25456  // Get new subs of C(p), remove protected segments.
25457  retrievenewsubs(newshlist, true);
25458  // Substitute the old C(p) with the new C(p)
25459  replacepolygonsubs(oldshlist, newshlist);
25460  // Clear work lists.
25461  ptlist->clear();
25462  conlist->clear();
25463  flipque->clear();
25464  viri->restart();
25465 
25466  // B(p) (tets with p as a vertex) has been separated into two parts
25467  // (B_0(p) and B_1(p)) by F. Process them individually.
25468  for (i = 0; i < 2 && success; i++) {
25469  if (i == 1) sesymself(*supsh);
25470  // Get a tet containing p.
25471  stpivot(*supsh, oldtet);
25472  // Is this part empty?
25473  if (oldtet.tet == dummytet) continue;
25474  // Allocate spaces for storing (old and new) B_i(p).
25475  oldtetlist[i] = new list(sizeof(triface), NULL, 256);
25476  newtetlist[i] = new list(sizeof(triface), NULL, 256);
25477  // Form old B_i(p) in oldtetlist[i].
25478  assert(!isdead(&oldtet));
25479  oldtetlist[i]->append(&oldtet);
25480  formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
25481  // Infect the tets in old B_i(p) (they're going to be delete).
25482  for (j = 0; j < oldtetlist[i]->len(); j++) {
25483  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25484  infect(oldtet);
25485  }
25486  // Preparation for re-tetrahedralzing old B_i(p).
25487  orientnewsubs(newshlist, supsh, norm);
25488  // Tetrahedralize old B_i(p).
25489  success = constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist,
25490  frontlist, misfrontlist, newtetlist[i], flipque);
25491  // If p is not suppressed, do relocation if 'noreloc' is not set.
25492  if (!success && !noreloc) {
25493  // Try to relocate p into the old B_i(p).
25494  makepoint(&(newpt[i]));
25495  success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
25496  oldtetlist[i]);
25497  // Initialize newpt = suppt.
25498  // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
25499  // success = smoothvolpoint(newpt[i], frontlist, true);
25500  if (success) {
25501  // p is relocated by newpt[i]. Now insert it. Don't do flip since
25502  // the new tets may get deleted again.
25503  relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
25504  setpointtype(newpt[i], FREEVOLVERTEX);
25505  relverts++;
25506  } else {
25507  // Fail to relocate p. Clean fake tets and quit this option.
25508  deallocfaketets(frontlist);
25509  pointdealloc(newpt[i]);
25510  newpt[i] = (point) NULL;
25511  assert(newtetlist[i]->len() == 0);
25512  }
25513  }
25514  if (!success && noreloc) {
25515  // Failed and no point relocation. Clean fake tets.
25516  deallocfaketets(frontlist);
25517  }
25518  // Clear work lists.
25519  ptlist->clear();
25520  frontlist->clear();
25521  misfrontlist->clear();
25522  flipque->clear();
25523  }
25524 
25525  if (success) {
25526  // p has been removed! (Still in the pool).
25527  setpointtype(suppt, UNUSEDVERTEX);
25528  unuverts++;
25529  // Delete old C(p).
25530  for (i = 0; i < oldshlist->len(); i++) {
25531  oldsh = * (face *)(* oldshlist)[i];
25532  if (i == 0) {
25533  // Update the 'hullsize' if C(p) is on the hull.
25534  stpivot(oldsh, oldtet);
25535  if (oldtet.tet != dummytet) {
25536  sesymself(oldsh);
25537  stpivot(oldsh, oldtet);
25538  }
25539  if (oldtet.tet == dummytet) {
25540  // A boundary face. Update the 'hullsize'.
25541  j = oldshlist->len() - newshlist->len();
25542  assert(j > 0);
25543  hullsize -= j;
25544  }
25545  }
25546  shellfacedealloc(subfaces, oldsh.sh);
25547  }
25548  // Delete old B_i(p).
25549  for (i = 0; i < 2; i++) {
25550  if (oldtetlist[i] != (list *) NULL) {
25551  // Delete tets of the old B_i(p).
25552  for (j = 0; j < oldtetlist[i]->len(); j++) {
25553  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25554  assert(!isdead(&oldtet));
25555  tetrahedrondealloc(oldtet.tet);
25556  }
25557  }
25558  }
25559  if (optflag) {
25560  // Check for new bad-quality tets.
25561  for (i = 0; i < 2; i++) {
25562  if (newtetlist[i] != (list *) NULL) {
25563  for (j = 0; j < newtetlist[i]->len(); j++) {
25564  newtet = * (triface *)(* (newtetlist[i]))[j];
25565  if (!isdead(&newtet)) checktet4opt(&newtet, true);
25566  }
25567  }
25568  }
25569  }
25570  } else {
25571  // p is not suppressed. Recover the original state.
25572  unsupverts++;
25573  // Restore the old C(p).
25574  replacepolygonsubs(newshlist, oldshlist);
25575  // Delete subs of the new C(p)
25576  for (i = 0; i < newshlist->len(); i++) {
25577  newsh = * (face *)(* newshlist)[i];
25578  shellfacedealloc(subfaces, newsh.sh);
25579  }
25580  // Restore old B_i(p).
25581  for (i = 0; i < 2; i++) {
25582  if (oldtetlist[i] != (list *) NULL) {
25583  // Uninfect tets of old B_i(p).
25584  for (j = 0; j < oldtetlist[i]->len(); j++) {
25585  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25586  assert(infected(oldtet));
25587  uninfect(oldtet);
25588  }
25589  // Has it been re-meshed?
25590  if (newtetlist[i]->len() > 0) {
25591  // Restore the old B_i(p).
25592  restorepolyhedron(oldtetlist[i]);
25593  // Delete tets of the new B_i(p);
25594  for (j = 0; j < newtetlist[i]->len(); j++) {
25595  newtet = * (triface *)(* (newtetlist[i]))[j];
25596  // Some new tets may already be deleted (by carvecavity()).
25597  if (!isdead(&newtet)) {
25598  tetrahedrondealloc(newtet.tet);
25599  }
25600  }
25601  }
25602  // Dealloc newpt[i] if it exists.
25603  if (newpt[i] != (point) NULL) {
25604  pointdealloc(newpt[i]);
25605  relverts--;
25606  }
25607  }
25608  }
25609  }
25610 
25611  // Delete work lists.
25612  delete oldshlist;
25613  delete newshlist;
25614  for (i = 0; i < 2; i++) {
25615  if (oldtetlist[i] != (list *) NULL) {
25616  delete oldtetlist[i];
25617  delete newtetlist[i];
25618  }
25619  }
25620 
25621  return success;
25622 }
25623 
25625 // //
25626 // suppresssegpoint() Suppress a point on a segment. //
25627 // //
25628 // The point p on a segment S will be suppressed from S by either being //
25629 // deleted from the mesh or being relocated into the volume. //
25630 // //
25631 // 'supseg' is the segment S, and p = sdest(S); the other parameters are //
25632 // working lists which are empty at the beginning and the end. //
25633 // //
25635 
25636 bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist,
25637  list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist,
25638  list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag)
25639 {
25640  list **oldtetlist, **newtetlist;
25641  list **oldshlist, **newshlist;
25642  list *pnewshlist, *dnewshlist;
25643  triface oldtet, newtet;
25644  face oldsh, newsh;
25645  face startsh, spinsh, segsh1, segsh2;
25646  face nsupseg, newseg, prevseg, nextseg;
25647  point suppt, *newpt;
25648  point pa, pb, *cons;
25649  REAL pnorm[2][3], norm[3];
25650  bool success;
25651  int shmark;
25652  int n, i, j, k;
25653 
25654  // Get the Steiner point p.
25655  assert(supseg->shver < 2);
25656  suppt = sdest(*supseg);
25657  // Find the segment ab split by p.
25658  senext(*supseg, nsupseg);
25659  spivotself(nsupseg);
25660  assert(nsupseg.sh != dummysh);
25661  nsupseg.shver = 0;
25662  if (sorg(nsupseg) != suppt) sesymself(nsupseg);
25663  assert(sorg(nsupseg) == suppt);
25664  pa = sorg(*supseg);
25665  pb = sdest(nsupseg);
25666  if (b->verbose > 1) {
25667  printf(" Remove point %d on segment (%d, %d).\n",
25668  pointmark(suppt), pointmark(pa), pointmark(pb));
25669  }
25670 
25671  // Let startsh s containing p.
25672  spivot(*supseg, startsh);
25673  spinsh = startsh;
25674  do {
25675  // Save it in list.
25676  spinshlist->append(&spinsh);
25677  // Go to the next facet.
25678  spivotself(spinsh);
25679  } while (spinsh.sh != startsh.sh);
25680  if (spinshlist->len() == 1) {
25681  // This case has not handled yet.
25682  // printf("Unhandled case: segment only belongs to one facet.\n");
25683  spinshlist->clear();
25684  unsupverts++;
25685  return false;
25686  }
25687 
25688  // Suppose ab is shared by n facets (n > 1), then there are n B(p) (tets
25689  // with p as a vertex). Some B(p) may be empty, eg, outside.
25690  n = spinshlist->len();
25691  oldtetlist = new list*[n];
25692  newtetlist = new list*[n];
25693  oldshlist = new list*[n];
25694  newshlist = new list*[n];
25695  newpt = new point[n];
25696  for (i = 0; i < n; i++) {
25697  oldtetlist[i] = (list *) NULL;
25698  newtetlist[i] = (list *) NULL;
25699  oldshlist[i] = (list *) NULL;
25700  newshlist[i] = (list *) NULL;
25701  newpt[i] = (point) NULL;
25702  }
25703 
25704  // Create a new segment ab (result in newseg).
25705  makeshellface(subsegs, &newseg);
25706  setsorg(newseg, pa);
25707  setsdest(newseg, pb);
25708  // ab gets the same mark and segment type as ap.
25709  setshellmark(newseg, shellmark(*supseg));
25710  setshelltype(newseg, shelltype(*supseg));
25711  if (b->quality && varconstraint) {
25712  // Copy the areabound into the new subsegment.
25713  setareabound(newseg, areabound(*supseg));
25714  }
25715  // Save the old connection at a.
25716  senext2(*supseg, prevseg);
25717  spivotself(prevseg);
25718  if (prevseg.sh != dummysh) {
25719  prevseg.shver = 0;
25720  if (sdest(prevseg) != pa) sesymself(prevseg);
25721  assert(sdest(prevseg) == pa);
25722  senextself(prevseg);
25723  senext2self(newseg);
25724  sbond(newseg, prevseg);
25725  newseg.shver = 0;
25726  }
25727  // Save the old connection at b.
25728  senext(nsupseg, nextseg);
25729  spivotself(nextseg);
25730  if (nextseg.sh != dummysh) {
25731  nextseg.shver = 0;
25732  if (sorg(nextseg) != pb) sesymself(nextseg);
25733  assert(sorg(nextseg) == pb);
25734  senext2self(nextseg);
25735  senextself(newseg);
25736  sbond(newseg, nextseg);
25737  newseg.shver = 0;
25738  }
25739 
25740  // Re-triangulate C(p) (subs with p as a vertex) to remove p.
25741  for (i = 0; i < spinshlist->len(); i++) {
25742  spinsh = * (face *)(* spinshlist)[i];
25743  // Allocate spaces for C_i(p).
25744  oldshlist[i] = new list(sizeof(face), NULL, 256);
25745  newshlist[i] = new list(sizeof(face), NULL, 256);
25746  // Get the subs of C_i(p).
25747  oldshlist[i]->append(&spinsh);
25748  formstarpolygon(suppt, oldshlist[i], ptlist);
25749  // Find the edges of C_i(p). It DOES NOT form a closed polygon.
25750  for (j = 0; j < oldshlist[i]->len(); j++) {
25751  oldsh = * (face *)(* (oldshlist[i]))[j];
25752  cons = (point *) conlist->append(NULL);
25753  cons[0] = sorg(oldsh);
25754  cons[1] = sdest(oldsh);
25755  }
25756  // The C_i(p) isn't closed without ab. Add it to it.
25757  cons = (point *) conlist->append(NULL);
25758  cons[0] = pa;
25759  cons[1] = pb;
25760  // Re-triangulate C_i(p).
25761  shmark = shellmark(spinsh);
25762  triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque);
25763  // Get new subs of C_i(p), remove protected segments.
25764  retrievenewsubs(newshlist[i], true);
25765  // Substitute old C_i(p) with the new C_i(p). !IT IS NOT COMPLETE!
25766  replacepolygonsubs(oldshlist[i], newshlist[i]);
25767  // Find the new subface s having edge ab.
25768  for (j = 0; j < newshlist[i]->len(); j++) {
25769  segsh1 = * (face *)(* (newshlist[i]))[j];
25770  for (k = 0; k < 3; k++) {
25771  if (((sorg(segsh1) == pa) && (sdest(segsh1) == pb)) ||
25772  ((sorg(segsh1) == pb) && (sdest(segsh1) == pa))) break;
25773  senextself(segsh1);
25774  }
25775  if (k < 3) break; // Found.
25776  }
25777  assert(j < newshlist[i]->len()); // ab must exist.
25778  // Bond s and ab together. The C_i(p) is completedly substituted.
25779  ssbond(segsh1, newseg);
25780  // Save s for forming the face ring of ab.
25781  newsegshlist->append(&segsh1);
25782  // Clear work lists.
25783  ptlist->clear();
25784  conlist->clear();
25785  flipque->clear();
25786  viri->restart();
25787  }
25788  // Form the face ring of ab.
25789  for (i = 0; i < newsegshlist->len(); i++) {
25790  segsh1 = * (face *)(* newsegshlist)[i];
25791  if ((i + 1) == newsegshlist->len()) {
25792  segsh2 = * (face *)(* newsegshlist)[0];
25793  } else {
25794  segsh2 = * (face *)(* newsegshlist)[i + 1];
25795  }
25796  sbond1(segsh1, segsh2);
25797  }
25798 
25799  // A work list for keeping subfaces from two facets.
25800  dnewshlist = new list(sizeof(face), NULL, 256);
25801  success = true; // Assume p is suppressable.
25802 
25803  // Suppress p in all B(p). B_i(p) is looped wrt the right-hand rule of ab.
25804  for (i = 0; i < spinshlist->len() && success; i++) {
25805  // Get an old subface s (ap) of a facet.
25806  spinsh = * (face *)(* spinshlist)[i];
25807  // Let the edge direction of s be a->b. Hence all subfaces follow
25808  // the right-hand rule of ab.
25809  if (sorg(spinsh) != pa) sesymself(spinsh);
25810  // Get a tet t of B_i(p).
25811  stpivot(spinsh, oldtet);
25812  // Is B_i(p) empty?
25813  if (oldtet.tet == dummytet) continue;
25814  // Allocate spaces for B_i(p).
25815  oldtetlist[i] = new list(sizeof(triface), NULL, 256);
25816  newtetlist[i] = new list(sizeof(triface), NULL, 256);
25817  // Find all tets of old B_i(p).
25818  oldtetlist[i]->append(&oldtet);
25819  formstarpolyhedron(suppt, oldtetlist[i], ptlist, false);
25820  // Infect tets of old B_i(p) (they're going to be deleted).
25821  for (j = 0; j < oldtetlist[i]->len(); j++) {
25822  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25823  infect(oldtet);
25824  }
25825  // Collect new subfaces (of two facets) bounded B_i(p).
25826  for (k = 0; k < 2; k++) {
25827  if ((i + k) < spinshlist->len()) {
25828  pnewshlist = newshlist[i + k];
25829  segsh1 = * (face *)(* spinshlist)[i + k];
25830  } else {
25831  pnewshlist = newshlist[0];
25832  segsh1 = * (face *)(* spinshlist)[0];
25833  }
25834  // Adjust the orientation of segsh1 to face to the inside of C.
25835  if (k == 0) {
25836  if (sorg(segsh1) != pa) sesymself(segsh1);
25837  assert(sorg(segsh1) == pa);
25838  } else {
25839  if (sdest(segsh1) != pa) sesymself(segsh1);
25840  assert(sdest(segsh1) == pa);
25841  }
25842  // Preparation for re-tetrahedralzing old B_i(p).
25843  orientnewsubs(pnewshlist, &segsh1, pnorm[k]);
25844  for (j = 0; j < pnewshlist->len(); j++) {
25845  dnewshlist->append((face *)(* pnewshlist)[j]);
25846  }
25847  }
25848  // Tetrahedralize B_i(p).
25849  success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist,
25850  frontlist, misfrontlist, newtetlist[i], flipque);
25851  if (!success && !noreloc) {
25852  // C must be finished by re-locating the steiner point.
25853  makepoint(&(newpt[i]));
25854  for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]);
25855  success = findrelocatepoint(suppt, newpt[i], norm, frontlist,
25856  oldtetlist[i]);
25857  // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j];
25858  // success = smoothvolpoint(newpt[i], frontlist, true);
25859  if (success) {
25860  // p is relocated by newpt[i]. Now insert it. Don't do flip since
25861  // the new tets may get deleted again.
25862  relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL);
25863  setpointtype(newpt[i], FREEVOLVERTEX);
25864  relverts++;
25865  } else {
25866  // Fail to relocate p. Clean fake tets and quit this option.
25867  deallocfaketets(frontlist);
25868  pointdealloc(newpt[i]);
25869  newpt[i] = (point) NULL;
25870  assert(newtetlist[i]->len() == 0);
25871  }
25872  }
25873  if (!success && noreloc) {
25874  // Failed and no point relocation. Clean fake tets.
25875  deallocfaketets(frontlist);
25876  }
25877  // Clear work lists.
25878  dnewshlist->clear();
25879  ptlist->clear();
25880  frontlist->clear();
25881  misfrontlist->clear();
25882  flipque->clear();
25883  }
25884 
25885  if (success) {
25886  // p has been suppressed. (Still in the pool).
25887  setpointtype(suppt, UNUSEDVERTEX);
25888  unuverts++;
25889  // Update the segmnet pointers saved in a and b.
25890  setpoint2sh(pa, sencode(newseg));
25891  setpoint2sh(pb, sencode(newseg));
25892  // Delete old segments ap, pb.
25893  shellfacedealloc(subsegs, supseg->sh);
25894  shellfacedealloc(subsegs, nsupseg.sh);
25895  // Delete subs of old C_i(p).
25896  for (i = 0; i < spinshlist->len(); i++) {
25897  for (j = 0; j < oldshlist[i]->len(); j++) {
25898  oldsh = * (face *)(* (oldshlist[i]))[j];
25899  if (j == 0) {
25900  // Update 'hullsize' if C_i(p) is on the hull.
25901  stpivot(oldsh, oldtet);
25902  if (oldtet.tet != dummytet) {
25903  sesymself(oldsh);
25904  stpivot(oldsh, oldtet);
25905  }
25906  if (oldtet.tet == dummytet) {
25907  // Update 'hullsize'.
25908  k = oldshlist[i]->len() - newshlist[i]->len();
25909  assert(k > 0);
25910  hullsize -= k;
25911  }
25912  }
25913  shellfacedealloc(subfaces, oldsh.sh);
25914  }
25915  }
25916  // Delete tets old B_i(p).
25917  for (i = 0; i < spinshlist->len(); i++) {
25918  // Delete them if it is not empty.
25919  if (oldtetlist[i] != (list *) NULL) {
25920  for (j = 0; j < oldtetlist[i]->len(); j++) {
25921  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25922  assert(!isdead(&oldtet));
25923  tetrahedrondealloc(oldtet.tet);
25924  }
25925  }
25926  }
25927  if (optflag) {
25928  for (i = 0; i < spinshlist->len(); i++) {
25929  // Check for new bad-quality tets.
25930  if (newtetlist[i] != (list *) NULL) {
25931  for (j = 0; j < newtetlist[i]->len(); j++) {
25932  newtet = * (triface *)(* (newtetlist[i]))[j];
25933  if (!isdead(&newtet)) checktet4opt(&newtet, true);
25934  }
25935  }
25936  }
25937  }
25938  } else {
25939  // p is not suppressed. Recover the original state.
25940  unsupverts++;
25941  // Restore old connection at a.
25942  senext2(*supseg, prevseg);
25943  spivotself(prevseg);
25944  if (prevseg.sh != dummysh) {
25945  prevseg.shver = 0;
25946  if (sdest(prevseg) != pa) sesymself(prevseg);
25947  assert(sdest(prevseg) == pa);
25948  senextself(prevseg);
25949  senext2self(*supseg);
25950  sbond(*supseg, prevseg);
25951  senextself(*supseg); // Restore original state.
25952  assert(supseg->shver < 2);
25953  }
25954  // Restore old connection at b.
25955  senext(nsupseg, nextseg);
25956  spivotself(nextseg);
25957  if (nextseg.sh != dummysh) {
25958  nextseg.shver = 0;
25959  if (sorg(nextseg) != pb) sesymself(nextseg);
25960  assert(sorg(nextseg) == pb);
25961  senext2self(nextseg);
25962  senextself(nsupseg);
25963  sbond(nsupseg, nextseg);
25964  // nsupseg.shver = 0;
25965  senext2self(nsupseg); // Restore original state
25966  assert(nsupseg.shver < 2);
25967  }
25968  // Delete the new segment ab.
25969  shellfacedealloc(subsegs, newseg.sh);
25970  // Restore old C_i(p).
25971  for (i = 0; i < spinshlist->len(); i++) {
25972  replacepolygonsubs(newshlist[i], oldshlist[i]);
25973  // Delete subs of the new C_i(p)
25974  for (j = 0; j < newshlist[i]->len(); j++) {
25975  newsh = * (face *)(* (newshlist[i]))[j];
25976  shellfacedealloc(subfaces, newsh.sh);
25977  }
25978  }
25979  // Restore old B_i(p).
25980  for (i = 0; i < spinshlist->len(); i++) {
25981  if (oldtetlist[i] != (list *) NULL) {
25982  // Uninfect tets of old B_i(p).
25983  for (j = 0; j < oldtetlist[i]->len(); j++) {
25984  oldtet = * (triface *)(* (oldtetlist[i]))[j];
25985  assert(infected(oldtet));
25986  uninfect(oldtet);
25987  }
25988  // Has it been re-meshed?
25989  if (newtetlist[i]->len() > 0) {
25990  // Restore the old B_i(p).
25991  restorepolyhedron(oldtetlist[i]);
25992  // Delete tets of the new B_i(p);
25993  for (j = 0; j < newtetlist[i]->len(); j++) {
25994  newtet = * (triface *)(* (newtetlist[i]))[j];
25995  // Some new tets may already be deleted (by carvecavity()).
25996  if (!isdead(&newtet)) {
25997  tetrahedrondealloc(newtet.tet);
25998  }
25999  }
26000  }
26001  // Dealloc newpt[i] if it exists.
26002  if (newpt[i] != (point) NULL) {
26003  pointdealloc(newpt[i]);
26004  relverts--;
26005  }
26006  }
26007  }
26008  }
26009 
26010  // Delete work lists.
26011  delete dnewshlist;
26012  for (i = 0; i < spinshlist->len(); i++) {
26013  delete oldshlist[i];
26014  delete newshlist[i];
26015  }
26016  delete [] oldshlist;
26017  delete [] newshlist;
26018  for (i = 0; i < spinshlist->len(); i++) {
26019  if (oldtetlist[i] != (list *) NULL) {
26020  delete oldtetlist[i];
26021  delete newtetlist[i];
26022  }
26023  }
26024  delete [] oldtetlist;
26025  delete [] newtetlist;
26026  // Clear work lists.
26027  newsegshlist->clear();
26028  spinshlist->clear();
26029 
26030  return success;
26031 }
26032 
26034 // //
26035 // suppressvolpoint() Suppress a point inside mesh. //
26036 // //
26037 // The point p = org(suptet) is inside the mesh and will be suppressed from //
26038 // the mesh. Note that p may not be suppressed. //
26039 // //
26040 // 'optflag' is used for mesh optimization. If it is set, after removing p, //
26041 // test the object function on each new tet, queue bad tets. //
26042 // //
26044 
26045 bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist,
26046  list* misfrontlist, list* ptlist, queue* flipque, bool optflag)
26047 {
26048  list *myfrontlist, *mymisfrontlist, *myptlist;
26049  list *oldtetlist, *newtetlist;
26050  list *newshlist; // a dummy list.
26051  queue *myflipque;
26052  triface oldtet, newtet;
26053  point suppt, conpt;
26054  bool success;
26055  int j;
26056 
26057  // Allocate spaces for storing (old and new) B(p).
26058  oldtetlist = new list(sizeof(triface), NULL, 256);
26059  newtetlist = new list(sizeof(triface), NULL, 256);
26060  newshlist = new list(sizeof(face), NULL, 256);
26061  // Allocate work lists if user doesn't supply them.
26062  myfrontlist = mymisfrontlist = myptlist = (list *) NULL;
26063  myflipque = (queue *) NULL;
26064  if (frontlist == (list *) NULL) {
26065  myfrontlist = new list(sizeof(triface), NULL, 256);
26066  frontlist = myfrontlist;
26067  mymisfrontlist = new list(sizeof(triface), NULL, 256);
26068  misfrontlist = mymisfrontlist;
26069  myptlist = new list(sizeof(point *), NULL, 256);
26070  ptlist = myptlist;
26071  myflipque = new queue(sizeof(badface));
26072  flipque = myflipque;
26073  }
26074 
26075  suppt = org(*suptet);
26076  oldtet = *suptet;
26077  success = true; // Assume p can be suppressed.
26078 
26079  if (b->verbose > 1) {
26080  printf(" Remove point %d in mesh.\n", pointmark(suppt));
26081  }
26082 
26083  // Form old B(p) in oldtetlist.
26084  oldtetlist->append(&oldtet);
26085  formstarpolyhedron(suppt, oldtetlist, ptlist, false);
26086  // Infect the tets in old B(p) (they're going to be delete).
26087  for (j = 0; j < oldtetlist->len(); j++) {
26088  oldtet = * (triface *)(* oldtetlist)[j];
26089  infect(oldtet);
26090  }
26091  // Tetrahedralize old B(p).
26092  success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist,
26093  frontlist, misfrontlist, newtetlist, flipque);
26094  if (!success) {
26095  // Unable to suppress p.
26096  deallocfaketets(frontlist);
26097  // Try to collapse an edge at p.
26098  conpt = (point) NULL;
26099  assert(newtetlist->len() == 0);
26100  if (findcollapseedge(suppt, &conpt, oldtetlist, ptlist)) {
26101  // Collapse the edge suppt->conpt. Re-use newtetlist.
26102  collapseedge(suppt, conpt, oldtetlist, newtetlist);
26103  // The oldtetlist contains newtetlist.
26104  if (optflag) {
26105  assert(newtetlist->len() == 0);
26106  for (j = 0; j < oldtetlist->len(); j++) {
26107  newtet = * (triface *)(* oldtetlist)[j];
26108  newtetlist->append(&newtet);
26109  }
26110  }
26111  oldtetlist->clear(); // Do not delete them.
26112  collapverts++;
26113  success = true;
26114  }
26115  }
26116  if (success) {
26117  // p has been removed! (Still in the pool).
26118  setpointtype(suppt, UNUSEDVERTEX);
26119  unuverts++;
26120  suprelverts++;
26121  // Delete old B(p).
26122  for (j = 0; j < oldtetlist->len(); j++) {
26123  oldtet = * (triface *)(* oldtetlist)[j];
26124  assert(!isdead(&oldtet));
26125  tetrahedrondealloc(oldtet.tet);
26126  }
26127  if (optflag) {
26128  // Check for new bad tets.
26129  for (j = 0; j < newtetlist->len(); j++) {
26130  newtet = * (triface *)(* newtetlist)[j];
26131  if (!isdead(&newtet)) checktet4opt(&newtet, true);
26132  }
26133  }
26134  } else {
26135  // p is not suppressed. Recover the original state.
26136  // Uninfect tets of old B(p).
26137  for (j = 0; j < oldtetlist->len(); j++) {
26138  oldtet = * (triface *)(* oldtetlist)[j];
26139  assert(infected(oldtet));
26140  uninfect(oldtet);
26141  }
26142  }
26143 
26144  // Clear work lists.
26145  ptlist->clear();
26146  frontlist->clear();
26147  misfrontlist->clear();
26148  flipque->clear();
26149  // Deallocate work lists.
26150  if (myfrontlist != (list *) NULL) {
26151  delete myfrontlist;
26152  delete mymisfrontlist;
26153  delete myptlist;
26154  delete myflipque;
26155  }
26156  delete oldtetlist;
26157  delete newtetlist;
26158  delete newshlist;
26159 
26160  return success;
26161 }
26162 
26164 // //
26165 // smoothpoint() Smooth a volume/segment point. //
26166 // //
26167 // 'smthpt' (p) is inside the polyhedron (C) bounded by faces in 'starlist'. //
26168 // This routine moves p inside C until an object function is maximized. //
26169 // //
26170 // Default, the CCW edge ring of the faces on C points to p. If 'invtori' is //
26171 // TRUE, the orientation is inversed. //
26172 // //
26173 // If 'key' != NULL, it contains an object value to be improved. Current it //
26174 // means the cosine of the largest dihedral angle. In such case, the point //
26175 // is smoothed only if the final configuration improves the object value, it //
26176 // is returned by the 'key'. //
26177 // //
26179 
26180 bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist,
26181  bool invtori, REAL *key)
26182 {
26183  triface starttet;
26184  point pa, pb, pc;
26185  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
26186  REAL iniTmax, oldTmax, newTmax;
26187  REAL ori, aspT, aspTmax, imprate;
26188  REAL cosd, maxcosd;
26189  bool segflag, randflag; //, subflag;
26190  int numdirs;
26191  int iter, i, j;
26192 
26193  // Is p a segment vertex?
26194  segflag = (e1 != (point) NULL);
26195  // Decide the number of moving directions.
26196  numdirs = segflag ? 2 : starlist->len();
26197  randflag = numdirs > 10;
26198  if (randflag) {
26199  numdirs = 10; // Maximum 10 directions.
26200  }
26201 
26202  aspTmax = 0.0;
26203  // Calculate the initial object value (the largest aspect ratio).
26204  for (i = 0; i < starlist->len(); i++) {
26205  starttet = * (triface *)(* starlist)[i];
26206  adjustedgering(starttet, !invtori ? CCW : CW);
26207  pa = org(starttet);
26208  pb = dest(starttet);
26209  pc = apex(starttet);
26210  aspT = tetaspectratio(pa, pb, pc, smthpt);
26211  if (i == 0) {
26212  aspTmax = aspT;
26213  } else {
26214  aspTmax = aspT > aspTmax ? aspT : aspTmax;
26215  }
26216  }
26217  iniTmax = aspTmax;
26218 
26219  if (b->verbose > 1) {
26220  printf(" Smooth %s point %d (%g, %g, %g).\n", segflag ? "seg" : "vol",
26221  pointmark(smthpt), smthpt[0], smthpt[1], smthpt[2]);
26222  printf(" Initial max L/h = %g.\n", iniTmax);
26223  }
26224  for (i = 0; i < 3; i++) {
26225  bestpt[i] = startpt[i] = smthpt[i];
26226  }
26227 
26228  // Do iteration until the new aspTmax does not decrease.
26229  newTmax = iniTmax;
26230  iter = 0;
26231  while (true) {
26232  // Find the best next location.
26233  oldTmax = newTmax;
26234  for (i = 0; i < numdirs; i++) {
26235  // Calculate the moved point (saved in 'nextpt').
26236  if (!segflag) {
26237  if (randflag) {
26238  // Randomly pick a direction.
26239  j = (int) randomnation(starlist->len());
26240  } else {
26241  j = i;
26242  }
26243  starttet = * (triface *)(* starlist)[j];
26244  adjustedgering(starttet, !invtori ? CCW : CW);
26245  pa = org(starttet);
26246  pb = dest(starttet);
26247  pc = apex(starttet);
26248  for (j = 0; j < 3; j++) {
26249  fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
26250  }
26251  } else {
26252  for (j = 0; j < 3; j++) {
26253  fcent[j] = (i == 0 ? e1[j] : e2[j]);
26254  }
26255  }
26256  for (j = 0; j < 3; j++) {
26257  nextpt[j] = startpt[j] + 0.01 * (fcent[j] - startpt[j]);
26258  }
26259  // Get the largest object value for the new location.
26260  for (j = 0; j < starlist->len(); j++) {
26261  starttet = * (triface *)(* starlist)[j];
26262  adjustedgering(starttet, !invtori ? CCW : CW);
26263  pa = org(starttet);
26264  pb = dest(starttet);
26265  pc = apex(starttet);
26266  ori = orient3d(pa, pb, pc, nextpt);
26267  if (ori < 0.0) {
26268  aspT = tetaspectratio(pa, pb, pc, nextpt);
26269  if (j == 0) {
26270  aspTmax = aspT;
26271  } else {
26272  aspTmax = aspT > aspTmax ? aspT : aspTmax;
26273  }
26274  } else {
26275  // An invalid new tet. Discard this point.
26276  aspTmax = newTmax;
26277  } // if (ori < 0.0)
26278  // Stop looping when the object value is bigger than before.
26279  if (aspTmax >= newTmax) break;
26280  } // for (j = 0; j < starlist->len(); j++)
26281  if (aspTmax < newTmax) {
26282  // Save the improved object value and the location.
26283  newTmax = aspTmax;
26284  for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
26285  }
26286  } // for (i = 0; i < starlist->len(); i++)
26287  // Does the object value improved much?
26288  imprate = fabs(oldTmax - newTmax) / oldTmax;
26289  if (imprate < 1e-3) break;
26290  // Yes, move p to the new location and continue.
26291  for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
26292  iter++;
26293  } // while (true)
26294 
26295  if (iter > 0) {
26296  // The point is moved.
26297  if (key) {
26298  // Check if the quality is improved by the smoothed point.
26299  maxcosd = 0.0; // = cos(90.0).
26300  for (j = 0; j < starlist->len(); j++) {
26301  starttet = * (triface *)(* starlist)[j];
26302  adjustedgering(starttet, !invtori ? CCW : CW);
26303  pa = org(starttet);
26304  pb = dest(starttet);
26305  pc = apex(starttet);
26306  tetalldihedral(pa, pb, pc, startpt, NULL, &cosd, NULL);
26307  if (cosd < *key) {
26308  // This quality will not be improved. Stop.
26309  iter = 0; break;
26310  } else {
26311  // Remeber the worst quality value (of the new configuration).
26312  maxcosd = maxcosd < cosd ? maxcosd : cosd;
26313  }
26314  }
26315  if (iter > 0) *key = maxcosd;
26316  }
26317  }
26318 
26319  if (iter > 0) {
26320  segflag ? smoothsegverts++ : smoothvolverts++;
26321  for (i = 0; i < 3; i++) smthpt[i] = startpt[i];
26322  if (b->verbose > 1) {
26323  printf(" Move to new location (%g, %g, %g).\n", smthpt[0], smthpt[1],
26324  smthpt[2]);
26325  printf(" Final max L/h = %g. (%d iterations)\n", newTmax, iter);
26326  if (key) {
26327  printf(" Max. dihed = %g (degree).\n", acos(*key) / PI * 180.0);
26328  }
26329  }
26330  return true;
26331  } else {
26332  if (b->verbose > 1) {
26333  printf(" Not smoothed.\n");
26334  }
26335  return false;
26336  }
26337 }
26338 
26340 // //
26341 // removesteiners() Delete or relocate Steiner points on facets. //
26342 // //
26344 
26345 void tetgenmesh::removesteiners(bool coarseflag)
26346 {
26347  list *frontlist, *misfrontlist;
26348  list *spinshlist, *newsegshlist;
26349  list *ptlist, *conlist;
26350  memorypool *viri;
26351  queue *flipque;
26352  triface checktet;
26353  face shloop;
26354  face segloop, nextseg;
26355  point pa, neipt;
26356  REAL len;
26357  bool remflag;
26358  int *worklist;
26359  int oldnum, rmstein;
26360  int i, j;
26361 
26362  if (!b->quiet) {
26363  if (!coarseflag) {
26364  printf("Removing Steiner points.\n");
26365  } else {
26366  printf("Coarsening mesh.\n");
26367  }
26368  }
26369 
26370  // Initialize work lists.
26371  frontlist = new list(sizeof(triface), NULL);
26372  misfrontlist = new list(sizeof(triface), NULL);
26373  spinshlist = new list(sizeof(face), NULL);
26374  newsegshlist = new list(sizeof(face), NULL);
26375  ptlist = new list(sizeof(point *), NULL);
26376  conlist = new list(sizeof(point *) * 2, NULL);
26377  flipque = new queue(sizeof(badface));
26378  viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0);
26379  oldnum = unuverts;
26380  relverts = suprelverts = collapverts = unsupverts;
26381  smoothvolverts = 0;
26382  expcavcount = 0;
26383 
26384  // Suppress Steiner points inside facets.
26385  do {
26386  rmstein = unuverts;
26387  subfaces->traversalinit();
26388  shloop.sh = shellfacetraverse(subfaces);
26389  while (shloop.sh != (shellface *) NULL) {
26390  remflag = false;
26391  // Is s contains a Steiner point?
26392  shloop.shver = 0;
26393  for (i = 0; i < 3; i++) {
26394  pa = sapex(shloop);
26395  if (pointtype(pa) == FREESUBVERTEX) {
26396  if (!coarseflag) {
26397  // Remove it if it is not an input point.
26398  j = pointmark(pa) - in->firstnumber;
26399  if (j >= in->numberofpoints) {
26400  if (b->nobisect == 1) {
26401  // '-Y'. Remove p if s is a hull face.
26402  stpivot(shloop, checktet);
26403  if (checktet.tet != dummytet) {
26404  sesymself(shloop);
26405  stpivot(shloop, checktet);
26406  }
26407  remflag = (checktet.tet == dummytet);
26408  } else {
26409  // '-YY'. Remove p whatever s is a hull face or not.
26410  remflag = true;
26411  }
26412  }
26413  } else {
26414  // Check if this vertex can be coarsed.
26415  if (b->nobisect == 0) {
26416  // Is a background mesh available?
26417  if (b->metric) {
26418  // assert(pa[pointmtrindex] > 0.0);
26419  // Form the star of pa.
26420  spinshlist->append(&shloop);
26421  formstarpolygon(pa, spinshlist, ptlist);
26422  len = 0.0;
26423  for (j = 0; j < ptlist->len(); j++) {
26424  neipt = * (point *)(* ptlist)[j];
26425  len += distance(pa, neipt);
26426  }
26427  len /= ptlist->len();
26428  // Carse it if the average edge length is small.
26429  remflag = len < pa[pointmtrindex];
26430  spinshlist->clear();
26431  ptlist->clear();
26432  } else {
26433  // Coarse it if (1) it is an input point and its pointmarker
26434  // is zero, or (2) it is a Steiner point.
26435  remflag = true;
26436  j = pointmark(pa) - in->firstnumber;
26437  if (j < in->numberofpoints) {
26438  remflag = (in->pointmarkerlist[j] == 0);
26439  }
26440  } // if (b->metric)
26441  } // if (b->nobisect == 0)
26442  } // if (!coarseflag)
26443  if (remflag) break;
26444  } // if (pointtype(pa) == FREESUBVERTEX)
26445  senextself(shloop);
26446  } // for (i = 0; i < 3; i++)
26447  if (remflag) {
26448  suppressfacetpoint(&shloop, frontlist, misfrontlist, ptlist, conlist,
26449  viri, flipque, coarseflag, false);
26450  }
26451  shloop.sh = shellfacetraverse(subfaces);
26452  }
26453  // Continue if any Steiner point has been removed.
26454  } while (unuverts > rmstein);
26455 
26456  if (coarseflag) {
26457  shellface **segsperverlist;
26458  int *idx2seglist;
26459  face seg1, seg2;
26460  point e1, e2;
26461  // Connecting collinear segments. Hence the segment vertices may be
26462  // removed. In fact, this should be done by reconstructmesh().
26463  makesegmentmap(idx2seglist, segsperverlist);
26464  subsegs->traversalinit();
26465  segloop.sh = shellfacetraverse(subsegs);
26466  while (segloop.sh != (shellface *) NULL) {
26467  for (i = 0; i < 2; i++) {
26468  segloop.shver = i;
26469  senext(segloop, nextseg);
26470  spivotself(nextseg);
26471  if ((nextseg.sh == dummysh) || (nextseg.sh > segloop.sh)) {
26472  // No neighbor segment connection or haven't been processed yet.
26473  pa = sdest(segloop);
26474  j = pointmark(pa) - in->firstnumber;
26475  if (idx2seglist[j + 1] - idx2seglist[j] == 2) {
26476  // pa is shared by only two segments. Get the other one.
26477  nextseg.sh = segsperverlist[idx2seglist[j]];
26478  if (nextseg.sh == segloop.sh) {
26479  nextseg.sh = segsperverlist[idx2seglist[j] + 1];
26480  }
26481  nextseg.shver = 0;
26482  if (sorg(nextseg) != pa) sesymself(nextseg);
26483  // Check if the two segments are collinear.
26484  e1 = sorg(segloop);
26485  e2 = sdest(nextseg);
26486  if (iscollinear(e1, pa, e2, b->epsilon)) {
26487  // Connect the two segments together.
26488  if (b->verbose > 1) {
26489  printf(" Glue two insegs (%d, %d) at %d.\n", pointmark(e1),
26490  pointmark(e2), pointmark(pa));
26491  }
26492  senext(segloop, seg1);
26493  senext2(nextseg, seg2);
26494  sbond(seg1, seg2);
26495  }
26496  }
26497  } // if (nextseg.sh == dummysh)
26498  } // for (i = 0;
26499  segloop.sh = shellfacetraverse(subsegs);
26500  }
26501  delete [] segsperverlist;
26502  delete [] idx2seglist;
26503  }
26504 
26505  // Suppress Steiner points on segments.
26506  do {
26507  rmstein = unuverts;
26508  subsegs->traversalinit();
26509  segloop.sh = shellfacetraverse(subsegs);
26510  while (segloop.sh != (shellface *) NULL) {
26511  remflag = false;
26512  // for (i = 0; i < 2; i++) {
26513  // Don't check the poinytype of pa, it may be a Steiner point but
26514  // has type NACUTEVERTEX due to splitting a type-3 segment.
26515  segloop.shver = 0; // segloop.shver = i;
26516  senext(segloop, nextseg);
26517  spivotself(nextseg);
26518  if (nextseg.sh != dummysh) {
26519  pa = sdest(segloop); // p is going to be checked for removal.
26520  nextseg.shver = 0;
26521  if (sorg(nextseg) != pa) sesymself(nextseg);
26522  assert(sorg(nextseg) == pa);
26523  if (!coarseflag) {
26524  // try to remove it if it is not an input point.
26525  j = pointmark(pa) - in->firstnumber;
26526  if (j >= in->numberofpoints) {
26527  if (b->nobisect == 1) {
26528  // '-Y'. Remove p if it is on the hull.
26529  sstpivot(&segloop, &checktet);
26530  assert(checktet.tet != dummytet);
26531  pa = apex(checktet);
26532  do {
26533  if (!fnextself(checktet)) {
26534  // Meet a boundary face - p is on the hull.
26535  remflag = true; break;
26536  }
26537  } while (pa != apex(checktet));
26538  } else {
26539  // '-YY'. Remove p whatever it is on the hull or not.
26540  remflag = true;
26541  }
26542  }
26543  } else {
26544  // Check if this vertex can be coarsed.
26545  if (b->nobisect == 0) {
26546  if (b->metric) {
26547  // assert(pa[pointmtrindex] > 0.0);
26548  len = 0.0;
26549  neipt = sorg(segloop);
26550  for (j = 0; j < 2; j++) {
26551  len += distance(pa, neipt);
26552  /*// Is neipt inside the sparse ball of pa?
26553  if (len < pa[pointmtrindex]) {
26554  // Yes, the local of pa is too dense, corse it.
26555  remflag = true; break;
26556  } */
26557  neipt = sdest(nextseg);
26558  }
26559  len /= 2.0;
26560  // Carse it if the average edge lengh is small.
26561  remflag = len < pa[pointmtrindex];
26562  } else {
26563  // Coarse it if (1) it is an input point and its pointmarker
26564  // is zero, or (2) it is a Steiner point.
26565  remflag = true;
26566  j = pointmark(pa) - in->firstnumber;
26567  if (j < in->numberofpoints) {
26568  remflag = (in->pointmarkerlist[j] == 0);
26569  }
26570  } // if (b->metric)
26571  } // if (b->nobisect == 0)
26572  } // if (!coarseflag)
26573  } // if (nextseg.sh != dummysh)
26574  // if (remflag) break;
26575  // } // for (i = 0; i < 2; i++)
26576  if (remflag) {
26577  suppresssegpoint(&segloop, spinshlist, newsegshlist, frontlist,
26578  misfrontlist, ptlist, conlist, viri, flipque, coarseflag, false);
26579  }
26580  segloop.sh = shellfacetraverse(subsegs);
26581  }
26582  // Continue if any Steiner point has been removed.
26583  } while (unuverts > rmstein);
26584 
26585  if ((relverts > 0) || coarseflag) {
26586  worklist = new int[points->items + 1];
26587  // Suppress relocated points & coarse free mesh points.
26588  do {
26589  // Initialize the work list. Each entry of the list counts how many
26590  // times the point has been processed.
26591  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
26592  rmstein = unuverts;
26593  tetrahedrons->traversalinit();
26594  checktet.tet = tetrahedrontraverse();
26595  while (checktet.tet != (tetrahedron *) NULL) {
26596  remflag = false;
26597  for (i = 0; i < 4; i++) {
26598  pa = (point) checktet.tet[4 + i];
26599  if (pointtype(pa) == FREEVOLVERTEX) {
26600  // NOTE. Chenge the number 3 will change the number n of removed
26601  // Steiner points. In my test, n is larger when it is 1. 3
26602  // reduces n in a reasonable way (see example, mech_part,
26603  // thepart), 5 results a larger n than 3 does. While the best
26604  // result is no limit of this number, but it makes the code
26605  // extremely slow.
26606  if (worklist[pointmark(pa)] < 3) {
26607  worklist[pointmark(pa)]++;
26608  if (!coarseflag) {
26609  // Remove p if it is a Steiner point.
26610  if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
26611  remflag = true;
26612  }
26613  } else {
26614  if (b->metric) {
26615  // assert(pa[pointmtrindex] > 0.0);
26616  // Form the star of pa.
26617  frontlist->append(&checktet);
26618  formstarpolyhedron(pa, frontlist, ptlist, true);
26619  len = 0.0;
26620  for (j = 0; j < ptlist->len(); j++) {
26621  neipt = * (point *)(* ptlist)[j];
26622  len += distance(pa, neipt);
26623  }
26624  len /= ptlist->len();
26625  // Carse it if the average edge length is small.
26626  remflag = len < pa[pointmtrindex];
26627  frontlist->clear();
26628  ptlist->clear();
26629  } else {
26630  // Coarse it if (1) it is an input point and its pointmarker
26631  // is zero, or (2) it is a Steiner point.
26632  remflag = true;
26633  j = pointmark(pa) - in->firstnumber;
26634  if (j < in->numberofpoints) {
26635  remflag = (in->pointmarkerlist[j] == 0);
26636  }
26637  } // if (b->metric)
26638  } // if (!coarseflag)
26639  if (remflag) break;
26640  } // if (worklist[pointmark(pa)] == 0)
26641  } // if (pointtype(pa) == FREEVOLVERTEX)
26642  } // for (i = 0; i < 4; i++)
26643  if (remflag) {
26644  findorg(&checktet, pa);
26645  assert(org(checktet) == pa);
26646  suppressvolpoint(&checktet, frontlist, misfrontlist, ptlist, flipque,
26647  false);
26648  }
26649  checktet.tet = tetrahedrontraverse();
26650  }
26651  // Continue if any relocated point has been suppressed.
26652  } while (unuverts > rmstein);
26653 
26654 
26655  // Smooth the unsuppressed points if it is not coarse mesh.
26656  if (!coarseflag && (relverts > suprelverts)) {
26657  if (b->verbose) {
26658  printf(" Smoothing relocated points.\n");
26659  }
26660  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
26661  tetrahedrons->traversalinit();
26662  checktet.tet = tetrahedrontraverse();
26663  while (checktet.tet != (tetrahedron *) NULL) {
26664  for (i = 0; i < 4; i++) {
26665  pa = (point) checktet.tet[4 + i];
26666  if (pointtype(pa) == FREEVOLVERTEX) {
26667  if (worklist[pointmark(pa)] == 0) {
26668  worklist[pointmark(pa)] = 1;
26669  if (pointmark(pa) >= (in->numberofpoints + in->firstnumber)) {
26670  // Smooth pa.
26671  findorg(&checktet, pa);
26672  frontlist->append(&checktet);
26673  formstarpolyhedron(pa, frontlist, NULL, false);
26674  smoothpoint(pa, NULL, NULL, frontlist, false, NULL);
26675  frontlist->clear();
26676  }
26677  } // if (worklist[pointmark(pa)] == 0)
26678  } // if (pointtype(pa) == FREEVOLVERTEX)
26679  } // for (i = 0; i < 4; i++)
26680  checktet.tet = tetrahedrontraverse();
26681  }
26682  }
26683  delete [] worklist;
26684  }
26685 
26686  if (b->verbose > 0) {
26687  if (!coarseflag) {
26688  printf(" %d points removed from boundary", unuverts - oldnum);
26689  if (expcavcount > 0) {
26690  printf(" (%d cavity corrections)", expcavcount);
26691  }
26692  printf("\n");
26693  if (relverts > 0) {
26694  printf(" %d points relocated (%d suppressed, %d collapsed).\n",
26695  relverts, suprelverts - collapverts, collapverts);
26696  if (smoothvolverts > 0) {
26697  printf(" %d points are smoothed.\n", smoothvolverts);
26698  }
26699  }
26700  if (unsupverts > 0) {
26701  printf(" !! %d points are unsuppressed.\n", unsupverts);
26702  }
26703  } else {
26704  printf(" %d points are removed.\n", unuverts - oldnum);
26705  }
26706  }
26707 
26708  // Delete work lists.
26709  delete frontlist;
26710  delete misfrontlist;
26711  delete spinshlist;
26712  delete newsegshlist;
26713  delete ptlist;
26714  delete conlist;
26715  delete flipque;
26716  delete viri;
26717 }
26718 
26719 //
26720 // End of boundary Steiner points removing routines
26721 //
26722 
26724 // //
26725 // reconstructmesh() Reconstruct a tetrahedral mesh from a list of //
26726 // tetrahedra and possibly a list of boundary faces. //
26727 // //
26728 // The list of tetrahedra is stored in 'in->tetrahedronlist', the list of //
26729 // boundary faces is stored in 'in->trifacelist'. The tetrahedral mesh is //
26730 // reconstructed in memorypool 'tetrahedrons', its boundary faces (subfaces) //
26731 // are reconstructed in 'subfaces', its boundary edges (subsegments) are //
26732 // reconstructed in 'subsegs'. If the -a switch is used, this procedure will //
26733 // also read a list of REALs from 'in->tetrahedronvolumelist' and set a //
26734 // maximum volume constraint on each tetrahedron. //
26735 // //
26736 // If the user has provided the boundary faces in 'in->trifacelist', they //
26737 // will be inserted the mesh. Otherwise subfaces will be identified from the //
26738 // mesh. All hull faces (including faces of the internal holes) will be //
26739 // recognized as subfaces, internal faces between two tetrahedra which have //
26740 // different attributes will also be recognized as subfaces. //
26741 // //
26742 // Subsegments will be identified after subfaces are reconstructed. Edges at //
26743 // the intersections of non-coplanar subfaces are recognized as subsegments. //
26744 // Edges between two coplanar subfaces with different boundary markers are //
26745 // also recognized as subsegments. //
26746 // //
26747 // The facet index of each subface will be set automatically after we have //
26748 // recovered subfaces and subsegments. That is, the set of subfaces, which //
26749 // are coplanar and have the same boundary marker will be recognized as a //
26750 // facet and has a unique index, stored as the facet marker in each subface //
26751 // of the set, the real boundary marker of each subface will be found in //
26752 // 'in->facetmarkerlist' by the index. Facet index will be used in Delaunay //
26753 // refinement for detecting two incident facets. //
26754 // //
26755 // Points which are not corners of tetrahedra will be inserted into the mesh.//
26756 // Return the number of faces on the hull after the reconstruction. //
26757 // //
26759 
26760 long tetgenmesh::reconstructmesh()
26761 {
26762  tetrahedron **tetsperverlist;
26763  shellface **facesperverlist;
26764  triface tetloop, neightet, neineightet, spintet;
26765  face subloop, neighsh, neineighsh, subseg;
26766  face sface1, sface2;
26767  point *idx2verlist;
26768  point torg, tdest, tapex, toppo;
26769  point norg, ndest, napex;
26770  list *neighshlist, *markerlist;
26771  REAL sign, attrib, volume;
26772  REAL da1, da2;
26773  bool bondflag, insertsegflag;
26774  int *idx2tetlist;
26775  int *idx2facelist;
26776  int *worklist;
26777  int facetidx, marker;
26778  int iorg, idest, iapex, ioppo;
26779  int inorg, indest, inapex;
26780  int index, i, j;
26781 
26782  if (!b->quiet) {
26783  printf("Reconstructing mesh.\n");
26784  }
26785 
26786  // Create a map from index to points.
26787  makeindex2pointmap(idx2verlist);
26788 
26789  // Create the tetrahedra.
26790  for (i = 0; i < in->numberoftetrahedra; i++) {
26791  // Create a new tetrahedron and set its four corners, make sure that
26792  // four corners form a positive orientation.
26793  maketetrahedron(&tetloop);
26794  index = i * in->numberofcorners;
26795  // Although there may be 10 nodes, we only read the first 4.
26796  iorg = in->tetrahedronlist[index] - in->firstnumber;
26797  idest = in->tetrahedronlist[index + 1] - in->firstnumber;
26798  iapex = in->tetrahedronlist[index + 2] - in->firstnumber;
26799  ioppo = in->tetrahedronlist[index + 3] - in->firstnumber;
26800  torg = idx2verlist[iorg];
26801  tdest = idx2verlist[idest];
26802  tapex = idx2verlist[iapex];
26803  toppo = idx2verlist[ioppo];
26804  sign = orient3d(torg, tdest, tapex, toppo);
26805  if (sign > 0.0) {
26806  norg = torg; torg = tdest; tdest = norg;
26807  } else if (sign == 0.0) {
26808  if (!b->quiet) {
26809  printf("Warning: Tet %d is degenerate.\n", i + in->firstnumber);
26810  }
26811  }
26812  setorg(tetloop, torg);
26813  setdest(tetloop, tdest);
26814  setapex(tetloop, tapex);
26815  setoppo(tetloop, toppo);
26816  // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that
26817  // they belong to the mesh. These types may be changed later.
26818  setpointtype(torg, FREEVOLVERTEX);
26819  setpointtype(tdest, FREEVOLVERTEX);
26820  setpointtype(tapex, FREEVOLVERTEX);
26821  setpointtype(toppo, FREEVOLVERTEX);
26822  // Set element attributes if they exist.
26823  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
26824  index = i * in->numberoftetrahedronattributes;
26825  attrib = in->tetrahedronattributelist[index + j];
26826  setelemattribute(tetloop.tet, j, attrib);
26827  }
26828  // If -a switch is used (with no number follows) Set a volume
26829  // constraint if it exists.
26830  if (b->varvolume) {
26831  if (in->tetrahedronvolumelist != (REAL *) NULL) {
26832  volume = in->tetrahedronvolumelist[i];
26833  } else {
26834  volume = -1.0;
26835  }
26836  setvolumebound(tetloop.tet, volume);
26837  }
26838  }
26839 
26840  // Set the connection between tetrahedra.
26841  hullsize = 0l;
26842  // Create a map from nodes to tetrahedra.
26843  maketetrahedronmap(idx2tetlist, tetsperverlist);
26844  // Initialize the worklist.
26845  worklist = new int[points->items];
26846  for (i = 0; i < points->items; i++) worklist[i] = 0;
26847 
26848  // Loop all tetrahedra, bond two tetrahedra if they share a common face.
26849  tetrahedrons->traversalinit();
26850  tetloop.tet = tetrahedrontraverse();
26851  while (tetloop.tet != (tetrahedron *) NULL) {
26852  // Loop the four sides of the tetrahedron.
26853  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
26854  sym(tetloop, neightet);
26855  if (neightet.tet != dummytet) continue; // This side has finished.
26856  torg = org(tetloop);
26857  tdest = dest(tetloop);
26858  tapex = apex(tetloop);
26859  iorg = pointmark(torg) - in->firstnumber;
26860  idest = pointmark(tdest) - in->firstnumber;
26861  iapex = pointmark(tapex) - in->firstnumber;
26862  worklist[iorg] = 1;
26863  worklist[idest] = 1;
26864  worklist[iapex] = 1;
26865  bondflag = false;
26866  // Search its neighbor in the adjacent tets of torg.
26867  for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag;
26868  j++) {
26869  if (tetsperverlist[j] == tetloop.tet) continue; // Skip myself.
26870  neightet.tet = tetsperverlist[j];
26871  for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
26872  sym(neightet, neineightet);
26873  if (neineightet.tet == dummytet) {
26874  norg = org(neightet);
26875  ndest = dest(neightet);
26876  napex = apex(neightet);
26877  inorg = pointmark(norg) - in->firstnumber;
26878  indest = pointmark(ndest) - in->firstnumber;
26879  inapex = pointmark(napex) - in->firstnumber;
26880  if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) {
26881  // Find! Bond them together and break the loop.
26882  bond(tetloop, neightet);
26883  bondflag = true;
26884  break;
26885  }
26886  }
26887  }
26888  }
26889  if (!bondflag) {
26890  hullsize++; // It's a hull face.
26891  // Bond this side to outer space.
26892  dummytet[0] = encode(tetloop);
26893  if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) {
26894  // Set its three corners's markers be boundary (hull) vertices.
26895  if (in->pointmarkerlist[iorg] == 0) {
26896  in->pointmarkerlist[iorg] = 1;
26897  }
26898  if (in->pointmarkerlist[idest] == 0) {
26899  in->pointmarkerlist[idest] = 1;
26900  }
26901  if (in->pointmarkerlist[iapex] == 0) {
26902  in->pointmarkerlist[iapex] = 1;
26903  }
26904  }
26905  }
26906  worklist[iorg] = 0;
26907  worklist[idest] = 0;
26908  worklist[iapex] = 0;
26909  }
26910  tetloop.tet = tetrahedrontraverse();
26911  }
26912 
26913  // Subfaces will be inserted into the mesh. It has two phases:
26914  // (1) Insert subfaces provided by user (in->trifacelist);
26915  // (2) Create subfaces for hull faces (if they're not subface yet) and
26916  // interior faces which separate two different materials.
26917 
26918  // Phase (1). Is there a list of user-provided subfaces?
26919  if (in->trifacelist != (int *) NULL) {
26920  // Recover subfaces from 'in->trifacelist'.
26921  for (i = 0; i < in->numberoftrifaces; i++) {
26922  index = i * 3;
26923  iorg = in->trifacelist[index] - in->firstnumber;
26924  idest = in->trifacelist[index + 1] - in->firstnumber;
26925  iapex = in->trifacelist[index + 2] - in->firstnumber;
26926  // Look for the location of this subface.
26927  worklist[iorg] = 1;
26928  worklist[idest] = 1;
26929  worklist[iapex] = 1;
26930  bondflag = false;
26931  // Search its neighbor in the adjacent tets of torg.
26932  for (j = idx2tetlist[iorg]; j < idx2tetlist[iorg + 1] && !bondflag;
26933  j++) {
26934  neightet.tet = tetsperverlist[j];
26935  for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) {
26936  norg = org(neightet);
26937  ndest = dest(neightet);
26938  napex = apex(neightet);
26939  inorg = pointmark(norg) - in->firstnumber;
26940  indest = pointmark(ndest) - in->firstnumber;
26941  inapex = pointmark(napex) - in->firstnumber;
26942  if ((worklist[inorg] + worklist[indest] + worklist[inapex]) == 3) {
26943  bondflag = true; // Find!
26944  break;
26945  }
26946  }
26947  }
26948  if (bondflag) {
26949  // Create a new subface and insert it into the mesh.
26950  makeshellface(subfaces, &subloop);
26951  torg = idx2verlist[iorg];
26952  tdest = idx2verlist[idest];
26953  tapex = idx2verlist[iapex];
26954  setsorg(subloop, torg);
26955  setsdest(subloop, tdest);
26956  setsapex(subloop, tapex);
26957  // Set the vertices be FREESUBVERTEX to indicate they belong to a
26958  // facet of the domain. They may be changed later.
26959  setpointtype(torg, FREESUBVERTEX);
26960  setpointtype(tdest, FREESUBVERTEX);
26961  setpointtype(tapex, FREESUBVERTEX);
26962  if (in->trifacemarkerlist != (int *) NULL) {
26963  setshellmark(subloop, in->trifacemarkerlist[i]);
26964  }
26965  adjustedgering(neightet, CCW);
26966  findedge(&subloop, org(neightet), dest(neightet));
26967  tsbond(neightet, subloop);
26968  sym(neightet, neineightet);
26969  if (neineightet.tet != dummytet) {
26970  sesymself(subloop);
26971  tsbond(neineightet, subloop);
26972  }
26973  } else {
26974  if (!b->quiet) {
26975  printf("Warning: Subface %d is discarded.\n", i + in->firstnumber);
26976  }
26977  }
26978  worklist[iorg] = 0;
26979  worklist[idest] = 0;
26980  worklist[iapex] = 0;
26981  }
26982  }
26983 
26984  // Phase (2). Indentify subfaces from the mesh.
26985  tetrahedrons->traversalinit();
26986  tetloop.tet = tetrahedrontraverse();
26987  while (tetloop.tet != (tetrahedron *) NULL) {
26988  // Loop the four sides of the tetrahedron.
26989  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
26990  tspivot(tetloop, subloop);
26991  if (subloop.sh != dummysh) continue;
26992  bondflag = false;
26993  sym(tetloop, neightet);
26994  if (neightet.tet == dummytet) {
26995  // It's a hull face. Insert a subface at here.
26996  bondflag = true;
26997  } else {
26998  // It's an interior face. Insert a subface if two tetrahedra have
26999  // different attributes (i.e., they belong to two regions).
27000  if (in->numberoftetrahedronattributes > 0) {
27001  if (elemattribute(neightet.tet,
27002  in->numberoftetrahedronattributes - 1) !=
27003  elemattribute(tetloop.tet,
27004  in->numberoftetrahedronattributes - 1)) {
27005  bondflag = true;
27006  }
27007  }
27008  }
27009  if (bondflag) {
27010  adjustedgering(tetloop, CCW);
27011  makeshellface(subfaces, &subloop);
27012  torg = org(tetloop);
27013  tdest = dest(tetloop);
27014  tapex = apex(tetloop);
27015  setsorg(subloop, torg);
27016  setsdest(subloop, tdest);
27017  setsapex(subloop, tapex);
27018  // Set the vertices be FREESUBVERTEX to indicate they belong to a
27019  // facet of the domain. They may be changed later.
27020  setpointtype(torg, FREESUBVERTEX);
27021  setpointtype(tdest, FREESUBVERTEX);
27022  setpointtype(tapex, FREESUBVERTEX);
27023  tsbond(tetloop, subloop);
27024  if (neightet.tet != dummytet) {
27025  sesymself(subloop);
27026  tsbond(neightet, subloop);
27027  }
27028  }
27029  }
27030  tetloop.tet = tetrahedrontraverse();
27031  }
27032 
27033  // Set the connection between subfaces. A subsegment may have more than
27034  // two subfaces sharing it, 'neighshlist' stores all subfaces sharing
27035  // one edge.
27036  neighshlist = new list(sizeof(face), NULL);
27037  // Create a map from nodes to subfaces.
27038  makesubfacemap(idx2facelist, facesperverlist);
27039 
27040  // Loop over the set of subfaces, setup the connection between subfaces.
27041  subfaces->traversalinit();
27042  subloop.sh = shellfacetraverse(subfaces);
27043  while (subloop.sh != (shellface *) NULL) {
27044  for (i = 0; i < 3; i++) {
27045  spivot(subloop, neighsh);
27046  if (neighsh.sh == dummysh) {
27047  // This side is 'empty', operate on it.
27048  torg = sorg(subloop);
27049  tdest = sdest(subloop);
27050  tapex = sapex(subloop);
27051  neighshlist->append(&subloop);
27052  iorg = pointmark(torg) - in->firstnumber;
27053  // Search its neighbor in the adjacent list of torg.
27054  for (j = idx2facelist[iorg]; j < idx2facelist[iorg + 1]; j++) {
27055  neighsh.sh = facesperverlist[j];
27056  if (neighsh.sh == subloop.sh) continue;
27057  neighsh.shver = 0;
27058  if (isfacehasedge(&neighsh, torg, tdest)) {
27059  findedge(&neighsh, torg, tdest);
27060  // Insert 'neighsh' into 'neighshlist'.
27061  if (neighshlist->len() < 2) {
27062  neighshlist->append(&neighsh);
27063  } else {
27064  for (index = 0; index < neighshlist->len() - 1; index++) {
27065  sface1 = * (face *)(* neighshlist)[index];
27066  sface2 = * (face *)(* neighshlist)[index + 1];
27067  da1 = facedihedral(torg, tdest, sapex(sface1), sapex(neighsh));
27068  da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2));
27069  if (da1 < da2) {
27070  break; // Insert it after index.
27071  }
27072  }
27073  neighshlist->insert(index + 1, &neighsh);
27074  }
27075  }
27076  }
27077  // Bond the subfaces in 'neighshlist'.
27078  if (neighshlist->len() > 1) {
27079  neighsh = * (face *)(* neighshlist)[0];
27080  for (j = 1; j <= neighshlist->len(); j++) {
27081  if (j < neighshlist->len()) {
27082  neineighsh = * (face *)(* neighshlist)[j];
27083  } else {
27084  neineighsh = * (face *)(* neighshlist)[0];
27085  }
27086  sbond1(neighsh, neineighsh);
27087  neighsh = neineighsh;
27088  }
27089  } else {
27090  // No neighbor subface be found, bond 'subloop' to itself.
27091  sbond(subloop, subloop);
27092  }
27093  neighshlist->clear();
27094  }
27095  senextself(subloop);
27096  }
27097  subloop.sh = shellfacetraverse(subfaces);
27098  }
27099 
27100  // Segments will be introudced. Each segment has a unique marker (1-based).
27101  marker = 1;
27102  subfaces->traversalinit();
27103  subloop.sh = shellfacetraverse(subfaces);
27104  while (subloop.sh != (shellface *) NULL) {
27105  for (i = 0; i < 3; i++) {
27106  sspivot(subloop, subseg);
27107  if (subseg.sh == dummysh) {
27108  // This side has no subsegment bonded, check it.
27109  torg = sorg(subloop);
27110  tdest = sdest(subloop);
27111  tapex = sapex(subloop);
27112  spivot(subloop, neighsh);
27113  spivot(neighsh, neineighsh);
27114  insertsegflag = false;
27115  if (subloop.sh == neighsh.sh || subloop.sh != neineighsh.sh) {
27116  // This side is either self-bonded or more than two subfaces,
27117  // insert a subsegment at this side.
27118  insertsegflag = true;
27119  } else {
27120  // Only two subfaces case.
27121 #ifdef SELF_CHECK
27122  assert(subloop.sh != neighsh.sh);
27123 #endif
27124  napex = sapex(neighsh);
27125  sign = orient3d(torg, tdest, tapex, napex);
27126  if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) {
27127  // Although they are coplanar, we still need to check if they
27128  // have the same boundary marker.
27129  insertsegflag = (shellmark(subloop) != shellmark(neighsh));
27130  } else {
27131  // Non-coplanar.
27132  insertsegflag = true;
27133  }
27134  }
27135  if (insertsegflag) {
27136  // Create a subsegment at this side.
27137  makeshellface(subsegs, &subseg);
27138  setsorg(subseg, torg);
27139  setsdest(subseg, tdest);
27140  // The two vertices have been marked as FREESUBVERTEX. Now mark
27141  // them as NACUTEVERTEX.
27142  setpointtype(torg, NACUTEVERTEX);
27143  setpointtype(tdest, NACUTEVERTEX);
27144  setshellmark(subseg, marker);
27145  marker++;
27146  // Bond all subfaces to this subsegment.
27147  neighsh = subloop;
27148  do {
27149  ssbond(neighsh, subseg);
27150  spivotself(neighsh);
27151  } while (neighsh.sh != subloop.sh);
27152  }
27153  }
27154  senextself(subloop);
27155  }
27156  subloop.sh = shellfacetraverse(subfaces);
27157  }
27158  // Remember the number of input segments.
27159  insegments = subsegs->items;
27160  // Find the acute vertices and set them be type ACUTEVERTEX.
27161 
27162  // Indentify facets and set the facet marker (1-based) for subfaces.
27163  markerlist = new list((char*)"int");
27164 
27165  subfaces->traversalinit();
27166  subloop.sh = shellfacetraverse(subfaces);
27167  while (subloop.sh != (shellface *) NULL) {
27168  // Only operate on uninfected subface, after operating, infect it.
27169  if (!sinfected(subloop)) {
27170  // A new facet is found.
27171  marker = shellmark(subloop);
27172  markerlist->append(&marker);
27173  facetidx = markerlist->len(); // 'facetidx' starts from 1.
27174  setshellmark(subloop, facetidx);
27175  sinfect(subloop);
27176  neighshlist->append(&subloop);
27177  // Find out all subfaces of this facet (bounded by subsegments).
27178  for (i = 0; i < neighshlist->len(); i++) {
27179  neighsh = * (face *) (* neighshlist)[i];
27180  for (j = 0; j < 3; j++) {
27181  sspivot(neighsh, subseg);
27182  if (subseg.sh == dummysh) {
27183  spivot(neighsh, neineighsh);
27184  if (!sinfected(neineighsh)) {
27185  // 'neineighsh' is in the same facet as 'subloop'.
27186 #ifdef SELF_CHECK
27187  assert(shellmark(neineighsh) == marker);
27188 #endif
27189  setshellmark(neineighsh, facetidx);
27190  sinfect(neineighsh);
27191  neighshlist->append(&neineighsh);
27192  }
27193  }
27194  senextself(neighsh);
27195  }
27196  }
27197  neighshlist->clear();
27198  }
27199  subloop.sh = shellfacetraverse(subfaces);
27200  }
27201  // Uninfect all subfaces.
27202  subfaces->traversalinit();
27203  subloop.sh = shellfacetraverse(subfaces);
27204  while (subloop.sh != (shellface *) NULL) {
27205 #ifdef SELF_CHECK
27206  assert(sinfected(subloop));
27207 #endif
27208  suninfect(subloop);
27209  subloop.sh = shellfacetraverse(subfaces);
27210  }
27211  // Save the facet markers in 'in->facetmarkerlist'.
27212  in->numberoffacets = markerlist->len();
27213  in->facetmarkerlist = new int[in->numberoffacets];
27214  for (i = 0; i < in->numberoffacets; i++) {
27215  marker = * (int *) (* markerlist)[i];
27216  in->facetmarkerlist[i] = marker;
27217  }
27218  // Initialize the 'facetabovepointlist'.
27219  facetabovepointarray = new point[in->numberoffacets + 1];
27220  for (i = 0; i < in->numberoffacets + 1; i++) {
27221  facetabovepointarray[i] = (point) NULL;
27222  }
27223 
27224  // The mesh contains boundary now.
27225  checksubfaces = 1;
27226  // The mesh is nonconvex now.
27227  nonconvex = 1;
27228 
27229  // Is there periodic boundary confitions?
27230  if (checkpbcs) {
27231  tetgenio::pbcgroup *pg;
27232  pbcdata *pd;
27233  // Initialize the global array 'subpbcgrouptable'.
27234  createsubpbcgrouptable();
27235  // Loop for each pbcgroup i.
27236  for (i = 0; i < in->numberofpbcgroups; i++) {
27237  pg = &(in->pbcgrouplist[i]);
27238  pd = &(subpbcgrouptable[i]);
27239  // Find all subfaces of pd, set each subface's group id be i.
27240  for (j = 0; j < 2; j++) {
27241  subfaces->traversalinit();
27242  subloop.sh = shellfacetraverse(subfaces);
27243  while (subloop.sh != (shellface *) NULL) {
27244  facetidx = shellmark(subloop);
27245  marker = in->facetmarkerlist[facetidx - 1];
27246  if (marker == pd->fmark[j]) {
27247  setshellpbcgroup(subloop, i);
27248  pd->ss[j] = subloop;
27249  }
27250  subloop.sh = shellfacetraverse(subfaces);
27251  }
27252  }
27253  if (pg->pointpairlist != (int *) NULL) {
27254  // Set the connections between pbc point pairs.
27255  for (j = 0; j < pg->numberofpointpairs; j++) {
27256  iorg = pg->pointpairlist[j * 2] - in->firstnumber;
27257  idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber;
27258  torg = idx2verlist[iorg];
27259  tdest = idx2verlist[idest];
27260  setpoint2pbcpt(torg, tdest);
27261  setpoint2pbcpt(tdest, torg);
27262  }
27263  }
27264  }
27265  // Create the global array 'segpbcgrouptable'.
27266  createsegpbcgrouptable();
27267  }
27268 
27269  delete markerlist;
27270  delete neighshlist;
27271  delete [] worklist;
27272  delete [] idx2tetlist;
27273  delete [] tetsperverlist;
27274  delete [] idx2facelist;
27275  delete [] facesperverlist;
27276  delete [] idx2verlist;
27277 
27278  return hullsize;
27279 }
27280 
27282 // //
27283 // insertconstrainedpoints() Insert a list of constrained points. //
27284 // //
27286 
27287 void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
27288 {
27289  queue *flipqueue;
27290  triface searchtet;
27291  face checksh, checkseg;
27292  point newpoint;
27293  enum locateresult loc;
27294  REAL *attr;
27295  bool insertflag;
27296  int covertices, outvertices;
27297  int index;
27298  int i, j;
27299 
27300  if (!b->quiet) {
27301  printf("Insert additional points into mesh.\n");
27302  }
27303  // Initialize 'flipqueue'.
27304  flipqueue = new queue(sizeof(badface));
27305  recenttet.tet = dummytet;
27306  covertices = outvertices = 0;
27307 
27308  index = 0;
27309  for (i = 0; i < addio->numberofpoints; i++) {
27310  // Create a newpoint.
27311  makepoint(&newpoint);
27312  newpoint[0] = addio->pointlist[index++];
27313  newpoint[1] = addio->pointlist[index++];
27314  newpoint[2] = addio->pointlist[index++];
27315  // Read the add point attributes if current points have attributes.
27316  if ((addio->numberofpointattributes > 0) &&
27317  (in->numberofpointattributes > 0)) {
27318  attr = addio->pointattributelist + addio->numberofpointattributes * i;
27319  for (j = 0; j < in->numberofpointattributes; j++) {
27320  if (j < addio->numberofpointattributes) {
27321  newpoint[3 + j] = attr[j];
27322  }
27323  }
27324  }
27325  // Find the location of the inserted point.
27326  searchtet = recenttet;
27327  loc = locate(newpoint, &searchtet);
27328  if (loc != ONVERTEX) {
27329  loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2);
27330  }
27331  if (loc == OUTSIDE) {
27332  loc = hullwalk(newpoint, &searchtet);
27333  if (loc == OUTSIDE) {
27334  // Perform a brute-force search.
27335  tetrahedrons->traversalinit();
27336  searchtet.tet = tetrahedrontraverse();
27337  while (searchtet.tet != (tetrahedron *) NULL) {
27338  loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon2);
27339  if (loc != OUTSIDE) break;
27340  searchtet.tet = tetrahedrontraverse();
27341  }
27342  }
27343  }
27344  // Insert the point if it not lies outside or on a vertex.
27345  insertflag = true;
27346  switch (loc) {
27347  case INTETRAHEDRON:
27348  setpointtype(newpoint, FREEVOLVERTEX);
27349  splittetrahedron(newpoint, &searchtet, flipqueue);
27350  break;
27351  case ONFACE:
27352  tspivot(searchtet, checksh);
27353  if (checksh.sh != dummysh) {
27354  // It is a boundary face. Don't insert it if -Y option is used.
27355  if (b->nobisect) {
27356  insertflag = false;
27357  } else {
27358  setpointtype(newpoint, FREESUBVERTEX);
27359  }
27360  } else {
27361  setpointtype(newpoint, FREEVOLVERTEX);
27362  }
27363  if (insertflag) {
27364  splittetface(newpoint, &searchtet, flipqueue);
27365  }
27366  break;
27367  case ONEDGE:
27368  tsspivot(&searchtet, &checkseg);
27369  if (checkseg.sh != dummysh) {
27370  if (b->nobisect) {
27371  insertflag = false;
27372  } else {
27373  setpointtype(newpoint, FREESEGVERTEX);
27374  setpoint2sh(newpoint, sencode(checkseg));
27375  }
27376  } else {
27377  tspivot(searchtet, checksh);
27378  if (checksh.sh != dummysh) {
27379  if (b->nobisect) {
27380  insertflag = false;
27381  } else {
27382  setpointtype(newpoint, FREESUBVERTEX);
27383  }
27384  } else {
27385  setpointtype(newpoint, FREEVOLVERTEX);
27386  }
27387  }
27388  if (insertflag) {
27389  splittetedge(newpoint, &searchtet, flipqueue);
27390  }
27391  break;
27392  case ONVERTEX:
27393  insertflag = false;
27394  covertices++;
27395  break;
27396  case OUTSIDE:
27397  insertflag = false;
27398  outvertices++;
27399  break;
27400  }
27401  // Remember the tetrahedron for next point searching.
27402  recenttet = searchtet;
27403  if (!insertflag) {
27404  pointdealloc(newpoint);
27405  } else {
27406  flip(flipqueue, NULL);
27407  }
27408  }
27409 
27410  if (b->verbose) {
27411  if (covertices > 0) {
27412  printf(" %d constrained points already exist.\n", covertices);
27413  }
27414  if (outvertices > 0) {
27415  printf(" %d constrained points lie outside the mesh.\n", outvertices);
27416  }
27417  printf(" %d constrained points have been inserted.\n",
27418  addio->numberofpoints - covertices - outvertices);
27419  }
27420 
27421  delete flipqueue;
27422 }
27423 
27425 // //
27426 // p1interpolatebgm() Set pt size by p^1 interpolation in background mesh.//
27427 // //
27428 // On input, 'bgmtet' is a suggesting tet in background mesh for searching //
27429 // 'pt'. It returns the tet containing 'pt'. //
27430 // //
27432 
27433 bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount)
27434 {
27435  point bgmpt[4];
27436  enum locateresult loc;
27437  REAL vol, volpt[4], weights[4];
27438  int i;
27439 
27440  loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items);
27441  if (loc == OUTSIDE) {
27442  loc = bgm->hullwalk(pt, bgmtet);
27443  if (loc == OUTSIDE) {
27444  // Perform a brute-force search.
27445  if (b->verbose) {
27446  printf("Warning: Global point location.\n");
27447  }
27448  if (scount) (*scount)++;
27449  bgm->tetrahedrons->traversalinit(); // in bgm
27450  bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
27451  while (bgmtet->tet != (tetrahedron *) NULL) {
27452  loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon);
27453  if (loc != OUTSIDE) break;
27454  bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm
27455  }
27456  }
27457  }
27458  if (loc != OUTSIDE) {
27459  // Let p remember t.
27460  setpoint2bgmtet(pt, encode(*bgmtet)); // in m
27461  // get the corners of t.
27462  for (i = 0; i < 4; i++) bgmpt[i] = (point) bgmtet->tet[4 + i];
27463  // Calculate the weighted coordinates of p in t.
27464  vol = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], bgmpt[3]);
27465  volpt[0] = orient3d(pt, bgmpt[1], bgmpt[2], bgmpt[3]);
27466  volpt[1] = orient3d(bgmpt[0], pt, bgmpt[2], bgmpt[3]);
27467  volpt[2] = orient3d(bgmpt[0], bgmpt[1], pt, bgmpt[3]);
27468  volpt[3] = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], pt);
27469  for (i = 0; i < 4; i++) weights[i] = fabs(volpt[i] / vol);
27470  // Interpolate the solution for p.
27471  for (i = 0; i < bgm->in->numberofpointmtrs; i++) {
27472  pt[pointmtrindex + i] = weights[0] * bgmpt[0][bgm->pointmtrindex + i]
27473  + weights[1] * bgmpt[1][bgm->pointmtrindex + i]
27474  + weights[2] * bgmpt[2][bgm->pointmtrindex + i]
27475  + weights[3] * bgmpt[3][bgm->pointmtrindex + i];
27476  }
27477  } else {
27478  setpoint2bgmtet(pt, (tetrahedron) NULL); // in m
27479  }
27480  return loc != OUTSIDE;
27481 }
27482 
27484 // //
27485 // interpolatesizemap() Interpolate the point sizes in the given size map.//
27486 // //
27487 // The size map is specified on each node of the background mesh. The points //
27488 // of current mesh get their sizes by interpolating. //
27489 // //
27490 // This function operation on two meshes simultaneously, the current mesh m, //
27491 // and the background mesh bgm. After this function, each point p in m will //
27492 // have a pointer to a tet of bgm. //
27493 // //
27495 
27496 void tetgenmesh::interpolatesizemap()
27497 {
27498  list *adjtetlist;
27499  triface tetloop, neightet, bgmtet;
27500  point searchpt;
27501  long scount;
27502  int *worklist;
27503  int sepcount;
27504  int i;
27505 
27506  if (b->verbose) {
27507  printf(" Interpolating size map.\n");
27508  }
27509 
27510  worklist = new int[points->items + 1];
27511  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
27512  sepcount = 0;
27513  scount = 0l;
27514 
27515  tetrahedrons->traversalinit();
27516  tetloop.tet = tetrahedrontraverse();
27517  while (tetloop.tet != (tetrahedron *) NULL) {
27518  if (!infected(tetloop)) {
27519  // Find a new subdomain.
27520  adjtetlist = new list(sizeof(triface), NULL, 1024);
27521  infect(tetloop);
27522  // Search the four corners in background mesh.
27523  for (i = 0; i < 4; i++) {
27524  searchpt = (point) tetloop.tet[4 + i];
27525  // Mark the point for avoiding multiple searchings.
27526  // assert(worklist[pointmark(searchpt)] == 0);
27527  worklist[pointmark(searchpt)] = 1;
27528  // Does it contain a pointer to bgm tet?
27529  bgm->decode(point2bgmtet(searchpt), bgmtet);
27530  if (bgm->isdead(&bgmtet)) {
27531  bgmtet = bgm->recenttet;
27532  }
27533  if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
27534  bgm->recenttet = bgmtet;
27535  }
27536  } // for (i = 0; i < 4; i++)
27537  // Collect all tets in this region.
27538  adjtetlist->append(&tetloop);
27539  // Collect the tets in the subdomain.
27540  for (i = 0; i < adjtetlist->len(); i++) {
27541  tetloop = * (triface *)(* adjtetlist)[i];
27542  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
27543  sym(tetloop, neightet);
27544  if ((neightet.tet != dummytet) && !infected(neightet)) {
27545  // Only need to search for the opposite point.
27546  searchpt = oppo(neightet);
27547  if (worklist[pointmark(searchpt)] == 0) {
27548  worklist[pointmark(searchpt)] = 1;
27549  decode(point2bgmtet(searchpt), bgmtet);
27550  if (bgm->isdead(&bgmtet)) {
27551  bgmtet = bgm->recenttet;
27552  }
27553  if (p1interpolatebgm(searchpt, &bgmtet, &scount)) {
27554  bgm->recenttet = bgmtet;
27555  }
27556  }
27557  infect(neightet);
27558  adjtetlist->append(&neightet);
27559  }
27560  }
27561  }
27562  // Increase the number of separated domains.
27563  sepcount++;
27564  delete adjtetlist;
27565  } // if (!infect())
27566  tetloop.tet = tetrahedrontraverse();
27567  }
27568 
27569  // Unmark all tets.
27570  tetrahedrons->traversalinit();
27571  tetloop.tet = tetrahedrontraverse();
27572  while (tetloop.tet != (tetrahedron *) NULL) {
27573  assert(infected(tetloop));
27574  uninfect(tetloop);
27575  tetloop.tet = tetrahedrontraverse();
27576  }
27577  delete [] worklist;
27578 
27579 #ifdef SELF_CHECK
27580  if (b->verbose && scount > 0l) {
27581  printf(" %ld brute-force searches.\n", scount);
27582  }
27583  if (b->verbose && sepcount > 0) {
27584  printf(" %d separate domains.\n", sepcount);
27585  }
27586 #endif
27587 }
27588 
27590 // //
27591 // duplicatebgmesh() Duplicate current mesh to background mesh. //
27592 // //
27593 // Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same //
27594 // input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'. //
27595 // //
27597 
27598 void tetgenmesh::duplicatebgmesh()
27599 {
27600  triface tetloop, btetloop;
27601  triface symtet, bsymtet;
27602  face bhullsh, bneighsh;
27603  point *idx2bplist, *tetptbaklist;
27604  point ploop, bploop;
27605  int idx, i;
27606 
27607  if (!b->quiet) {
27608  printf("Duplicating background mesh.\n");
27609  }
27610 
27611  // The background mesh itself has no background mesh.
27612  // assert(bgm->bgm == (tetgenmesh *) NULL);
27613  // The space for metric tensor should be allocated.
27614  // assert(bgm->sizeoftensor > 0);
27615 
27616  // Copy point list.
27617  idx2bplist = new point[points->items + 1];
27618  idx = in->firstnumber;
27619  points->traversalinit();
27620  ploop = pointtraverse();
27621  while (ploop != (point) NULL) {
27622  bgm->makepoint(&bploop);
27623  // Copy coordinates, attributes.
27624  for (i = 0; i < 3 + in->numberofpointattributes; i++) {
27625  bploop[i] = ploop[i];
27626  }
27627  // Transfer the metric tensor.
27628  for (i = 0; i < bgm->sizeoftensor; i++) {
27629  bploop[bgm->pointmtrindex + i] = ploop[pointmtrindex + i];
27630  // Metric tensor should have a positive value.
27631  if (bploop[bgm->pointmtrindex + i] <= 0.0) {
27632  printf("Error: Point %d has non-positive size %g (-m option).\n",
27633  bgm->pointmark(bploop), bploop[bgm->pointmtrindex + i]);
27634  terminatetetgen(1);
27635  }
27636  }
27637  // Remember the point for searching.
27638  idx2bplist[idx++] = bploop;
27639  ploop = pointtraverse();
27640  }
27641 
27642  // Copy tetrahedra list.
27643  tetptbaklist = new point[tetrahedrons->items + 1];
27644  idx = in->firstnumber;
27645  tetrahedrons->traversalinit();
27646  tetloop.tet = tetrahedrontraverse();
27647  while (tetloop.tet != (tetrahedron *) NULL) {
27648  bgm->maketetrahedron(&btetloop);
27649  // Set the four corners.
27650  for (i = 0; i < 4; i++) {
27651  ploop = (point) tetloop.tet[4 + i];
27652  bploop = idx2bplist[pointmark(ploop)];
27653  btetloop.tet[4 + i] = (tetrahedron) bploop;
27654  }
27655  // Remember the tet for setting neighbor connections.
27656  tetptbaklist[idx++] = (point) tetloop.tet[4];
27657  tetloop.tet[4] = (tetrahedron) btetloop.tet;
27658  tetloop.tet = tetrahedrontraverse();
27659  }
27660 
27661  // Set the connections between background tetrahedra. Create background
27662  // hull subfaces. Create the map of point-to-bgmtet.
27663  idx = in->firstnumber;
27664  tetrahedrons->traversalinit();
27665  tetloop.tet = tetrahedrontraverse();
27666  while (tetloop.tet != (tetrahedron *) NULL) {
27667  // Get the corresponding background tet.
27668  btetloop.tet = (tetrahedron *) tetloop.tet[4];
27669  // Set the four neighbors.
27670  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
27671  btetloop.loc = tetloop.loc;
27672  sym(tetloop, symtet);
27673  if ((symtet.tet != dummytet) && (symtet.tet > tetloop.tet)) {
27674  // Operate on the un-connected interior face.
27675  bsymtet.tet = (tetrahedron *) symtet.tet[4]; // The saved bgm tet.
27676  bsymtet.loc = symtet.loc;
27677  bgm->bond(btetloop, bsymtet);
27678  } else if (symtet.tet == dummytet) {
27679  // Create a subface in background mesh.
27680  bgm->makeshellface(bgm->subfaces, &bhullsh);
27681  bgm->adjustedgering(btetloop, CCW); // face to inside.
27682  bgm->setsorg(bhullsh, bgm->org(btetloop));
27683  bgm->setsdest(bhullsh, bgm->dest(btetloop));
27684  bgm->setsapex(bhullsh, bgm->apex(btetloop));
27685  bgm->tsbond(btetloop, bhullsh);
27686  // Remember a hull face for point location.
27687  bgm->dummytet[0] = bgm->encode(btetloop);
27688  }
27689  }
27690  // Restore the backup tet point.
27691  tetloop.tet[4] = (tetrahedron) tetptbaklist[idx++];
27692  // Make the point-to-bgmtet map for size interpolation.
27693  btetloop.loc = 0;
27694  for (i = 0; i < 4; i++) {
27695  ploop = (point) tetloop.tet[4 + i];
27696  setpoint2bgmtet(ploop, bgm->encode(btetloop));
27697  }
27698  // Go to the next tet, btet.
27699  tetloop.tet = tetrahedrontraverse();
27700  }
27701 
27702  // Connect bgm hull subfaces. Note: all hull subfaces form a 2-manifold.
27703  bgm->subfaces->traversalinit();
27704  bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
27705  while (bhullsh.sh != (shellface *) NULL) {
27706  bhullsh.shver = 0;
27707  bgm->stpivot(bhullsh, btetloop);
27708  assert(btetloop.tet != bgm->dummytet);
27709  bgm->adjustedgering(btetloop, CCW);
27710  for (i = 0; i < 3; i++) {
27711  bgm->spivot(bhullsh, bneighsh);
27712  if (bneighsh.sh == bgm->dummysh) {
27713  // This side is open, operate on it.
27714  bsymtet = btetloop;
27715  while (bgm->fnextself(bsymtet));
27716  bgm->tspivot(bsymtet, bneighsh);
27717  bgm->findedge(&bneighsh, bgm->sdest(bhullsh), bgm->sorg(bhullsh));
27718  bgm->sbond(bhullsh, bneighsh);
27719  }
27720  bgm->enextself(btetloop);
27721  bgm->senextself(bhullsh);
27722  }
27723  bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces);
27724  }
27725 
27726  delete [] tetptbaklist;
27727  delete [] idx2bplist;
27728 }
27729 
27730 //
27731 // Begin of Delaunay refinement routines
27732 //
27733 
27735 // //
27736 // marksharpsegments() Mark sharp segments. //
27737 // //
27738 // A segment s is called sharp if it is in one of the two cases: //
27739 // (1) There is a segment s' intersecting with s. The internal angle (*) //
27740 // between s and s' is acute. //
27741 // (2) There are two facets f1 and f2 intersecting at s. The internal //
27742 // dihedral angle (*) between f1 and f2 is acute. //
27743 // This routine finds the sharp segments and marked them as type SHARP. //
27744 // The minimum angle between segments (minfaceang) and the minimum dihedral //
27745 // angle between facets (minfacetdihed) are calulcated. //
27746 // //
27747 // (*) The internal angle (or dihedral) bewteen two features means the angle //
27748 // inside the mesh domain. //
27749 // //
27751 
27752 void tetgenmesh::marksharpsegments(REAL sharpangle)
27753 {
27754  triface adjtet;
27755  face startsh, spinsh, neighsh;
27756  face segloop, prevseg, nextseg;
27757  point eorg, edest;
27758  REAL ang, smallang;
27759  bool issharp;
27760  int sharpsegcount;
27761 
27762  if (b->verbose > 0) {
27763  printf(" Marking sharp segments.\n");
27764  }
27765 
27766  smallang = sharpangle * PI / 180.;
27767  sharpsegcount = 0;
27768  eorg = edest = (point) NULL; // To avoid compiler warnings.
27769 
27770  // A segment s may have been split into many subsegments. Operate the one
27771  // which contains the origin of s. Then mark the rest of subsegments.
27772  subsegs->traversalinit();
27773  segloop.sh = shellfacetraverse(subsegs);
27774  while (segloop.sh != (shellface *) NULL) {
27775  segloop.shver = 0;
27776  senext2(segloop, prevseg);
27777  spivotself(prevseg);
27778  if (prevseg.sh == dummysh) {
27779  // Operate on this seg s.
27780  assert(shelltype(segloop) != SHARP); // It should be unmarked.
27781  issharp = false;
27782  spivot(segloop, startsh);
27783  if (startsh.sh != dummysh) {
27784  // First check if two facets form an acute dihedral angle at s.
27785  eorg = sorg(segloop);
27786  edest = sdest(segloop);
27787  spinsh = startsh;
27788  do {
27789  if (sorg(spinsh) != eorg) {
27790  sesymself(spinsh);
27791  }
27792  // Only do test when the spinsh is faceing inward.
27793  stpivot(spinsh, adjtet);
27794  if (adjtet.tet != dummytet) {
27795  // Get the subface on the adjacent facet.
27796  spivot(spinsh, neighsh);
27797  // Do not calculate if it is self-bonded.
27798  if (neighsh.sh != spinsh.sh) {
27799  // Calculate the dihedral angle between the two subfaces.
27800  ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh));
27801  // Only do check if a sharp angle has not been found.
27802  if (!issharp) issharp = (ang < smallang);
27803  // Remember the smallest facet dihedral angle.
27804  minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang;
27805  }
27806  }
27807  // Go to the next facet.
27808  spivotself(spinsh);
27809  } while (spinsh.sh != startsh.sh);
27810  // if (!issharp) {
27811  // Second check if s forms an acute angle with another seg.
27812  spinsh = startsh;
27813  do {
27814  if (sorg(spinsh) != eorg) {
27815  sesymself(spinsh);
27816  }
27817  // Calculate the angle between s and s' of this facet.
27818  neighsh = spinsh;
27819  // Rotate edges around 'eorg' until meeting another seg s'. Such
27820  // seg (s') must exist since the facet is segment-bounded.
27821  // The sum of the angles of faces at 'eorg' gives the internal
27822  // angle between the two segments.
27823  ang = 0.0;
27824  do {
27825  ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
27826  senext2self(neighsh);
27827  sspivot(neighsh, nextseg);
27828  if (nextseg.sh != dummysh) break;
27829  // Go to the next coplanar subface.
27830  spivotself(neighsh);
27831  assert(neighsh.sh != dummysh);
27832  if (sorg(neighsh) != eorg) {
27833  sesymself(neighsh);
27834  }
27835  } while (true);
27836  // Only do check if a sharp angle has not been found.
27837  if (!issharp) issharp = (ang < smallang);
27838  // Remember the smallest input face angle.
27839  minfaceang = minfaceang < ang ? minfaceang : ang;
27840  // Go to the next facet.
27841  spivotself(spinsh);
27842  } while (spinsh.sh != startsh.sh);
27843  // }
27844  }
27845  if (issharp) {
27846  setshelltype(segloop, SHARP);
27847  // Set the type for all subsegments at forwards.
27848  senext(segloop, nextseg);
27849  spivotself(nextseg);
27850  while (nextseg.sh != dummysh) {
27851  nextseg.shver = 0;
27852  setshelltype(nextseg, SHARP);
27853  senextself(nextseg);
27854  spivotself(nextseg);
27855  }
27856  sharpsegcount++;
27857  }
27858  }
27859  segloop.sh = shellfacetraverse(subsegs);
27860  }
27861 
27862  // So far we have marked all segments which have an acute dihedral angle
27863  // or whose ORIGINs have an acute angle. In the un-marked subsegments,
27864  // there are possible ones whose DESTINATIONs have an acute angle.
27865  subsegs->traversalinit();
27866  segloop.sh = shellfacetraverse(subsegs);
27867  while (segloop.sh != (shellface *) NULL) {
27868  // Only operate if s is non-sharp and contains the dest.
27869  segloop.shver = 0;
27870  senext(segloop, nextseg);
27871  spivotself(nextseg);
27872  // if ((nextseg.sh == dummysh) && (shelltype(segloop) != SHARP)) {
27873  if (nextseg.sh == dummysh) {
27874  // issharp = false;
27875  issharp = (shelltype(segloop) == SHARP);
27876  spivot(segloop, startsh);
27877  if (startsh.sh != dummysh) {
27878  // Check if s forms an acute angle with another seg.
27879  eorg = sdest(segloop);
27880  spinsh = startsh;
27881  do {
27882  if (sorg(spinsh) != eorg) {
27883  sesymself(spinsh);
27884  }
27885  // Calculate the angle between s and s' of this facet.
27886  neighsh = spinsh;
27887  ang = 0.0;
27888  do {
27889  ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL);
27890  senext2self(neighsh);
27891  sspivot(neighsh, nextseg);
27892  if (nextseg.sh != dummysh) break;
27893  // Go to the next coplanar subface.
27894  spivotself(neighsh);
27895  assert(neighsh.sh != dummysh);
27896  if (sorg(neighsh) != eorg) {
27897  sesymself(neighsh);
27898  }
27899  } while (true);
27900  // Only do check if a sharp angle has not been found.
27901  if (!issharp) issharp = (ang < smallang);
27902  // Remember the smallest input face angle.
27903  minfaceang = minfaceang < ang ? minfaceang : ang;
27904  // Go to the next facet.
27905  spivotself(spinsh);
27906  } while (spinsh.sh != startsh.sh);
27907  }
27908  if (issharp) {
27909  setshelltype(segloop, SHARP);
27910  // Set the type for all subsegments at backwards.
27911  senext2(segloop, prevseg);
27912  spivotself(prevseg);
27913  while (prevseg.sh != dummysh) {
27914  prevseg.shver = 0;
27915  setshelltype(prevseg, SHARP);
27916  senext2self(prevseg);
27917  spivotself(prevseg);
27918  }
27919  sharpsegcount++;
27920  }
27921  }
27922  segloop.sh = shellfacetraverse(subsegs);
27923  }
27924 
27925  if ((b->verbose > 0) && (sharpsegcount > 0)) {
27926  printf(" %d sharp segments.\n", sharpsegcount);
27927  }
27928 }
27929 
27931 // //
27932 // decidefeaturepointsizes() Decide the sizes for all feature points. //
27933 // //
27934 // A feature point is a point on a sharp segment. Every feature point p will //
27935 // be assigned a positive size which is the radius of the protecting ball. //
27936 // //
27937 // The size of a feature point may be specified by one of the following ways://
27938 // (1) directly specifying on an input vertex (by using .mtr file); //
27939 // (2) imposing a fixed maximal volume constraint ('-a__' option); //
27940 // (3) imposing a maximal volume constraint in a region ('-a' option); //
27941 // (4) imposing a maximal area constraint on a facet (in .var file); //
27942 // (5) imposing a maximal length constraint on a segment (in .var file); //
27943 // (6) combining (1) - (5). //
27944 // (7) automatically deriving a size if none of (1) - (6) is available. //
27945 // In case (7),the size of p is set to be the smallest edge length among all //
27946 // edges connecting at p. The final size of p is the minimum of (1) - (7). //
27947 // //
27949 
27950 void tetgenmesh::decidefeaturepointsizes()
27951 {
27952  list *tetlist, *verlist;
27953  shellface **segsperverlist;
27954  triface starttet;
27955  face shloop;
27956  face checkseg, prevseg, nextseg, testseg;
27957  point ploop, adjpt, e1, e2;
27958  REAL lfs_0, len, vol, maxlen, varlen;
27959  bool isfeature;
27960  int *idx2seglist;
27961  int featurecount;
27962  int idx, i, j;
27963 
27964  maxlen = 0.0;
27965 
27966  if (b->verbose > 0) {
27967  printf(" Deciding feature-point sizes.\n");
27968  }
27969 
27970  // Constructing a map from vertices to segments.
27971  makesegmentmap(idx2seglist, segsperverlist);
27972  // Initialize working lists.
27973  tetlist = new list(sizeof(triface), NULL, 256);
27974  verlist = new list(sizeof(point *), NULL, 256);
27975 
27976  if (b->fixedvolume) {
27977  // A fixed volume constraint is imposed. This gives an upper bound of
27978  // the maximal radius of the protect ball of a vertex.
27979  maxlen = pow(6.0 * b->maxvolume, 1.0/3.0);
27980  }
27981 
27982  if (!b->refine) {
27983  // Initially correct types for Steiner points.
27984  featurecount = 0;
27985  points->traversalinit();
27986  ploop = pointtraverse();
27987  while (ploop != (point) NULL) {
27988  if (pointtype(ploop) == NACUTEVERTEX) {
27989  if (point2sh(ploop) != (shellface) NULL) {
27990  setpointtype(ploop, FREESEGVERTEX);
27991  featurecount++;
27992  }
27993  }
27994  ploop = pointtraverse();
27995  }
27996 #ifdef SELF_CHECK
27997  if ((b->verbose > 0) && (featurecount > 0)) {
27998  printf(" %d Steiner points correction.\n", featurecount);
27999  }
28000 #endif
28001  }
28002 
28003  // First only assign a size of p if p is not a Steiner point. The size of
28004  // a Steiner point will be interpolated later from the endpoints of the
28005  // segment on which it lies.
28006  featurecount = 0;
28007  points->traversalinit();
28008  ploop = pointtraverse();
28009  while (ploop != (point) NULL) {
28010  if (pointtype(ploop) != FREESEGVERTEX) {
28011  // Is p a feature point?
28012  isfeature = false;
28013  idx = pointmark(ploop) - in->firstnumber;
28014  for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) {
28015  checkseg.sh = segsperverlist[i];
28016  isfeature = (shelltype(checkseg) == SHARP);
28017  }
28018  // Decide the size of p if it is on a sharp segment.
28019  if (isfeature) {
28020  // Find a tet containing p (checkseg is a sharp seg which contains p).
28021  sstpivot(&checkseg, &starttet);
28022  // Form star(p).
28023  tetlist->append(&starttet);
28024  formstarpolyhedron(ploop, tetlist, verlist, true);
28025  // Decide the size for p if no input size is given on input.
28026  if (ploop[pointmtrindex] == 0.0) {
28027  // Calculate lfs_0(p).
28028  lfs_0 = longest;
28029  for (i = 0; i < verlist->len(); i++) {
28030  adjpt = * (point *)(* verlist)[i];
28031  if (pointtype(adjpt) == FREESEGVERTEX) {
28032  // A Steiner point q. Find the seg it lies on.
28033  sdecode(point2sh(adjpt), checkseg);
28034  assert(checkseg.sh != dummysh);
28035  checkseg.shver = 0;
28036  // Find the origin of this seg.
28037  prevseg = checkseg;
28038  do {
28039  senext2(prevseg, testseg);
28040  spivotself(testseg);
28041  if (testseg.sh == dummysh) break;
28042  prevseg = testseg; // Go to the previous subseg.
28043  prevseg.shver = 0;
28044  } while (true);
28045  // Find the dest of this seg.
28046  nextseg = checkseg;
28047  do {
28048  senext(nextseg, testseg);
28049  spivotself(testseg);
28050  if (testseg.sh == dummysh) break;
28051  nextseg = testseg; // Go to the next subseg.
28052  nextseg.shver = 0;
28053  } while (true);
28054  e1 = sorg(prevseg);
28055  e2 = sdest(nextseg);
28056  // Check if p is the origin or the dest of this seg.
28057  if (ploop == e1) {
28058  // Set q to be the dest of this seg.
28059  adjpt = e2;
28060  } else if (ploop == e2) {
28061  // Set q to be the org of this seg.
28062  adjpt = e1;
28063  }
28064  }
28065  len = distance(ploop, adjpt);
28066  if (lfs_0 > len) lfs_0 = len;
28067  }
28068  ploop[pointmtrindex] = lfs_0;
28069  }
28070  if (b->fixedvolume) {
28071  // A fixed volume constraint is imposed. Adjust H(p) <= maxlen.
28072  if (ploop[pointmtrindex] > maxlen) {
28073  ploop[pointmtrindex] = maxlen;
28074  }
28075  }
28076  if (b->varvolume) {
28077  // Variant volume constraints are imposed. Adjust H(p) <= varlen.
28078  for (i = 0; i < tetlist->len(); i++) {
28079  starttet = * (triface *)(* tetlist)[i];
28080  vol = volumebound(starttet.tet);
28081  if (vol > 0.0) {
28082  varlen = pow(6 * vol, 1.0/3.0);
28083  if (ploop[pointmtrindex] > varlen) {
28084  ploop[pointmtrindex] = varlen;
28085  }
28086  }
28087  }
28088  }
28089  // Clear working lists.
28090  tetlist->clear();
28091  verlist->clear();
28092  featurecount++;
28093  } else {
28094  // NO feature point, set the size of p be zero.
28095  ploop[pointmtrindex] = 0.0;
28096  }
28097  } // if (pointtype(ploop) != FREESEGVERTEX) {
28098  ploop = pointtraverse();
28099  }
28100 
28101  if (b->verbose > 0) {
28102  printf(" %d feature points.\n", featurecount);
28103  }
28104 
28105  if (!b->refine) {
28106  // Second only assign sizes for all Steiner points. A Steiner point p
28107  // inserted on a sharp segment s is assigned a size by interpolating
28108  // the sizes of the original endpoints of s.
28109  featurecount = 0;
28110  points->traversalinit();
28111  ploop = pointtraverse();
28112  while (ploop != (point) NULL) {
28113  if (pointtype(ploop) == FREESEGVERTEX) {
28114  if (ploop[pointmtrindex] == 0.0) {
28115  sdecode(point2sh(ploop), checkseg);
28116  assert(checkseg.sh != dummysh);
28117  if (shelltype(checkseg) == SHARP) {
28118  checkseg.shver = 0;
28119  // Find the origin of this seg.
28120  prevseg = checkseg;
28121  do {
28122  senext2(prevseg, testseg);
28123  spivotself(testseg);
28124  if (testseg.sh == dummysh) break;
28125  prevseg = testseg; // Go the previous subseg.
28126  prevseg.shver = 0;
28127  } while (true);
28128  // Find the dest of this seg.
28129  nextseg = checkseg;
28130  do {
28131  senext(nextseg, testseg);
28132  spivotself(testseg);
28133  if (testseg.sh == dummysh) break;
28134  nextseg = testseg; // Go the next subseg.
28135  nextseg.shver = 0;
28136  } while (true);
28137  e1 = sorg(prevseg);
28138  e2 = sdest(nextseg);
28139  len = distance(e1, e2);
28140  lfs_0 = distance(e1, ploop);
28141  // The following assert() happens when -Y option is used.
28142  if (b->nobisect == 0) {
28143  assert(lfs_0 < len);
28144  }
28145  ploop[pointmtrindex] = e1[pointmtrindex]
28146  + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]);
28147  featurecount++;
28148  } else {
28149  // NO feature point, set the size of p be zero.
28150  ploop[pointmtrindex] = 0.0;
28151  } // if (shelltype(checkseg) == SHARP)
28152  } // if (ploop[pointmtrindex] == 0.0)
28153  } // if (pointtype(ploop) != FREESEGVERTEX)
28154  ploop = pointtraverse();
28155  }
28156  if ((b->verbose > 0) && (featurecount > 0)) {
28157  printf(" %d Steiner feature points.\n", featurecount);
28158  }
28159  }
28160 
28161  if (varconstraint) {
28162  // A .var file exists. Adjust feature sizes.
28163  if (in->facetconstraintlist) {
28164  // Have facet area constrains.
28165  subfaces->traversalinit();
28166  shloop.sh = shellfacetraverse(subfaces);
28167  while (shloop.sh != (shellface *) NULL) {
28168  varlen = areabound(shloop);
28169  if (varlen > 0.0) {
28170  // Check if the three corners are feature points.
28171  varlen = sqrt(varlen);
28172  for (j = 0; j < 3; j++) {
28173  ploop = (point) shloop.sh[3 + j];
28174  isfeature = false;
28175  idx = pointmark(ploop) - in->firstnumber;
28176  for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
28177  i++) {
28178  checkseg.sh = segsperverlist[i];
28179  isfeature = (shelltype(checkseg) == SHARP);
28180  }
28181  if (isfeature) {
28182  assert(ploop[pointmtrindex] > 0.0);
28183  if (ploop[pointmtrindex] > varlen) {
28184  ploop[pointmtrindex] = varlen;
28185  }
28186  }
28187  } // for (j = 0; j < 3; j++)
28188  }
28189  shloop.sh = shellfacetraverse(subfaces);
28190  }
28191  }
28192  if (in->segmentconstraintlist) {
28193  // Have facet area constrains.
28194  subsegs->traversalinit();
28195  shloop.sh = shellfacetraverse(subsegs);
28196  while (shloop.sh != (shellface *) NULL) {
28197  varlen = areabound(shloop);
28198  if (varlen > 0.0) {
28199  // Check if the two endpoints are feature points.
28200  for (j = 0; j < 2; j++) {
28201  ploop = (point) shloop.sh[3 + j];
28202  isfeature = false;
28203  idx = pointmark(ploop) - in->firstnumber;
28204  for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature;
28205  i++) {
28206  checkseg.sh = segsperverlist[i];
28207  isfeature = (shelltype(checkseg) == SHARP);
28208  }
28209  if (isfeature) {
28210  assert(ploop[pointmtrindex] > 0.0);
28211  if (ploop[pointmtrindex] > varlen) {
28212  ploop[pointmtrindex] = varlen;
28213  }
28214  }
28215  } // for (j = 0; j < 2; j++)
28216  }
28217  shloop.sh = shellfacetraverse(subsegs);
28218  }
28219  }
28220  } // if (varconstraint)
28221 
28222  delete [] segsperverlist;
28223  delete [] idx2seglist;
28224  delete tetlist;
28225  delete verlist;
28226 }
28227 
28229 // //
28230 // enqueueencsub() Add an encroached subface into the queue. //
28231 // //
28233 
28234 void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber,
28235  REAL* cent)
28236 {
28237  badface *encsub;
28238  int i;
28239 
28240  encsub = (badface *) badsubfaces->alloc();
28241  encsub->ss = *testsub;
28242  encsub->forg = sorg(*testsub);
28243  encsub->fdest = sdest(*testsub);
28244  encsub->fapex = sapex(*testsub);
28245  encsub->foppo = (point) encpt;
28246  for (i = 0; i < 3; i++) encsub->cent[i] = cent[i];
28247  encsub->nextitem = (badface *) NULL;
28248  // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes:
28249  // (1) We can regonize it is encroached; (2) It is uniquely queued.
28250  setshell2badface(encsub->ss, encsub);
28251  // Add the subface to the end of a queue (quenumber = 2, high priority).
28252  *subquetail[quenumber] = encsub;
28253  // Maintain a pointer to the NULL pointer at the end of the queue.
28254  subquetail[quenumber] = &encsub->nextitem;
28255  if (b->verbose > 2) {
28256  printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg),
28257  pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber);
28258  }
28259 }
28260 
28262 // //
28263 // dequeueencsub() Remove an enc-subface from the front of the queue. //
28264 // //
28266 
28267 tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber)
28268 {
28269  badface *result;
28270  int quenumber;
28271 
28272  // Look for a nonempty queue.
28273  for (quenumber = 2; quenumber >= 0; quenumber--) {
28274  result = subquefront[quenumber];
28275  if (result != (badface *) NULL) {
28276  // Remove the badface from the queue.
28277  subquefront[quenumber] = result->nextitem;
28278  // Maintain a pointer to the NULL pointer at the end of the queue.
28279  if (subquefront[quenumber] == (badface *) NULL) {
28280  subquetail[quenumber] = &subquefront[quenumber];
28281  }
28282  *pquenumber = quenumber;
28283  return result;
28284  }
28285  }
28286  return (badface *) NULL;
28287 }
28288 
28290 // //
28291 // enqueuebadtet() Add a tetrahedron into the queue. //
28292 // //
28294 
28295 void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent)
28296 {
28297  badface *newbadtet;
28298  int queuenumber;
28299  int i;
28300 
28301  // Allocate space for the bad tetrahedron.
28302  newbadtet = (badface *) badtetrahedrons->alloc();
28303  newbadtet->tt = *testtet;
28304  newbadtet->key = ratio2;
28305  if (cent != NULL) {
28306  for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i];
28307  } else {
28308  for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
28309  }
28310  newbadtet->forg = org(*testtet);
28311  newbadtet->fdest = dest(*testtet);
28312  newbadtet->fapex = apex(*testtet);
28313  newbadtet->foppo = oppo(*testtet);
28314  newbadtet->nextitem = (badface *) NULL;
28315  // Determine the appropriate queue to put the bad tetrahedron into.
28316  if (ratio2 > b->goodratio) {
28317  // queuenumber = (int) ((ratio2 - b->goodratio) / 0.5);
28318  queuenumber = (int) (64.0 - 64.0 / ratio2);
28319  // 'queuenumber' may overflow (negative) caused by a very large ratio.
28320  if ((queuenumber > 63) || (queuenumber < 0)) {
28321  queuenumber = 63;
28322  }
28323  } else {
28324  // It's not a bad ratio; put the tet in the lowest-priority queue.
28325  queuenumber = 0;
28326  }
28327 
28328  // Are we inserting into an empty queue?
28329  if (tetquefront[queuenumber] == (badface *) NULL) {
28330  // Yes. Will this become the highest-priority queue?
28331  if (queuenumber > firstnonemptyq) {
28332  // Yes, this is the highest-priority queue.
28333  nextnonemptyq[queuenumber] = firstnonemptyq;
28334  firstnonemptyq = queuenumber;
28335  } else {
28336  // No. Find the queue with next higher priority.
28337  i = queuenumber + 1;
28338  while (tetquefront[i] == (badface *) NULL) {
28339  i++;
28340  }
28341  // Mark the newly nonempty queue as following a higher-priority queue.
28342  nextnonemptyq[queuenumber] = nextnonemptyq[i];
28343  nextnonemptyq[i] = queuenumber;
28344  }
28345  // Put the bad tetrahedron at the beginning of the (empty) queue.
28346  tetquefront[queuenumber] = newbadtet;
28347  } else {
28348  // Add the bad tetrahedron to the end of an already nonempty queue.
28349  tetquetail[queuenumber]->nextitem = newbadtet;
28350  }
28351  // Maintain a pointer to the last tetrahedron of the queue.
28352  tetquetail[queuenumber] = newbadtet;
28353 
28354  if (b->verbose > 2) {
28355  printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n",
28356  pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
28357  pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
28358  sqrt(ratio2), queuenumber);
28359  }
28360 }
28361 
28363 // //
28364 // dequeuebadtet() Remove a tetrahedron from the front of the queue. //
28365 // //
28367 
28368 tetgenmesh::badface* tetgenmesh::topbadtetra()
28369 {
28370  // Keep a record of which queue was accessed in case dequeuebadtetra()
28371  // is called later.
28372  recentq = firstnonemptyq;
28373  // If no queues are nonempty, return NULL.
28374  if (firstnonemptyq < 0) {
28375  return (badface *) NULL;
28376  } else {
28377  // Return the first tetrahedron of the highest-priority queue.
28378  return tetquefront[firstnonemptyq];
28379  }
28380 }
28381 
28382 void tetgenmesh::dequeuebadtet()
28383 {
28384  badface *deadbadtet;
28385  int i;
28386 
28387  // If queues were empty last time topbadtetra() was called, do nothing.
28388  if (recentq >= 0) {
28389  // Find the tetrahedron last returned by topbadtetra().
28390  deadbadtet = tetquefront[recentq];
28391  // Remove the tetrahedron from the queue.
28392  tetquefront[recentq] = deadbadtet->nextitem;
28393  // If this queue is now empty, update the list of nonempty queues.
28394  if (deadbadtet == tetquetail[recentq]) {
28395  // Was this the highest-priority queue?
28396  if (firstnonemptyq == recentq) {
28397  // Yes; find the queue with next lower priority.
28398  firstnonemptyq = nextnonemptyq[firstnonemptyq];
28399  } else {
28400  // No; find the queue with next higher priority.
28401  i = recentq + 1;
28402  while (tetquefront[i] == (badface *) NULL) {
28403  i++;
28404  }
28405  nextnonemptyq[i] = nextnonemptyq[recentq];
28406  }
28407  }
28408  // Return the bad tetrahedron to the pool.
28409  badfacedealloc(badtetrahedrons, deadbadtet);
28410  }
28411 }
28412 
28414 // //
28415 // checkseg4encroach() Check a subsegment to see if it is encroached. //
28416 // //
28417 // A segment s is encroached if there is a vertex lies inside or on its dia- //
28418 // metral circumsphere, i.e., s faces an angle theta >= 90 degrees. //
28419 // //
28420 // If 'testpt' (p) != NULL, only test if 'testseg' (s) is encroached by it, //
28421 // else, check all apexes of faces around s. Return TRUE if s is encroached. //
28422 // If and 'enqflag' is TRUE, add it into 'badsubsegs' if s is encroached. //
28423 // //
28424 // If 'prefpt' != NULL, it returns the reference point (defined in my paper) //
28425 // if it exists. This point is will be used to split s. //
28426 // //
28428 
28429 bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt,
28430  bool enqflag)
28431 {
28432  badface *encsubseg;
28433  triface starttet, spintet;
28434  point eorg, edest, eapex, encpt;
28435  REAL cent[3], radius, dist, diff;
28436  REAL maxradius;
28437  bool enq;
28438  int hitbdry;
28439 
28440  enq = false;
28441  eorg = sorg(*testseg);
28442  edest = sdest(*testseg);
28443  cent[0] = 0.5 * (eorg[0] + edest[0]);
28444  cent[1] = 0.5 * (eorg[1] + edest[1]);
28445  cent[2] = 0.5 * (eorg[2] + edest[2]);
28446  radius = distance(cent, eorg);
28447 
28448  if (varconstraint && (areabound(*testseg) > 0.0)) {
28449  enq = (2.0 * radius) > areabound(*testseg);
28450  }
28451 
28452  if (!enq) {
28453  maxradius = 0.0;
28454  if (testpt == (point) NULL) {
28455  // Check if it is encroached by traversing all faces containing it.
28456  sstpivot(testseg, &starttet);
28457  eapex = apex(starttet);
28458  spintet = starttet;
28459  hitbdry = 0;
28460  do {
28461  dist = distance(cent, apex(spintet));
28462  diff = dist - radius;
28463  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28464  if (diff <= 0.0) {
28465  // s is encroached.
28466  enq = true;
28467  if (prefpt != (point *) NULL) {
28468  // Find the reference point.
28469  encpt = apex(spintet);
28470  circumsphere(eorg, edest, encpt, NULL, NULL, &dist);
28471  if (dist > maxradius) {
28472  // Rememebr this point.
28473  *prefpt = encpt;
28474  maxradius = dist;
28475  }
28476  } else {
28477  break;
28478  }
28479  }
28480  if (!fnextself(spintet)) {
28481  hitbdry++;
28482  if (hitbdry < 2) {
28483  esym(starttet, spintet);
28484  if (!fnextself(spintet)) {
28485  hitbdry++;
28486  }
28487  }
28488  }
28489  } while (apex(spintet) != eapex && (hitbdry < 2));
28490  } else {
28491  // Only check if 'testseg' is encroached by 'testpt'.
28492  dist = distance(cent, testpt);
28493  diff = dist - radius;
28494  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28495  enq = (diff <= 0.0);
28496  }
28497  }
28498 
28499  if (enq && enqflag) {
28500  if (b->verbose > 2) {
28501  printf(" Queuing encroaching subsegment (%d, %d).\n",
28502  pointmark(eorg), pointmark(edest));
28503  }
28504  encsubseg = (badface *) badsubsegs->alloc();
28505  encsubseg->ss = *testseg;
28506  encsubseg->forg = eorg;
28507  encsubseg->fdest = edest;
28508  encsubseg->foppo = (point) NULL; // Not used.
28509  // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes:
28510  // (1) We can regonize it is encroached; (2) It is uniquely queued.
28511  setshell2badface(encsubseg->ss, encsubseg);
28512  }
28513 
28514  return enq;
28515 }
28516 
28518 // //
28519 // checksub4encroach() Check a subface to see if it is encroached. //
28520 // //
28521 // A subface f is encroached if there is a vertex inside or on its diametral //
28522 // circumsphere. //
28523 // //
28524 // If 'testpt (p) != NULL', test if 'testsub' (f) is encroached by it, else, //
28525 // test if f is encroached by one of the two opposites of the adjacent tets. //
28526 // Return TRUE if f is encroached and queue it if 'enqflag' is set. //
28527 // //
28529 
28530 bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag)
28531 {
28532  triface abuttet;
28533  point pa, pb, pc, encpt;
28534  REAL A[4][4], rhs[4], D;
28535  REAL cent[3], area;
28536  REAL radius, dist, diff;
28537  bool enq;
28538  int indx[4];
28539  int quenumber;
28540 
28541  enq = false;
28542  radius = 0.0;
28543  encpt = (point) NULL;
28544 
28545  pa = sorg(*testsub);
28546  pb = sdest(*testsub);
28547  pc = sapex(*testsub);
28548 
28549  // Compute the coefficient matrix A (3x3).
28550  A[0][0] = pb[0] - pa[0];
28551  A[0][1] = pb[1] - pa[1];
28552  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
28553  A[1][0] = pc[0] - pa[0];
28554  A[1][1] = pc[1] - pa[1];
28555  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
28556  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
28557 
28558  if (varconstraint && (areabound(*testsub) > 0.0)) {
28559  // Check if the subface has too big area.
28560  area = 0.5 * sqrt(dot(A[2], A[2]));
28561  enq = area > areabound(*testsub);
28562  if (enq) {
28563  quenumber = 2; // A queue of subfaces having too big area.
28564  }
28565  }
28566 
28567  // Compute the right hand side vector b (3x1).
28568  rhs[0] = 0.5 * dot(A[0], A[0]);
28569  rhs[1] = 0.5 * dot(A[1], A[1]);
28570  rhs[2] = 0.0;
28571  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
28572  // and backward and forward substitute..
28573  if (lu_decmp(A, 3, indx, &D, 0)) {
28574  lu_solve(A, 3, indx, rhs, 0);
28575  cent[0] = pa[0] + rhs[0];
28576  cent[1] = pa[1] + rhs[1];
28577  cent[2] = pa[2] + rhs[2];
28578  radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
28579  }
28580 
28581  if (!enq) {
28582  // Check if the subface is encroached.
28583  if (testpt == (point) NULL) {
28584  stpivot(*testsub, abuttet);
28585  if (abuttet.tet != dummytet) {
28586  dist = distance(cent, oppo(abuttet));
28587  diff = dist - radius;
28588  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28589  enq = (diff <= 0.0);
28590  if (enq) encpt = oppo(abuttet);
28591  }
28592  if (!enq) {
28593  sesymself(*testsub);
28594  stpivot(*testsub, abuttet);
28595  if (abuttet.tet != dummytet) {
28596  dist = distance(cent, oppo(abuttet));
28597  diff = dist - radius;
28598  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28599  enq = (diff <= 0.0);
28600  if (enq) encpt = oppo(abuttet);
28601  }
28602  }
28603  } else {
28604  dist = distance(cent, testpt);
28605  diff = dist - radius;
28606  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28607  enq = (diff <= 0.0);
28608  }
28609  if (enq) {
28610  quenumber = 0; // A queue of encroached subfaces.
28611  }
28612  }
28613 
28614  if (enq && enqflag) {
28615  enqueueencsub(testsub, encpt, quenumber, cent);
28616  }
28617 
28618  return enq;
28619 }
28620 
28622 // //
28623 // checktet4badqual() Test a tetrahedron for quality measures. //
28624 // //
28625 // Tests a tetrahedron to see if it satisfies the minimum ratio condition //
28626 // and the maximum volume condition. Tetrahedra that aren't upto spec are //
28627 // added to the bad tetrahedron queue. //
28628 // //
28630 
28631 bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag)
28632 {
28633  point pa, pb, pc, pd, pe1, pe2;
28634  REAL vda[3], vdb[3], vdc[3];
28635  REAL vab[3], vbc[3], vca[3];
28636  REAL N[4][3], A[4][4], rhs[4], D;
28637  REAL elen[6], circumcent[3];
28638  REAL bicent[3], offcent[3];
28639  offcent[0] = 0.0; // Just to avoid uninitialised value warnings.
28640  offcent[1] = 0.0; // Just to avoid uninitialised value warnings.
28641  offcent[2] = 0.0; // Just to avoid uninitialised value warnings.
28642  REAL volume, L, cosd;
28643  REAL radius2, smlen2, ratio2;
28644  REAL dist, sdist, split;
28645  bool enq;
28646  int indx[4];
28647  int sidx, i, j;
28648 
28649  pa = (point) testtet->tet[4];
28650  pb = (point) testtet->tet[5];
28651  pc = (point) testtet->tet[6];
28652  pd = (point) testtet->tet[7];
28653 
28654  // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
28655  // Set the matrix A = [vda, vdb, vdc]^T.
28656  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
28657  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
28658  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
28659  // Get the rest edge vectors
28660  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
28661  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
28662  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
28663 
28664  // Lu-decompose the matrix A.
28665  lu_decmp(A, 3, indx, &D, 0);
28666  // Get the volume of abcd.
28667  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
28668  if (volume < 0.0) volume = -volume;
28669  // Check the radiu-edge ratio of the tet.
28670  rhs[0] = 0.5 * dot(vda, vda);
28671  rhs[1] = 0.5 * dot(vdb, vdb);
28672  rhs[2] = 0.5 * dot(vdc, vdc);
28673  lu_solve(A, 3, indx, rhs, 0);
28674  // Get the circumcenter.
28675  for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
28676  // Get the square of the circumradius.
28677  radius2 = dot(rhs, rhs);
28678  // Find the square of the shortest edge length.
28679  elen[0] = dot(vda, vda);
28680  elen[1] = dot(vdb, vdb);
28681  elen[2] = dot(vdc, vdc);
28682  elen[3] = dot(vab, vab);
28683  elen[4] = dot(vbc, vbc);
28684  elen[5] = dot(vca, vca);
28685  smlen2 = elen[0]; sidx = 0;
28686  for (i = 1; i < 6; i++) {
28687  if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; }
28688  }
28689  // Calculate the square of radius-edge ratio.
28690  ratio2 = radius2 / smlen2;
28691  // Check whether the ratio is smaller than permitted.
28692  enq = ratio2 > b->goodratio;
28693  if (!enq) {
28694  // abcd has good ratio.
28695  // ratio2 = 0.0;
28696  // if (b->offcenter) {
28697  // Test if it is a sliver.
28698  // Compute the 4 face normals (N[0], ..., N[3]).
28699  for (j = 0; j < 3; j++) {
28700  for (i = 0; i < 3; i++) rhs[i] = 0.0;
28701  rhs[j] = 1.0; // Positive means the inside direction
28702  lu_solve(A, 3, indx, rhs, 0);
28703  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
28704  }
28705  // Get the fourth normal by summing up the first three.
28706  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
28707  // Normalized the normals.
28708  for (i = 0; i < 4; i++) {
28709  L = sqrt(dot(N[i], N[i]));
28710  if (L > 0.0) {
28711  for (j = 0; j < 3; j++) N[i][j] /= L;
28712  }
28713  }
28714  // N[0] is the normal of face bcd. Test the dihedral angles at edge
28715  // cd, bd, and bc to see if they are too small or too big.
28716  for (i = 1; i < 4 && !enq; i++) {
28717  cosd = -dot(N[0], N[i]); // Edge cd, bd, bc.
28718  enq = cosd > cosmindihed;
28719  }
28720  if (!enq) {
28721  for (i = 2; i < 4 && !enq; i++) {
28722  cosd = -dot(N[1], N[i]); // Edge ad, ac
28723  enq = cosd > cosmindihed;
28724  }
28725  if (!enq) {
28726  cosd = -dot(N[2], N[3]); // Edge ab
28727  enq = cosd > cosmindihed;
28728  }
28729  }
28730  // }
28731  } else if (b->offcenter) {
28732  // abcd has bad-quality. Use off-center instead of circumcenter.
28733  switch (sidx) {
28734  case 0: // edge da.
28735  pe1 = pd; pe2 = pa; break;
28736  case 1: // edge db.
28737  pe1 = pd; pe2 = pb; break;
28738  case 2: // edge dc.
28739  pe1 = pd; pe2 = pc; break;
28740  case 3: // edge ab.
28741  pe1 = pa; pe2 = pb; break;
28742  case 4: // edge bc.
28743  pe1 = pb; pe2 = pc; break;
28744  case 5: // edge ca.
28745  pe1 = pc; pe2 = pa; break;
28746  default:
28747  pe1 = pe2 = (point) NULL; // Avoid a compile warning.
28748  }
28749  // The shortest edge is e1->e2.
28750  for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]);
28751  dist = distance(bicent, circumcent);
28752  // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle.
28753  // The following formulae is from
28754  sdist = b->alpha3 * (b->minratio+sqrt(b->goodratio-0.25))* sqrt(smlen2);
28755  split = sdist / dist;
28756  if (split > 1.0) split = 1.0;
28757  // Get the off-center.
28758  for (i = 0; i < 3; i++) {
28759  offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]);
28760  }
28761  }
28762 
28763  if (!enq && (b->varvolume || b->fixedvolume)) {
28764  // Check if the tet has too big volume.
28765  enq = b->fixedvolume && (volume > b->maxvolume);
28766  if (!enq && b->varvolume) {
28767  enq = (volume > volumebound(testtet->tet)) &&
28768  (volumebound(testtet->tet) > 0.0);
28769  }
28770  }
28771 
28772  if (!enq) {
28773  // Check if the user-defined sizing function is satisfied.
28774  if (b->metric) {
28775  // assert(b->alpha1 > 0.0);
28776  sdist = sqrt(radius2) / b->alpha1;
28777  for (i = 0; i < 4; i++) {
28778  pa = (point) testtet->tet[4 + i];
28779  // Get the indicated size of p.
28780  dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex];
28781  enq = ((dist < sdist) && (dist > 0.0));
28782  if (enq) break; // It is bad wrt. a node constraint.
28783  // *** Experiment ! Stop test if c is inside H(a).
28784  // if ((dist > 0.0) && (dist > sdist)) break;
28785  }
28786  // *** Experiment !
28787  // enq = (i == 4); // Does c lies outside all sparse-ball?
28788  } // if (b->metric)
28789  }
28790 
28791  if (enq && enqflag) {
28792  if (b->offcenter && (ratio2 > b->goodratio)) {
28793  for (i = 0; i < 3; i++) circumcent[i] = offcent[i];
28794  }
28795  enqueuebadtet(testtet, ratio2, circumcent);
28796  }
28797 
28798  return enq;
28799 }
28800 
28802 // //
28803 // acceptsegpt() Check if a segment point can be inserted or not. //
28804 // //
28805 // Segment(ab) is indicated to be split by a point p (\in ab). This routine //
28806 // decides whether p can be inserted or not. //
28807 // //
28808 // p can not be inserted either the '-Y' option is used and ab is a hull //
28809 // segment or '-YY' option is used. //
28810 // //
28811 // p can be inserted if it is in one of the following cases: //
28812 // (1) if L = |a - b| is too long wrt the edge constraint; or //
28813 // (2) if |x - p| > \alpha_2 H(x) for x = a, b; or //
28814 // (3) if 'refpt' != NULL. //
28815 // //
28817 
28818 bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg)
28819 {
28820  point p[2];
28821  REAL L, lfs;
28822  int i, j;
28823 
28824  if (b->nobisect == 1) {
28825  // '-Y'. It can not be split if it is on the hull.
28826  triface spintet;
28827  point pc;
28828  sstpivot(splitseg, &spintet);
28829  assert(spintet.tet != dummytet);
28830  pc = apex(spintet);
28831  do {
28832  if (!fnextself(spintet)) {
28833  // Meet a boundary face - s is on the hull.
28834  return false;
28835  }
28836  } while (pc != apex(spintet));
28837  } else if (b->nobisect > 1) {
28838  // '-YY'. Do not split it.
28839  return false;
28840  }
28841 
28842  p[0] = sorg(*splitseg);
28843  p[1] = sdest(*splitseg);
28844  if (varconstraint && (areabound(*splitseg) > 0)) {
28845  lfs = areabound(*splitseg);
28846  L = distance(p[0], p[1]);
28847  if (L > lfs) {
28848  return true; // case (1)
28849  }
28850  }
28851 
28852  j = 0; // Use j to count the number of inside balls.
28853  for (i = 0; i < 2; i++) {
28854  // Check if p is inside the protect ball of q.
28855  if (p[i][pointmtrindex] > 0.0) {
28856  lfs = b->alpha2 * p[i][pointmtrindex];
28857  L = distance(p[i], segpt);
28858  if (L < lfs) j++; // p is inside ball.
28859  }
28860  }
28861  if (j == 0) return true; // case (3).
28862 
28863  // If 'refpt' != NULL, force p to be inserted.
28864  if (refpt != (point) NULL) {
28865  cdtenforcesegpts++;
28866  return true;
28867  }
28868 
28869  // Do not split it.
28870  rejsegpts++;
28871  return false;
28872 }
28873 
28875 // //
28876 // acceptfacpt() Check if a facet point can be inserted or not. //
28877 // //
28878 // 'subceillist' is CBC(p). 'verlist' (V) is empty on input, it returns the //
28879 // set of vertices of CBC(p). //
28880 // //
28881 // p can not be inserted either the '-Y' option is used and the facet is on //
28882 // the hull or '-YY' option is used. //
28883 // //
28884 // p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V. //
28885 // //
28887 
28888 bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist)
28889 {
28890  face *testsh;
28891  point p[2], ploop;
28892  REAL L, lfs;
28893  int idx, i, j;
28894 
28895  if (b->nobisect == 1) {
28896  // '-Y'. p can not be inserted if CBC(p) is on the hull.
28897  triface testtet;
28898  testsh = (face *)(* subceillist)[0];
28899  stpivot(*testsh, testtet);
28900  if (testtet.tet != dummytet) {
28901  sesymself(*testsh);
28902  stpivot(*testsh, testtet);
28903  }
28904  if (testtet.tet == dummytet) return false;
28905  } else if (b->nobisect > 1) {
28906  // '-YY'. Do not split s.
28907  return false;
28908  }
28909 
28910  // Collect the vertices of CBC(p), save them in V.
28911  for (i = 0; i < subceillist->len(); i++) {
28912  testsh = (face *)(* subceillist)[i];
28913  p[0] = sorg(*testsh);
28914  p[1] = sdest(*testsh);
28915  for (j = 0; j < 2; j++) {
28916  idx = pointmark(p[j]);
28917  if (idx >= 0) {
28918  setpointmark(p[j], -idx - 1);
28919  verlist->append(&(p[j]));
28920  }
28921  }
28922  }
28923 
28924  j = 0; // Use j to count the number of inside balls.
28925  for (i = 0; i < verlist->len(); i++) {
28926  ploop = * (point *)(* verlist)[i];
28927  // Uninfect q.
28928  idx = pointmark(ploop);
28929  setpointmark(ploop, -(idx + 1));
28930  // Check if p is inside the protect ball of q.
28931  if (ploop[pointmtrindex] > 0.0) {
28932  lfs = b->alpha2 * ploop[pointmtrindex];
28933  L = distance(ploop, facpt);
28934  if (L < lfs) j++; // p is inside ball.
28935  }
28936  }
28937  verlist->clear();
28938 
28939  if (j == 0) return true; // case (3).
28940 
28941  rejsubpts++;
28942  return false;
28943 }
28944 
28946 // //
28947 // acceptvolpt() Check if a volume point can be inserted or not. //
28948 // //
28949 // 'ceillist' is B(p). 'verlist' (V) is empty on input, it returns the set //
28950 // of vertices of B(p). //
28951 // //
28952 // p can be split if |p - v| > \alpha_2 H(v), for all v \in V. //
28953 // //
28955 
28956 bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist)
28957 {
28958  triface* testtet;
28959  point p[3], ploop;
28960  REAL L, lfs;
28961  int idx, i, j;
28962 
28963  // Collect the vertices of CBC(p), save them in V.
28964  for (i = 0; i < ceillist->len(); i++) {
28965  testtet = (triface *)(* ceillist)[i];
28966  p[0] = org(*testtet);
28967  p[1] = dest(*testtet);
28968  p[2] = apex(*testtet);
28969  for (j = 0; j < 3; j++) {
28970  idx = pointmark(p[j]);
28971  if (idx >= 0) {
28972  setpointmark(p[j], -idx - 1);
28973  verlist->append(&(p[j]));
28974  }
28975  }
28976  }
28977 
28978  j = 0; // Use j to counte the number of inside balls.
28979  for (i = 0; i < verlist->len(); i++) {
28980  ploop = * (point *)(* verlist)[i];
28981  // Uninfect q.
28982  idx = pointmark(ploop);
28983  setpointmark(ploop, -(idx + 1));
28984  // Check if p is inside the protect ball of q.
28985  if (ploop[pointmtrindex] > 0.0) {
28986  lfs = b->alpha2 * ploop[pointmtrindex];
28987  L = distance(ploop, volpt);
28988  if (L < lfs) j++; // p is inside the protect ball.
28989  }
28990  }
28991  verlist->clear();
28992 
28993  if (j == 0) return true; // case (2).
28994 
28995  rejtetpts++;
28996  return false;
28997 }
28998 
29000 // //
29001 // getsplitpoint() Get the inserting point in a segment. //
29002 // //
29004 
29005 void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt)
29006 {
29007  point ei, ej;
29008  REAL split, L, d1, d2, ps, rs;
29009  bool acutea, acuteb;
29010  int i;
29011 
29012  if (refpt != (point) NULL) {
29013  // Use the CDT rules to split the segment.
29014  acutea = (pointtype(e1) == ACUTEVERTEX);
29015  acuteb = (pointtype(e2) == ACUTEVERTEX);
29016  if (acutea ^ acuteb) {
29017  // Only one endpoint is acute. Use rule-2 or rule-3.
29018  ei = acutea ? e1 : e2;
29019  ej = acutea ? e2 : e1;
29020  L = distance(ei, ej);
29021  // Apply rule-2.
29022  d1 = distance(ei, refpt);
29023  split = d1 / L;
29024  for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
29025  // Check if rule-3 is needed.
29026  d2 = distance(refpt, newpt);
29027  if (d2 > (L - d1)) {
29028  // Apply rule-3.
29029  if ((d1 - d2) > (0.5 * d1)) {
29030  split = (d1 - d2) / L;
29031  } else {
29032  split = 0.5 * d1 / L;
29033  }
29034  for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]);
29035  if (b->verbose > 1) {
29036  printf(" Found by rule-3:");
29037  }
29038  r3count++;
29039  } else {
29040  if (b->verbose > 1) {
29041  printf(" Found by rule-2:");
29042  }
29043  r2count++;
29044  }
29045  if (b->verbose > 1) {
29046  printf(" center %d, split = %.12g.\n", pointmark(ei), split);
29047  }
29048  // Add a random perturbation on newpt.
29049  d1 = distance(ei, newpt);
29050  d2 = distance(newpt, refpt);
29051  ps = randgenerator(d2 * b->epsilon2 * 1e+2);
29052  rs = ps / d1;
29053  // Perturb newpt away from ei.
29054  for (i = 0; i < 3; i++) newpt[i] = ei[i] + (1.0+rs) * (newpt[i] - ei[i]);
29055  } else {
29056  // Both endpoints are acute or not. Split it at the middle.
29057  for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
29058  // Add a random perturbation on newpt.
29059  d1 = 0.5 * distance(e1, e2);
29060  ps = randgenerator(d1 * b->epsilon2 * 1e+2);
29061  rs = ps / d1;
29062  for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
29063  }
29064  } else {
29065  // Split the segment at its midpoint.
29066  for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]);
29067  // Add a random perturbation on newpt.
29068  d1 = 0.5 * distance(e1, e2);
29069  ps = randgenerator(d1 * b->epsilon2 * 1e+2);
29070  rs = ps / d1;
29071  for (i = 0; i < 3; i++) newpt[i] = e1[i] + (1.0+rs) * (newpt[i] - e1[i]);
29072  }
29073 }
29074 
29076 // //
29077 // shepardinterpolation() Interpolate the local size of a newpoint. //
29078 // //
29079 // The classical Shepard interoplation (inversed weighted distance) is used. //
29080 // (With the choice p = 2). //
29081 // //
29082 // 'verlist' contains a list vertices neighboring to 'newpt'. //
29083 // //
29085 
29086 void tetgenmesh::shepardinterpolate(point newpt, list *verlist)
29087 {
29088  point neipt;
29089  REAL *weights, sumweight;
29090  REAL vec[3];
29091  int i, j;
29092 
29093  weights = new REAL[verlist->len()];
29094  sumweight = 0.0;
29095 
29096  // Calculate the weight of each point.
29097  for (i = 0; i < verlist->len(); i++) {
29098  neipt = * (point *)(* verlist)[i];
29099  for (j = 0; j < 3; j++) vec[j] = neipt[j] - newpt[j];
29100  weights[i] = 1.0 / dot(vec, vec);
29101  sumweight += weights[i];
29102  }
29103  // Interpolate.
29104  newpt[pointmtrindex] = 0.0;
29105  for (i = 0; i < verlist->len(); i++) {
29106  neipt = * (point *)(* verlist)[i];
29107  newpt[pointmtrindex] += (weights[i] * neipt[pointmtrindex]) / sumweight;
29108  }
29109 
29110  delete [] weights;
29111 }
29112 
29114 // //
29115 // setnewpointsize() Set the size for a new point. //
29116 // //
29117 // The size of the new point p is interpolated either from a background mesh //
29118 // (b->bgmesh) or from the two input endpoints. //
29119 // //
29121 
29122 void tetgenmesh::setnewpointsize(point newpt, point e1, point e2)
29123 {
29124  if (b->metric) {
29125  // Interpolate the point size in a background mesh.
29126  triface bgmtet;
29127  // Get a tet in background mesh for locating p.
29128  decode(point2bgmtet(e1), bgmtet);
29129  p1interpolatebgm(newpt, &bgmtet, NULL);
29130  } else {
29131  if (e2 != (point) NULL) {
29132  // Interpolate the size between the two endpoints.
29133  REAL split, l, d;
29134  l = distance(e1, e2);
29135  d = distance(e1, newpt);
29136  split = d / l;
29137 #ifdef SELF_CHECK
29138  // Check if e1 and e2 are endpoints of a sharp segment.
29139  assert(e1[pointmtrindex] > 0.0);
29140  assert(e2[pointmtrindex] > 0.0);
29141 #endif
29142  newpt[pointmtrindex] = (1.0 - split) * e1[pointmtrindex]
29143  + split * e2[pointmtrindex];
29144  }
29145  }
29146 }
29147 
29149 // //
29150 // splitencseg() Split an enc-seg and recover the Delaunayness by flips. //
29151 // //
29153 
29154 void tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist,
29155  list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet,
29156  bool optflag)
29157 {
29158  list *mytetlist;
29159  queue *myflipque;
29160  triface starttet;
29161  face startsh, spinsh, checksh;
29162  int i;
29163 
29164  mytetlist = NULL;
29165  myflipque = NULL;
29166 
29167  if (optflag) {
29168  mytetlist = new list(sizeof(triface), NULL, 1024);
29169  myflipque = new queue(sizeof(badface));
29170  tetlist = mytetlist;
29171  flipque = myflipque;
29172  }
29173 
29174  // Use the base orientation (important in this routine).
29175  splitseg->shver = 0;
29176  // Insert p, this should always success.
29177  sstpivot(splitseg, &starttet);
29178  splittetedge(newpt, &starttet, flipque);
29179  // Remove locally non-Delaunay faces by flipping.
29180  flip(flipque, NULL); // lawson(NULL, flipque);
29181 
29182  if (!optflag) {
29183  // Check the two new subsegs to see if they're encroached (not by p).
29184  for (i = 0; i < 2; i++) {
29185  if (!shell2badface(*splitseg)) {
29186  checkseg4encroach(splitseg, NULL, NULL, true);
29187  }
29188  if (i == 1) break; // Two new segs have been checked.
29189  senextself(*splitseg);
29190  spivotself(*splitseg);
29191 #ifdef SELF_CHECK
29192  assert(splitseg->sh != (shellface *) NULL);
29193 #endif
29194  splitseg->shver = 0;
29195  }
29196  // Check the new subfaces to see if they're encroached (not by p).
29197  if (chkencsub) {
29198  spivot(*splitseg, startsh);
29199  spinsh = startsh;
29200  do {
29201  sublist->append(&spinsh);
29202  formstarpolygon(newpt, sublist, verlist);
29203  for (i = 0; i < sublist->len(); i++) {
29204  checksh = * (face *)(* sublist)[i];
29205  if (!shell2badface(checksh)) {
29206  checksub4encroach(&checksh, NULL, true);
29207  }
29208  }
29209  sublist->clear();
29210  if (verlist) verlist->clear();
29211  spivotself(spinsh);
29212  } while (spinsh.sh != startsh.sh);
29213  }
29214  } // if (!optflag)
29215 
29216  // Collect the new tets connecting at p.
29217  sstpivot(splitseg, &starttet);
29218  tetlist->append(&starttet);
29219  formstarpolyhedron(newpt, tetlist, verlist, true);
29220 
29221  if (!optflag) {
29222  // Check if p encroaches adjacent segments.
29223  tallencsegs(newpt, 1, &tetlist);
29224  if (chkencsub) {
29225  // Check if p encroaches adjacent subfaces.
29226  tallencsubs(newpt, 1, &tetlist);
29227  }
29228  if (chkbadtet) {
29229  // Check if there are new bad quality tets at p.
29230  for (i = 0; i < tetlist->len(); i++) {
29231  starttet = * (triface *)(* tetlist)[i];
29232  checktet4badqual(&starttet, true);
29233  }
29234  }
29235  tetlist->clear();
29236  } else {
29237  // Check if new tets are non-optimal.
29238  for (i = 0; i < tetlist->len(); i++) {
29239  starttet = * (triface *)(* tetlist)[i];
29240  checktet4opt(&starttet, true);
29241  }
29242  delete mytetlist;
29243  delete myflipque;
29244  }
29245 }
29246 
29248 // //
29249 // tallencsegs() Check for encroached segments and save them in list. //
29250 // //
29251 // If 'testpt' (p) != NULL, only check if segments are encroached by p, else,//
29252 // check all the nearby mesh vertices. //
29253 // //
29254 // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the //
29255 // segments which are on B_i(p)s, else, check the entire list of segments //
29256 // (in the pool 'this->subsegs'). //
29257 // //
29259 
29260 bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists)
29261 {
29262  list *ceillist;
29263  triface ceiltet;
29264  face checkseg;
29265  long oldencnum;
29266  int i, j, k;
29267 
29268  // Remember the current number of encroached segments.
29269  oldencnum = badsubsegs->items;
29270 
29271  if (ceillists != (list **) NULL) {
29272  for (k = 0; k < n; k++) {
29273  ceillist = ceillists[k];
29274  // Check the segments on B_i(p).
29275  for (i = 0; i < ceillist->len(); i++) {
29276  ceiltet = * (triface *)(* ceillist)[i];
29277  ceiltet.ver = 0;
29278  for (j = 0; j < 3; j++) {
29279  tsspivot(&ceiltet, &checkseg);
29280  if (checkseg.sh != dummysh) {
29281  // Found a segment. Test it if it isn't in enc-list.
29282  if (!shell2badface(checkseg)) {
29283  checkseg4encroach(&checkseg, testpt, NULL, true);
29284  }
29285  }
29286  enextself(ceiltet);
29287  }
29288  }
29289  }
29290  } else {
29291  // Check the entire list of segments.
29292  subsegs->traversalinit();
29293  checkseg.sh = shellfacetraverse(subsegs);
29294  while (checkseg.sh != (shellface *) NULL) {
29295  // Test it if it isn't in enc-list.
29296  if (!shell2badface(checkseg)) {
29297  checkseg4encroach(&checkseg, testpt, NULL, true);
29298  }
29299  checkseg.sh = shellfacetraverse(subsegs);
29300  }
29301  }
29302 
29303  return (badsubsegs->items > oldencnum);
29304 }
29305 
29307 // //
29308 // tallencsubs() Find all encroached subfaces and save them in list. //
29309 // //
29310 // If 'testpt' (p) != NULL, only check if subfaces are encroached by p, else,//
29311 // check the adjacent vertices of subfaces. //
29312 // //
29313 // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the //
29314 // subfaces which are on B_i(p)s, else, check the entire list of subfaces //
29315 // (in the pool 'this->subfaces'). //
29316 // //
29318 
29319 bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists)
29320 {
29321  list *ceillist;
29322  triface ceiltet;
29323  face checksh;
29324  long oldencnum;
29325  int i, k;
29326 
29327  // Remember the current number of encroached segments.
29328  oldencnum = badsubfaces->items;
29329 
29330  if (ceillists != (list **) NULL) {
29331  for (k = 0; k < n; k++) {
29332  ceillist = ceillists[k];
29333  // Check the subfaces on B_i(p).
29334  for (i = 0; i < ceillist->len(); i++) {
29335  ceiltet = * (triface *)(* ceillist)[i];
29336  tspivot(ceiltet, checksh);
29337  if (checksh.sh != dummysh) {
29338  // Found a subface. Test it if it isn't in enc-list.
29339  if (!shell2badface(checksh)) {
29340  checksub4encroach(&checksh, testpt, true);
29341  }
29342  }
29343  }
29344  }
29345  } else {
29346  // Check the entire list of subfaces.
29347  subfaces->traversalinit();
29348  checksh.sh = shellfacetraverse(subfaces);
29349  while (checksh.sh != (shellface *) NULL) {
29350  // Test it if it isn't in enc-list.
29351  if (!shell2badface(checksh)) {
29352  checksub4encroach(&checksh, testpt, true);
29353  }
29354  checksh.sh = shellfacetraverse(subfaces);
29355  }
29356  }
29357 
29358  return (badsubfaces->items > oldencnum);
29359 }
29360 
29362 // //
29363 // tallbadtetrahedrons() Queue all the bad-quality tetrahedra in the mesh.//
29364 // //
29366 
29367 void tetgenmesh::tallbadtetrahedrons()
29368 {
29369  triface tetloop;
29370 
29371  tetrahedrons->traversalinit();
29372  tetloop.tet = tetrahedrontraverse();
29373  while (tetloop.tet != (tetrahedron *) NULL) {
29374  checktet4badqual(&tetloop, true);
29375  tetloop.tet = tetrahedrontraverse();
29376  }
29377 }
29378 
29380 // //
29381 // repairencsegs() Repair (split) all the encroached segments. //
29382 // //
29383 // Each encroached segment is repaired by splitting it - inserting a vertex //
29384 // at or near its midpoint. Newly inserted vertices may encroach upon other //
29385 // subsegments, these are also repaired. //
29386 // //
29387 // 'chkencsub' and 'chkbadtet' are two flags that specify whether one should //
29388 // take note of new encroaced subfaces and bad quality tets that result from //
29389 // inserting vertices to repair encroached subsegments. //
29390 // //
29392 
29393 void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet)
29394 {
29395  list **tetlists, **ceillists;
29396  list **sublists, **subceillists;
29397  list *tetlist, *sublist;
29398  queue *flipque;
29399  badface *encloop;
29400  face splitseg, symsplitseg;
29401  point newpt, sympt, refpt;
29402  point e1, e2;
29403  enum locateresult symloc;
29404  int nmax, n, i, j;
29405 
29406  ceillists = NULL;
29407  flipque = NULL;
29408  subceillists = NULL;
29409  sublist = NULL;
29410  sublists = NULL;
29411  tetlist = NULL;
29412  tetlists = NULL;
29413 
29414  n = 0;
29415  nmax = 128;
29416  if (!b->fliprepair) {
29417  tetlists = new list*[nmax];
29418  ceillists = new list*[nmax];
29419  sublists = new list*[nmax];
29420  subceillists = new list*[nmax];
29421  } else {
29422  tetlist = new list(sizeof(triface), NULL, 1024);
29423  sublist = new list(sizeof(face), NULL, 256);
29424  flipque = new queue(sizeof(badface));
29425  }
29426 
29427  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
29428  // if an unlimited number of Steiner points is allowed.
29429  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
29430  badsubsegs->traversalinit();
29431  encloop = badfacetraverse(badsubsegs);
29432  while ((encloop != (badface *) NULL) && (steinerleft != 0)) {
29433  // Get an encroached subsegment s.
29434  splitseg = encloop->ss;
29435  // Clear the in-queue flag in s.
29436  setshell2badface(splitseg, NULL);
29437  if ((sorg(splitseg) == encloop->forg) &&
29438  (sdest(splitseg) == encloop->fdest)) {
29439  if (b->verbose > 1) {
29440  printf(" Get an enc-seg (%d, %d)\n", pointmark(encloop->forg),
29441  pointmark(encloop->fdest));
29442  }
29443  refpt = (point) NULL;
29444  if (b->conformdel) {
29445  // Look for a reference point.
29446  checkseg4encroach(&splitseg, NULL, &refpt, false);
29447  }
29448  // Create the new point p (at the middle of s).
29449  makepoint(&newpt);
29450  getsplitpoint(encloop->forg, encloop->fdest, refpt, newpt);
29451  setpointtype(newpt, FREESEGVERTEX);
29452  setpoint2sh(newpt, sencode(splitseg));
29453  // Decide whether p can be inserted or not.
29454  if (acceptsegpt(newpt, refpt, &splitseg)) {
29455  // Is there periodic boundary condition?
29456  if (checkpbcs) {
29457  // Insert points on other segments of incident pbcgroups.
29458  i = shellmark(splitseg) - 1;
29459  for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++) {
29460  makepoint(&sympt);
29461  symloc = getsegpbcsympoint(newpt, &splitseg, sympt, &symsplitseg,
29462  segpglist[j]);
29463  if (symloc == ONEDGE) {
29464  if (symsplitseg.sh != splitseg.sh) {
29465  // Insert sympt.
29466  setpointtype(sympt, FREESEGVERTEX);
29467  setpoint2sh(sympt, sencode(symsplitseg));
29468  // Save the endpoints of the seg for size interpolation.
29469  e1 = sorg(symsplitseg);
29470  if (shelltype(symsplitseg) == SHARP) {
29471  e2 = sdest(symsplitseg);
29472  } else {
29473  e2 = (point) NULL; // No need to do size interpolation.
29474  }
29475  if (!b->fliprepair) {
29476  // Form BC(symp), B(symp), CBC(symp)s, C(symp)s.
29477  formbowatcavity(sympt, &symsplitseg, NULL, &n, &nmax,
29478  sublists, subceillists, tetlists, ceillists);
29479  // Validate BC(symp), B(symp), CBC(symp)s, C(symp)s.
29480  if (trimbowatcavity(sympt, &symsplitseg, n, sublists,
29481  subceillists, tetlists, ceillists, -1.0)) {
29482  bowatinsertsite(sympt, &symsplitseg, n, sublists,
29483  subceillists, tetlists, ceillists, NULL, flipque,
29484  true, chkencsub, chkbadtet);
29485  setnewpointsize(sympt, e1, e2);
29486  if (steinerleft > 0) steinerleft--;
29487  } else {
29488  // p did not insert for invalid BC(symp).
29489  pointdealloc(sympt);
29490  }
29491  // Free the memory allocated in formbowatcavity().
29492  releasebowatcavity(&symsplitseg, n, sublists, subceillists,
29493  tetlists, ceillists);
29494  } else {
29495  splitencseg(sympt, &symsplitseg, tetlist, sublist, NULL,
29496  flipque, chkencsub, chkbadtet, false);
29497  setnewpointsize(sympt, e1, e2);
29498  if (steinerleft > 0) steinerleft--;
29499  }
29500  } else {
29501  // The sympt are on the same segment. It is possible when
29502  // splitseg is the symmetric rotating axes.
29503  pointdealloc(sympt);
29504  }
29505  } else if (symloc == ONVERTEX) {
29506  // The sympt already exists. It is possible when two pbc
29507  // groups are exactly the same. Omit this point.
29508  pointdealloc(sympt);
29509  } else {
29510  // Do not isnert symp for unknown cases: ONFACE, OUTSIDE.
29511  // assert(0);
29512  pointdealloc(sympt);
29513  }
29514  } // for (j = idx2segpglist[i]; j < idx2segpglist[i + 1]; j++)
29515  } // if (checkpbcs)
29516  // Save the endpoints of the seg for size interpolation.
29517  e1 = sorg(splitseg);
29518  if (shelltype(splitseg) == SHARP) {
29519  e2 = sdest(splitseg);
29520  } else {
29521  e2 = (point) NULL; // No need to do size interoplation.
29522  }
29523  if (!b->fliprepair) {
29524  // Form BC(p), B(p), CBC(p)s, and C(p)s.
29525  formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists,
29526  subceillists, tetlists, ceillists);
29527  // Validate/update BC(p), B(p), CBC(p)s, and C(p)s.
29528  if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists,
29529  tetlists, ceillists, -1.0)) {
29530  bowatinsertsite(newpt, &splitseg, n, sublists, subceillists,
29531  tetlists, ceillists, NULL, flipque, true,
29532  chkencsub, chkbadtet);
29533  setnewpointsize(newpt, e1, e2);
29534  if (steinerleft > 0) steinerleft--;
29535  } else {
29536  // p did not insert for invalid B(p).
29537  pointdealloc(newpt);
29538  }
29539  // Free the memory allocated in formbowatcavity().
29540  releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists,
29541  ceillists);
29542  } else {
29543  splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque,
29544  chkencsub, chkbadtet, false);
29545  setnewpointsize(newpt, e1, e2);
29546  if (steinerleft > 0) steinerleft--;
29547  }
29548  } else {
29549  // p did not accept for insertion.
29550  pointdealloc(newpt);
29551  } // if (checkseg4splitting(newpt, &splitseg))
29552  } // if ((encloop->forg == pa) && (encloop->fdest == pb))
29553  badfacedealloc(badsubsegs, encloop); // Remove this entry from list.
29554  encloop = badfacetraverse(badsubsegs); // Get the next enc-segment.
29555  } // while ((encloop != (badface *) NULL) && (steinerleft != 0))
29556  } // while ((badsubsegs->items > 0) && (steinerleft != 0))
29557 
29558  if (!b->fliprepair) {
29559  delete [] tetlists;
29560  delete [] ceillists;
29561  delete [] sublists;
29562  delete [] subceillists;
29563  } else {
29564  delete tetlist;
29565  delete sublist;
29566  delete flipque;
29567  }
29568 }
29569 
29571 // //
29572 // repairencsubs() Repair (split) all the encroached subfaces. //
29573 // //
29574 // Each encroached subface is repaired by splitting it - inserting a vertex //
29575 // at or near its circumcenter. Newly inserted vertices may encroach upon //
29576 // other subfaces, these are also repaired. //
29577 // //
29578 // 'chkbadtet' is a flag that specifies whether one should take note of new //
29579 // bad quality tets that result from inserted vertices. //
29580 // //
29582 
29583 void tetgenmesh::repairencsubs(bool chkbadtet)
29584 {
29585  list *tetlists[2], *ceillists[2];
29586  list *sublist, *subceillist;
29587  list *verlist;
29588  badface *encloop;
29589  face splitsub, symsplitsub;
29590  point newpt, sympt, e1;
29591  enum locateresult loc, symloc;
29592  bool reject;
29593  long oldptnum;
29594  int quenumber, n, i;
29595 
29596  quenumber = 0;
29597  n = 0;
29598  sublist = (list *) NULL;
29599  subceillist = (list *) NULL;
29600  verlist = new list(sizeof(point *), NULL, 256);
29601 
29602  // Loop until the pool 'badsubfaces' is empty. Note that steinerleft == -1
29603  // if an unlimited number of Steiner points is allowed.
29604  while ((badsubfaces->items > 0) && (steinerleft != 0)) {
29605  // Get an encroached subface f.
29606  encloop = dequeueencsub(&quenumber);
29607  splitsub = encloop->ss;
29608  // Clear the in-queue flag of f.
29609  setshell2badface(splitsub, NULL);
29610  // f may not be the same one when it was determined to be encroached.
29611  if (!isdead(&splitsub)
29612  && (sorg(splitsub) == encloop->forg)
29613  && (sdest(splitsub) == encloop->fdest)
29614  && (sapex(splitsub) == encloop->fapex)) {
29615  if (b->verbose > 1) {
29616  printf(" Dequeuing ensub (%d, %d, %d) [%d].\n",
29617  pointmark(encloop->forg), pointmark(encloop->fdest),
29618  pointmark(encloop->fapex), quenumber);
29619  }
29620  // Create a new point p at the circumcenter of f.
29621  makepoint(&newpt);
29622  for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i];
29623  setpointtype(newpt, FREESUBVERTEX);
29624  setpoint2sh(newpt, sencode(splitsub));
29625  // Set the abovepoint of f for point location.
29626  abovepoint = facetabovepointarray[shellmark(splitsub)];
29627  if (abovepoint == (point) NULL) {
29628  getfacetabovepoint(&splitsub);
29629  }
29630  // Locate p, start from f, stop at segment (1), use a tolerance to
29631  // detect ONVERTEX or OUTSIDE case. Update f on return.
29632  loc = locatesub(newpt, &splitsub, 1, b->epsilon * 1e+2);
29633  if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
29634  // Form BC(p), B(p), CBC(p) and C(p).
29635  formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
29636  &subceillist, tetlists, ceillists);
29637  // Check for encroached subsegments (on B(p)).
29638  reject = tallencsegs(newpt, 2, ceillists);
29639  // Execute point accept rule if p does not encroach upon any segment.
29640  if (!reject) {
29641  reject = !acceptfacpt(newpt, subceillist, verlist);
29642  }
29643  if (!reject) {
29644  // Validate/update cavity.
29645  reject = !trimbowatcavity(newpt, NULL, n, &sublist, &subceillist,
29646  tetlists, ceillists, -1.0);
29647  }
29648  if (!reject) {
29649  // CBC(p) should include s, so that s can be removed after CBC(p)
29650  // is remeshed. However, if there are locally non-Delaunay faces
29651  // and encroached subsegments, s may not be collected in CBC(p).
29652  // p should not be inserted in such case.
29653  reject = !sinfected(encloop->ss);
29654  }
29655  if (!reject) {
29656  if (checkpbcs) {
29657  if (shellpbcgroup(splitsub) >= 0) {
29658  // Check for splitting of the symmetric subface of f.
29659  makepoint(&sympt);
29660  symloc = getsubpbcsympoint(newpt,&splitsub,sympt,&symsplitsub);
29661  if (symloc != ONVERTEX) {
29662  // Release CBC(p) and BC(p) and free the memory..
29663  releasebowatcavity(NULL, 2, &sublist, &subceillist, tetlists,
29664  ceillists);
29665  // Form CBC(symp), C(symp), BC(sympt) and B(sympt).
29666  formbowatcavity(sympt, NULL, &symsplitsub, &n, NULL, &sublist,
29667  &subceillist, tetlists, ceillists);
29668  reject = tallencsegs(sympt, 2, ceillists);
29669  if (!reject) {
29670  reject = !acceptfacpt(sympt, subceillist, verlist);
29671  }
29672  if (!reject) {
29673  reject = !trimbowatcavity(sympt,NULL,n,&sublist,&subceillist,
29674  tetlists, ceillists, -1.0);
29675  }
29676  if (!reject) {
29677  // Insert sympt.
29678  setpoint2pbcpt(newpt, sympt);
29679  setpoint2pbcpt(sympt, newpt);
29680  setpointtype(sympt, FREESUBVERTEX);
29681  setpoint2sh(sympt, sencode(symsplitsub));
29682  // Save a point for size interpolation.
29683  e1 = sorg(symsplitsub);
29684  bowatinsertsite(sympt, NULL, n, &sublist, &subceillist,
29685  tetlists,ceillists,NULL,NULL,false,true,chkbadtet);
29686  setnewpointsize(sympt, e1, NULL);
29687  if (steinerleft > 0) steinerleft--;
29688  // Release CBC(symp) and BC(symp) and free the memory..
29689  releasebowatcavity(NULL, n, &sublist, &subceillist, tetlists,
29690  ceillists);
29691  } else {
29692  // symp is rejected for one of the following reasons:
29693  // (1) BC(symp) is not valid; or
29694  // (2) symp encroaches upon some subsegments (queued); or
29695  // (3) symp is rejected by point accepting rule.
29696  pointdealloc(sympt);
29697  // Cavity will be released by the following code.
29698  }
29699  } else {
29700  // Do not insert sympt for invalid PBC data.
29701  pointdealloc(sympt);
29702  // p is rejected due to symp.
29703  reject = true;
29704  }
29705  }
29706  } // if (checkpbcs)
29707  }
29708  if (!reject) {
29709  // Insert p.
29710  if (checkpbcs) {
29711  if (shellpbcgroup(splitsub) >= 0) {
29712  // Form CBC(p), C(p), BC(p) and B(p).
29713  formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist,
29714  &subceillist, tetlists, ceillists);
29715  trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, tetlists,
29716  ceillists, -1.0);
29717  }
29718  }
29719  // Save a point for size interpolation.
29720  e1 = sorg(splitsub);
29721  bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists,
29722  ceillists, NULL, NULL, true, true, chkbadtet);
29723  setnewpointsize(newpt, e1, NULL);
29724  if (steinerleft > 0) steinerleft--;
29725  } else {
29726  // p is rejected for the one of the following reasons:
29727  // (1) BC(p) is not valid.
29728  // (2) s does not in CBC(p).
29729  // (3) p encroaches upon some segments (queued); or
29730  // (4) p is rejected by point accepting rule, or
29731  // (5) due to the rejection of symp (the PBC).
29732  pointdealloc(newpt);
29733  } // if (!reject)
29734  // Release the cavity and free the memory.
29735  releasebowatcavity(NULL,n,&sublist,&subceillist,tetlists,ceillists);
29736  if (reject) {
29737  // Are there queued encroached subsegments.
29738  if (badsubsegs->items > 0) {
29739  // Repair enc-subsegments.
29740  oldptnum = points->items;
29741  repairencsegs(true, chkbadtet);
29742  if (points->items > oldptnum) {
29743  // Some enc-subsegments got split. Try to repair f later.
29744  splitsub = encloop->ss;
29745  if (!isdead(&splitsub)) {
29746  if (!shell2badface(splitsub)) {
29747  checksub4encroach(&splitsub, NULL, true);
29748  }
29749  }
29750  }
29751  }
29752  }
29753  } else {
29754  // Don't insert p for one of the following reasons:
29755  // (1) Locate on an existing vertex; or
29756  // (2) locate outside the domain.
29757  // Case (1) should not be possible. If such vertex v exists, it is
29758  // the circumcenter of f, ie., f is non-Delaunay. Either f was got
29759  // split before by v, but survived after v was inserted, or the
29760  // same for a f' which is nearly co-circular with f. Whatsoever,
29761  // there are encroached segs by v, but the routine tallencsegs()
29762  // did not find them out.
29763  if (loc == ONVERTEX) {
29764  printf("Internal error in repairencsubs():\n");
29765  printf(" During repairing encroached subface (%d, %d, %d)\n",
29766  pointmark(encloop->forg), pointmark(encloop->fdest),
29767  pointmark(encloop->fapex));
29768  printf(" New point %d is coincident with an existing vertex %d\n",
29769  pointmark(newpt), pointmark(sorg(splitsub)));
29770  internalerror();
29771  }
29772  // Case (2) can happen when thers is a segment s which is close to f
29773  // and is non-conforming Delaunay. The circumcenter of f encroaches
29774  // upon s, but the circumcenter of s is rejected for insertion.
29775  pointdealloc(newpt);
29776  } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
29777  } else {
29778  if (!isdead(&splitsub)) {
29779  // The subface has been changed, re-check it.
29780  checksub4encroach(&splitsub, NULL, true);
29781  }
29782  } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) &&
29783  // Remove this entry from list.
29784  badfacedealloc(badsubfaces, encloop);
29785  } // while ((badsubfaces->items > 0) && (steinerleft != 0))
29786 
29787  delete verlist;
29788 }
29789 
29791 // //
29792 // repairbadtets() Repair all bad-quality tetrahedra. //
29793 // //
29794 // All bad-quality tets are stored in pool 'badtetrahedrons'. Each bad tet //
29795 // is repaired by inserting a point at or near its circumcenter. However, if //
29796 // this point encroaches any subsegment or subface, it is not inserted. Ins- //
29797 // tead the encroached segment and subface are split. Newly inserted points //
29798 // may create other bad-quality tets, these are also repaired. //
29799 // //
29801 
29802 void tetgenmesh::repairbadtets()
29803 {
29804  list *tetlist, *ceillist;
29805  list *verlist;
29806  badface *badtet;
29807  triface starttet;
29808  point newpt, e1;
29809  enum locateresult loc;
29810  bool reject;
29811  long oldptnum;
29812  int i;
29813 
29814  tetlist = new list(sizeof(triface), NULL, 1024);
29815  ceillist = new list(sizeof(triface), NULL, 1024);
29816  verlist = new list(sizeof(point *), NULL, 256);
29817 
29818  // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1
29819  // if an unlimited number of Steiner points is allowed.
29820  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
29821  // Get a bad-quality tet t.
29822  badtet = topbadtetra();
29823  // Make sure that the tet is still the same one when it was tested.
29824  // Subsequent transformations may have made it a different tet.
29825  if ((badtet != (badface *) NULL) && !isdead(&badtet->tt)
29826  && org(badtet->tt) == badtet->forg
29827  && dest(badtet->tt) == badtet->fdest
29828  && apex(badtet->tt) == badtet->fapex
29829  && oppo(badtet->tt) == badtet->foppo) {
29830  if (b->verbose > 1) {
29831  printf(" Dequeuing btet (%d, %d, %d, %d).\n",
29832  pointmark(badtet->forg), pointmark(badtet->fdest),
29833  pointmark(badtet->fapex), pointmark(badtet->foppo));
29834  }
29835  // Create the new point p (at the circumcenter of t).
29836  makepoint(&newpt);
29837  for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i];
29838  setpointtype(newpt, FREEVOLVERTEX);
29839  // Locate p.
29840  starttet = badtet->tt;
29841  loc = preciselocate(newpt, &starttet, tetrahedrons->items);
29842  if ((loc != ONVERTEX) && (loc != OUTSIDE)) {
29843  // For BC(p) and B(p).
29844  infect(starttet);
29845  tetlist->append(&starttet);
29846  formbowatcavityquad(newpt, tetlist, ceillist);
29847  // Check for encroached subsegments.
29848  reject = tallencsegs(newpt, 1, &ceillist);
29849  if (!reject) {
29850  // Check for encroached subfaces.
29851  reject = tallencsubs(newpt, 1, &ceillist);
29852  }
29853  // Execute point accepting rule if p does not encroach upon any
29854  // subsegment and subface.
29855  if (!reject) {
29856  reject = !acceptvolpt(newpt, ceillist, verlist);
29857  }
29858  if (!reject) {
29859  reject = !trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist,
29860  &ceillist, -1.0);
29861  }
29862  if (!reject) {
29863  // BC(p) should include t, so that t can be removed after BC(p) is
29864  // remeshed. However, if there are locally non-Delaunay faces
29865  // and encroached subsegments/subfaces, t may not be collected
29866  // in BC(p). p should not be inserted in such case.
29867  reject = !infected(badtet->tt);
29868  if (reject) outbowatcircumcount++;
29869  }
29870  if (!reject) {
29871  // Save a point for size interpolation.
29872  e1 = org(starttet);
29873  // Insert p.
29874  bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist,
29875  NULL, NULL, false, false, true);
29876  setnewpointsize(newpt, e1, NULL);
29877  if (steinerleft > 0) steinerleft--;
29878  } else {
29879  // p is rejected for one of the following reasons:
29880  // (1) BC(p) is not valid.
29881  // (2) t does not in BC(p).
29882  // (3) p encroaches upon some segments;
29883  // (4) p encroaches upon some subfaces;
29884  // (5) p is rejected by the point accepting rule.
29885  pointdealloc(newpt);
29886  // Uninfect tets of BC(p).
29887  for (i = 0; i < tetlist->len(); i++) {
29888  starttet = * (triface *)(* tetlist)[i];
29889  uninfect(starttet);
29890  }
29891  }
29892  tetlist->clear();
29893  ceillist->clear();
29894  // Split encroached subsegments/subfaces if there are.
29895  if (reject) {
29896  oldptnum = points->items;
29897  if (badsubsegs->items > 0) {
29898  repairencsegs(true, true);
29899  }
29900  if (badsubfaces->items > 0) {
29901  repairencsubs(true);
29902  }
29903  if (points->items > oldptnum) {
29904  // Some encroaching subsegments/subfaces got split. Re-queue the
29905  // tet if it is still alive.
29906  starttet = badtet->tt;
29907  if (!isdead(&starttet)) {
29908  checktet4badqual(&starttet, true);
29909  }
29910  }
29911  }
29912  } else {
29913  // Do not insert p. The reason may be one of:
29914  // (1) p is coincident (ONVERTEX) with an existing vertex; or
29915  // (2) p is outside (OUTSIDE) the mesh.
29916  // Case (1) should not be possible. If such vertex v exists, it is
29917  // the circumcenter of t, ie., t is non-Delaunay. Either t was got
29918  // split before by v, but survived after v was inserted, or the
29919  // same for a t' which is nearly co-spherical with t. Whatsoever,
29920  // there are encroached segments or subfaces by v but the routines
29921  // tallencsegs() or tallencsubs() did not find them out.
29922  if (loc == ONVERTEX) {
29923  printf("Internal error in repairbadtets():\n");
29924  printf(" During repairing bad tet (%d, %d, %d, %d)\n",
29925  pointmark(badtet->forg), pointmark(badtet->fdest),
29926  pointmark(badtet->fapex), pointmark(badtet->foppo));
29927  printf(" New point %d is coincident with an existing vertex %d\n",
29928  pointmark(newpt), pointmark(org(starttet)));
29929  internalerror();
29930  }
29931  // Case (2) can happen when there is a segment s (or subface f) which
29932  // is close to f and is non-conforming Delaunay. The circumcenter
29933  // of t encroaches upon s (or f), but the circumcenter of s (or f)
29934  // is rejected for insertion.
29935  pointdealloc(newpt);
29936  } // if ((loc != ONVERTEX) && (loc != OUTSIDE))
29937  } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg &&
29938  // Remove the tet from the queue.
29939  dequeuebadtet();
29940  } // while ((badtetrahedrons->items > 0) && (steinerleft != 0))
29941 
29942  delete tetlist;
29943  delete ceillist;
29944  delete verlist;
29945 }
29946 
29948 // //
29949 // enforcequality() Refine the mesh. //
29950 // //
29952 
29953 void tetgenmesh::enforcequality()
29954 {
29955  long total, vertcount;
29956  int i;
29957 
29958  if (!b->quiet) {
29959  printf("Adding Steiner points to enforce quality.\n");
29960  }
29961 
29962  total = vertcount = 0l;
29963  if (b->conformdel) {
29964  r2count = r3count = 0l;
29965  }
29966 
29967  // If both '-D' and '-r' options are used.
29968  if (b->conformdel && b->refine) {
29969  markacutevertices(65.0);
29970  }
29971  // If '-m' is not used.
29972  if (!b->metric) {
29973  // Find and mark all sharp segments.
29974  marksharpsegments(65.0);
29975  // Decide the sizes for feature points.
29976  decidefeaturepointsizes();
29977  }
29978 
29979  // Initialize the pool of encroached subsegments.
29980  badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
29981  // Looking for encroached subsegments.
29982  tallencsegs(NULL, 0, NULL);
29983  if (b->verbose && badsubsegs->items > 0) {
29984  printf(" Splitting encroached subsegments.\n");
29985  }
29986  vertcount = points->items;
29987  // Fix encroached segments without noting any enc subfaces.
29988  repairencsegs(false, false);
29989  if (b->verbose > 0) {
29990  printf(" %ld split points.\n", points->items - vertcount);
29991  }
29992  total += points->items - vertcount;
29993 
29994  // Initialize the pool of encroached subfaces.
29995  badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0);
29996  // Initialize the priority queues of badfaces.
29997  for (i = 0; i < 3; i++) subquefront[i] = (badface *) NULL;
29998  for (i = 0; i < 3; i++) subquetail[i] = &subquefront[i];
29999  // Looking for encroached subfaces.
30000  tallencsubs(NULL, 0, NULL);
30001  if (b->verbose && badsubfaces->items > 0) {
30002  printf(" Splitting encroached subfaces.\n");
30003  }
30004  vertcount = points->items;
30005  // Fix encroached subfaces without noting bad tetrahedra.
30006  repairencsubs(false);
30007  if (b->verbose > 0) {
30008  printf(" %ld split points.\n", points->items - vertcount);
30009  }
30010  total += points->items - vertcount;
30011  // At this point, the mesh should be conforming Delaunay if no input
30012  // angle is smaller than 90 degree.
30013 
30014  // Next, fix bad quality tetrahedra.
30015  if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) {
30016  // Initialize the pool of bad tets
30017  badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
30018  // Initialize the priority queues of bad tets.
30019  for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL;
30020  firstnonemptyq = -1;
30021  recentq = -1;
30022  // Looking for bad quality tets.
30023  cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
30024  cosmindihed = cos(b->mindihedral * PI / 180.0);
30025  tallbadtetrahedrons();
30026  if (b->verbose && badtetrahedrons->items > 0) {
30027  printf(" Splitting bad tetrahedra.\n");
30028  }
30029  vertcount = points->items;
30030  repairbadtets();
30031  if (b->verbose > 0) {
30032  printf(" %ld refinement points.\n", points->items - vertcount);
30033  }
30034  total += points->items - vertcount;
30035  delete badtetrahedrons;
30036  }
30037 
30038  if (b->verbose > 0) {
30039  printf(" Totally added %ld points.\n", total);
30040  }
30041 
30042  delete badsubfaces;
30043  delete badsubsegs;
30044 }
30045 
30046 //
30047 // End of Delaunay refinement routines
30048 //
30049 
30050 //
30051 // Begin of mesh optimization routines
30052 //
30053 
30054 void tetgenmesh::dumpbadtets()
30055 {
30056  FILE *fout;
30057  badface *remtet;
30058 
30059  // Write out a file of remaining bad tets.
30060  printf(" Writing bad tets to file bad-dump.lua.\n");
30061  fout = fopen("bad-dump.lua", "w");
30062  fprintf(fout, "-- %ld remaining bad tets (> %g degree).\n",
30063  badtetrahedrons->items, b->maxdihedral);
30064  badtetrahedrons->traversalinit();
30065  remtet = badfacetraverse(badtetrahedrons);
30066  while (remtet != (badface *) NULL) {
30067  if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30068  dest(remtet->tt) == remtet->fdest &&
30069  apex(remtet->tt) == remtet->fapex &&
30070  oppo(remtet->tt) == remtet->foppo) {
30071  fprintf(fout, "p:draw_tet(%d, %d, %d, %d) -- %g\n",
30072  pointmark(remtet->forg), pointmark(remtet->fdest),
30073  pointmark(remtet->fapex), pointmark(remtet->foppo),
30074  acos(remtet->key) * 180.0 / PI);
30075  }
30076  remtet = badfacetraverse(badtetrahedrons);
30077  }
30078  fclose(fout);
30079 }
30080 
30082 // //
30083 // checktet4ill() Check a tet to see if it is illegal. //
30084 // //
30085 // A tet is "illegal" if it spans on one input facet. Save the tet in queue //
30086 // if it is illegal and the flag 'enqflag' is set. //
30087 // //
30088 // Note: Such case can happen when the input facet has non-coplanar vertices //
30089 // and the Delaunay tetrahedralization of the vertices may creat such tets. //
30090 // //
30092 
30093 bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag)
30094 {
30095  badface *newbadtet;
30096  triface checktet;
30097  face checksh1, checksh2;
30098  face checkseg;
30099  bool illflag;
30100  int i;
30101 
30102  illflag = false;
30103  for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) {
30104  tspivot(*testtet, checksh1);
30105  if (checksh1.sh != dummysh) {
30106  testtet->ver = 0;
30107  findedge(&checksh1, org(*testtet), dest(*testtet));
30108  for (i = 0; i < 3; i++) {
30109  fnext(*testtet, checktet);
30110  tspivot(checktet, checksh2);
30111  if (checksh2.sh != dummysh) {
30112  // Two subfaces share this edge.
30113  sspivot(checksh1, checkseg);
30114  if (checkseg.sh == dummysh) {
30115  // The four corners of the tet are on one facet. Illegal! Try to
30116  // flip the opposite edge of the current one.
30117  enextfnextself(*testtet);
30118  enextself(*testtet);
30119  illflag = true;
30120  break;
30121  }
30122  }
30123  enextself(*testtet);
30124  senextself(checksh1);
30125  }
30126  }
30127  if (illflag) break;
30128  }
30129 
30130  if (illflag && enqflag) {
30131  // Allocate space for the bad tetrahedron.
30132  newbadtet = (badface *) badtetrahedrons->alloc();
30133  newbadtet->tt = *testtet;
30134  newbadtet->key = -1.0; // = 180 degree.
30135  for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0;
30136  newbadtet->forg = org(*testtet);
30137  newbadtet->fdest = dest(*testtet);
30138  newbadtet->fapex = apex(*testtet);
30139  newbadtet->foppo = oppo(*testtet);
30140  newbadtet->nextitem = (badface *) NULL;
30141  if (b->verbose > 2) {
30142  printf(" Queueing illtet: (%d, %d, %d, %d).\n",
30143  pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
30144  pointmark(newbadtet->fapex), pointmark(newbadtet->foppo));
30145  }
30146  }
30147 
30148  return illflag;
30149 }
30150 
30152 // //
30153 // checktet4opt() Check a tet to see if it needs to be optimized. //
30154 // //
30155 // A tet t needs to be optimized if it fails to certain quality measures. //
30156 // The only quality measure currently used is the maximal dihedral angle at //
30157 // edges. The desired maximal dihedral angle is b->maxdihed (set by the '-s' //
30158 // option. //
30159 // //
30160 // A tet may have one, two, or three big dihedral angles. Examples: Let the //
30161 // tet t = abcd, and its four corners are nearly co-planar. Then t has one //
30162 // big dihedral angle if d is very close to the edge ab; t has three big //
30163 // dihedral angles if d's projection on the face abc is also inside abc, i.e.//
30164 // the shape of t likes a hat; finally, t has two big dihedral angles if d's //
30165 // projection onto abc is outside abc. //
30166 // //
30168 
30169 bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag)
30170 {
30171  badface *newbadtet;
30172  point pa, pb, pc, pd;
30173  REAL N[4][3], len;
30174  REAL cosd;
30175  bool enq;
30176  int i, j;
30177 
30178  cosd = 0.0;
30179  enq = false;
30180  pa = (point) testtet->tet[4];
30181  pb = (point) testtet->tet[5];
30182  pc = (point) testtet->tet[6];
30183  pd = (point) testtet->tet[7];
30184  // Compute the 4 face normals: N[0] cbd, N[1] acd, N[2] bad, N[3] abc.
30185  tetallnormal(pa, pb, pc, pd, N, NULL);
30186  // Normalize the normals.
30187  for (i = 0; i < 4; i++) {
30188  len = sqrt(dot(N[i], N[i]));
30189  if (len != 0.0) {
30190  for (j = 0; j < 3; j++) N[i][j] /= len;
30191  }
30192  }
30193  // Find all large dihedral angles.
30194  for (i = 0; i < 6; i++) {
30195  // Locate the edge i and calculate the dihedral angle at the edge.
30196  testtet->loc = 0;
30197  testtet->ver = 0;
30198  switch (i) {
30199  case 0: // edge ab
30200  cosd = -dot(N[2], N[3]);
30201  break;
30202  case 1: // edge cd
30203  enextfnextself(*testtet);
30204  enextself(*testtet);
30205  cosd = -dot(N[0], N[1]);
30206  break;
30207  case 2: // edge bd
30208  enextfnextself(*testtet);
30209  enext2self(*testtet);
30210  cosd = -dot(N[0], N[2]);
30211  break;
30212  case 3: // edge bc
30213  enextself(*testtet);
30214  cosd = -dot(N[0], N[3]);
30215  break;
30216  case 4: // edge ad
30217  enext2fnextself(*testtet);
30218  enextself(*testtet);
30219  cosd = -dot(N[1], N[2]);
30220  break;
30221  case 5: // edge ac
30222  enext2self(*testtet);
30223  cosd = -dot(N[1], N[3]);
30224  break;
30225  }
30226  if (cosd < cosmaxdihed) {
30227  // A bigger dihedral angle.
30228  if (enqflag) {
30229  // Allocate space for the bad tetrahedron.
30230  newbadtet = (badface *) badtetrahedrons->alloc();
30231  newbadtet->tt = *testtet;
30232  newbadtet->key = cosd;
30233  for (j = 0; j < 3; j++) newbadtet->cent[j] = 0.0;
30234  newbadtet->forg = org(*testtet);
30235  newbadtet->fdest = dest(*testtet);
30236  newbadtet->fapex = apex(*testtet);
30237  newbadtet->foppo = oppo(*testtet);
30238  newbadtet->nextitem = (badface *) NULL;
30239  if (b->verbose > 2) {
30240  printf(" Queueing tet: (%d, %d, %d, %d), dihed %g (degree).\n",
30241  pointmark(newbadtet->forg), pointmark(newbadtet->fdest),
30242  pointmark(newbadtet->fapex), pointmark(newbadtet->foppo),
30243  acos(cosd) * 180.0 / PI);
30244  }
30245  }
30246  enq = true;
30247  }
30248  }
30249 
30250  return enq;
30251 }
30252 
30254 // //
30255 // removeedge() Remove an edge //
30256 // //
30257 // 'remedge' is a tet (abcd) having the edge ab wanted to be removed. Local //
30258 // reconnecting operations are used to remove edge ab. The following opera- //
30259 // tion will be tryed. //
30260 // //
30261 // If ab is on the hull, and abc and abd are both hull faces. Then ab can be //
30262 // removed by stripping abcd from the mesh. However, if ab is a segemnt, do //
30263 // the operation only if 'b->optlevel' > 1 and 'b->nobisect == 0'. //
30264 // //
30265 // If ab is an internal edge, there are n tets contains it. Then ab can be //
30266 // removed if there exists another m tets which can replace the n tets with- //
30267 // out changing the boundary of the n tets. //
30268 // //
30269 // If 'optflag' is set. The value 'remedge->key' means cos(theta), where //
30270 // 'theta' is the maximal dishedral angle at ab. In this case, even if the //
30271 // n-to-m flip exists, it will not be performed if the maximum dihedral of //
30272 // the new tets is larger than 'theta'. //
30273 // //
30275 
30276 bool tetgenmesh::removeedge(badface* remedge, bool optflag)
30277 {
30278  triface abcd, badc; // Tet configuration at edge ab.
30279  triface baccasing, abdcasing;
30280  triface abtetlist[11]; // Old configuration at ab, save maximum 10 tets.
30281  triface bftetlist[11]; // Old configuration at bf, save maximum 10 tets.
30282  triface newtetlist[33]; // New configuration after removing ab.
30283  face checksh;
30284  enum fliptype fty;
30285  REAL key;
30286  bool remflag, subflag;
30287  int n, n1, m, i, j;
30288 
30289  // First try to strip abcd from the mesh. This needs to check either ab
30290  // or cd is on the hull. Try to strip it whichever is true.
30291  abcd = remedge->tt;
30292  adjustedgering(abcd, CCW);
30293  i = 0;
30294  do {
30295  sym(abcd, baccasing);
30296  // Is the tet on the hull?
30297  if (baccasing.tet == dummytet) {
30298  fnext(abcd, badc);
30299  sym(badc, abdcasing);
30300  if (abdcasing.tet == dummytet) {
30301  // Strip the tet from the mesh -> ab is removed as well.
30302  if (removetetbypeeloff(&abcd)) {
30303  if (b->verbose > 1) {
30304  printf(" Stripped tet from the mesh.\n");
30305  }
30306  optcount[0]++;
30307  return true;
30308  }
30309  }
30310  }
30311  // Check if the oppsite edge cd is on the hull.
30312  enext2fnextself(abcd);
30313  enext2self(abcd);
30314  esymself(abcd); // --> cdab
30315  i++;
30316  } while (i < 2);
30317 
30318  // Get the tets configuration at ab. Collect maximum 10 tets.
30319  subflag = false;
30320  abcd = remedge->tt;
30321  adjustedgering(abcd, CW);
30322  n = 0;
30323  abtetlist[n] = abcd;
30324  do {
30325  // Is the list full?
30326  if (n == 10) break;
30327  // Stop if a subface appears.
30328  tspivot(abtetlist[n], checksh);
30329  if (checksh.sh != dummysh) {
30330  // ab is either a segment or a facet edge. The latter case is not
30331  // handled yet! An edge flip is needed.
30332  subflag = true; break; // return false;
30333  }
30334  // Get the next tet at ab.
30335  fnext(abtetlist[n], abtetlist[n + 1]);
30336  n++;
30337  } while (apex(abtetlist[n]) != apex(abcd));
30338 
30339  remflag = false;
30340  key = remedge->key;
30341 
30342  if (subflag && optflag) {
30343  abcd = remedge->tt;
30344  adjustedgering(abcd, CCW);
30345  // Try to flip face cda or cdb to improve quality.
30346  for (j = 0; j < 2; j++) {
30347  if (j == 0) {
30348  enext2fnext(abcd, abtetlist[0]); // Goto cda.
30349  } else {
30350  enextfnext(abcd, abtetlist[0]); // Goto cdb.
30351  }
30352  fty = categorizeface(abtetlist[0]);
30353  if (fty == T23) {
30354  // A 2-to-3 flip is possible.
30355  sym(abtetlist[0], abtetlist[1]);
30356  assert(abtetlist[1].tet != dummytet);
30357  n = 2;
30358  m = 3;
30359  remflag = removefacebyflip23(&key, abtetlist, newtetlist, NULL);
30360  } else if (fty == T22) {
30361  // A 2-to-2 or 4-to-4 flip is possible.
30362  n = 2;
30363  newtetlist[0] = abtetlist[0];
30364  adjustedgering(newtetlist[0], CW);
30365  fnext(newtetlist[0], newtetlist[1]);
30366  assert(newtetlist[1].tet != dummytet);
30367  // May it is 4-to-4 flip.
30368  if (fnext(newtetlist[1], newtetlist[2])) {
30369  fnext(newtetlist[2], newtetlist[3]);
30370  assert(newtetlist[3].tet != dummytet);
30371  n = 4;
30372  }
30373  m = n;
30374  remflag = removeedgebyflip22(&key, n, newtetlist, NULL);
30375  }
30376  // Has quality been improved?
30377  if (remflag) {
30378  if (b->verbose > 1) {
30379  printf(" Done flip %d-to-%d. Qual: %g -> %g.\n", n, m,
30380  acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0);
30381  }
30382  // Delete the old tets. Note, flip22() does not create new tets.
30383  if (m == 3) {
30384  for (i = 0; i < n; i++) {
30385  tetrahedrondealloc(abtetlist[i].tet);
30386  }
30387  }
30388  for (i = 0; i < m; i++) {
30389  checktet4opt(&(newtetlist[i]), true);
30390  }
30391  optcount[1]++;
30392  return true;
30393  }
30394  } // if (j = 0; j < 2; j++)
30395  // Faces are not flipable. Return.
30396  return false;
30397  }
30398 
30399  // 2 <= n <= 10.
30400  if (n == 3) {
30401  // There are three tets at ab. Try to do a flip32 at ab.
30402  remflag = removeedgebyflip32(&key, abtetlist, newtetlist, NULL);
30403  } else if ((n == 4) || (n == 5) || (n == 6)) {
30404  // Four tets case. Try to do edge transformation.
30405  remflag = removeedgebytranNM(&key,n,abtetlist,newtetlist,NULL,NULL,NULL);
30406  } else {
30407  if (b->verbose > 1) {
30408  printf(" !! Unhandled case: n = %d.\n", n);
30409  }
30410  }
30411  if (remflag) {
30412  optcount[n]++;
30413  // Delete the old tets.
30414  for (i = 0; i < n; i++) {
30415  tetrahedrondealloc(abtetlist[i].tet);
30416  }
30417  m = (n - 2) * 2; // The numebr of new tets.
30418  if (b->verbose > 1) {
30419  printf(" Done flip %d-to-%d. ", n, m);
30420  if (optflag) {
30421  printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
30422  acos(key) / PI * 180.0);
30423  }
30424  printf("\n");
30425  }
30426  }
30427 
30428  if (!remflag && (key == remedge->key) && (n < 7)) {
30429  // Try to do a combination of flips.
30430  n1 = 0;
30431  remflag = removeedgebycombNM(&key, n, abtetlist, &n1, bftetlist,
30432  newtetlist, NULL);
30433  if (remflag) {
30434  optcount[9]++;
30435  // Delete the old tets.
30436  for (i = 0; i < n; i++) {
30437  tetrahedrondealloc(abtetlist[i].tet);
30438  }
30439  for (i = 0; i < n1; i++) {
30440  if (!isdead(&(bftetlist[i]))) {
30441  tetrahedrondealloc(bftetlist[i].tet);
30442  }
30443  }
30444  m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets.
30445  if (b->verbose > 1) {
30446  printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1);
30447  if (optflag) {
30448  printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0,
30449  acos(key) / PI * 180.0);
30450  }
30451  printf("\n");
30452  }
30453  }
30454  }
30455 
30456  if (remflag) {
30457  // edge is removed. Test new tets for further optimization.
30458  for (i = 0; i < m; i++) {
30459  if (optflag) {
30460  checktet4opt(&(newtetlist[i]), true);
30461  } else {
30462  checktet4ill(&(newtetlist[i]), true);
30463  }
30464  }
30465  }
30466 
30467  return remflag;
30468 }
30469 
30471 // //
30472 // smoothsliver() Remove a sliver by smoothing a vertex of it. //
30473 // //
30474 // The 'slivtet' represents a sliver abcd, and ab is the current edge which //
30475 // has a large dihedral angle (close to 180 degree). //
30476 // //
30478 
30479 bool tetgenmesh::smoothsliver(badface* remedge, list *starlist)
30480 {
30481  triface checktet;
30482  point smthpt;
30483  bool smthed;
30484  int idx, i, j;
30485 
30486  // Find a Steiner volume point and smooth it.
30487  smthed = false;
30488  for (i = 0; i < 4 && !smthed; i++) {
30489  smthpt = (point) remedge->tt.tet[4 + i];
30490  // Is it a volume point?
30491  if (pointtype(smthpt) == FREEVOLVERTEX) {
30492  // Is it a Steiner point?
30493  idx = pointmark(smthpt) - in->firstnumber;
30494  if (!(idx < in->numberofpoints)) {
30495  // Smooth a Steiner volume point.
30496  starlist->append(&(remedge->tt.tet));
30497  formstarpolyhedron(smthpt, starlist, NULL, false);
30498  smthed = smoothpoint(smthpt,NULL,NULL,starlist,false,&remedge->key);
30499  // If it is smoothed. Queue new bad tets.
30500  if (smthed) {
30501  for (j = 0; j < starlist->len(); j++) {
30502  checktet = * (triface *)(* starlist)[j];
30503  checktet4opt(&checktet, true);
30504  }
30505  }
30506  starlist->clear();
30507  }
30508  }
30509  }
30510 
30511  /* Omit to smooth segment points. This may cause infinite loop.
30512  if (smthed) {
30513  return true;
30514  }
30515  face abseg, nextseg, prevseg;
30516  point pt[2];
30517  // Check if ab is a segment.
30518  tsspivot(slivtet, &abseg);
30519  if (abseg.sh == dummysh) {
30520  // ab is not a segment. Check if a or b is a Steiner segment point.
30521  for (i = 0; i < 2 && !smthed; i++) {
30522  smthpt = (i == 0 ? org(*slivtet) : dest(*slivtet));
30523  if (pointtype(smthpt) == FREESEGVERTEX) {
30524  // Is it a Steiner point?
30525  idx = pointmark(smthpt) - in->firstnumber;
30526  if (!(idx < in->numberofpoints)) {
30527  // Smooth a Steiner segment point. Get the segment.
30528  sdecode(point2sh(smthpt), nextseg);
30529  locateseg(smthpt, &nextseg);
30530  assert(sorg(nextseg) == smthpt);
30531  pt[0] = sdest(nextseg);
30532  senext2(nextseg, prevseg);
30533  spivotself(prevseg);
30534  prevseg.shver = 0;
30535  if (sorg(prevseg) == smthpt) sesymself(prevseg);
30536  assert(sdest(prevseg) == smthpt);
30537  pt[1] = sorg(prevseg);
30538  starlist->append(slivtet);
30539  formstarpolyhedron(smthpt, starlist, NULL, true);
30540  smthed = smoothpoint(smthpt, pt[0], pt[1], starlist, false);
30541  // If it is smoothed. Check if the tet is still a sliver.
30542  if (smthed) checktet4opt(slivtet, true);
30543  starlist->clear();
30544  }
30545  }
30546  }
30547  }
30548  */
30549 
30550  return smthed;
30551 }
30552 
30554 // //
30555 // splitsliver() Remove a sliver by inserting a point. //
30556 // //
30557 // The 'remedge->tt' represents a sliver abcd, ab is the current edge which //
30558 // has a large dihedral angle (close to 180 degree). //
30559 // //
30561 
30562 bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist)
30563 {
30564  triface starttet;
30565  face checkseg;
30566  point newpt, pt[4];
30567  bool remflag;
30568  int i;
30569 
30570  starttet = remedge->tt;
30571 
30572  // Check if cd is a segment.
30573  adjustedgering(starttet, CCW);
30574  enextfnextself(starttet);
30575  enextself(starttet);
30576  tsspivot(&starttet, &checkseg);
30577  if (b->nobisect == 0) {
30578  if (checkseg.sh != dummysh) {
30579  // cd is a segment. The seg will be split. BUT do not flip! Due to the
30580  // exact predicates, lot of slivers ay be rsulted and hard to remove.
30581  checkseg.shver = 0;
30582  pt[0] = sorg(checkseg);
30583  pt[1] = sdest(checkseg);
30584  makepoint(&newpt);
30585  getsplitpoint(pt[0], pt[1], NULL, newpt);
30586  setpointtype(newpt, FREESEGVERTEX);
30587  setpoint2sh(newpt, sencode(checkseg));
30588  // Insert p, this should always success.
30589  sstpivot(&checkseg, &starttet);
30590  splittetedge(newpt, &starttet, NULL);
30591  // Collect the new tets connecting at p.
30592  sstpivot(&checkseg, &starttet);
30593  ceillist->append(&starttet);
30594  formstarpolyhedron(newpt, ceillist, NULL, true);
30595  setnewpointsize(newpt, pt[0], NULL);
30596  if (steinerleft > 0) steinerleft--;
30597  // Smooth p.
30598  smoothpoint(newpt, pt[0], pt[1], ceillist, false, NULL);
30599  // Queue new slivers.
30600  for (i = 0; i < ceillist->len(); i++) {
30601  starttet = * (triface *)(* ceillist)[i];
30602  checktet4opt(&starttet, true);
30603  }
30604  ceillist->clear();
30605  return true;
30606  }
30607  }
30608 
30609  // Get the four corners.
30610  for (i = 0; i < 4; i++) {
30611  pt[i] = (point) starttet.tet[4 + i];
30612  }
30613  // Create the new point p (at the circumcenter of t).
30614  makepoint(&newpt);
30615  for (i = 0; i < 3; i++) {
30616  newpt[i] = 0.25 * (pt[0][i] + pt[1][i] + pt[2][i] + pt[3][i]);
30617  }
30618  setpointtype(newpt, FREEVOLVERTEX);
30619 
30620  // Form the Bowyer-Watson cavity of p.
30621  remflag = false;
30622  infect(starttet);
30623  tetlist->append(&starttet);
30624  formbowatcavityquad(newpt, tetlist, ceillist);
30625  if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0)) {
30626  // Smooth p.
30627  if (smoothpoint( newpt, NULL, NULL, ceillist, false, &remedge->key)) {
30628  // Insert p.
30629  bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL,
30630  NULL, false, false, false);
30631  setnewpointsize(newpt, pt[0], NULL);
30632  if (steinerleft > 0) steinerleft--;
30633  // Queue new slivers.
30634  for (i = 0; i < ceillist->len(); i++) {
30635  starttet = * (triface *)(* ceillist)[i];
30636  checktet4opt(&starttet, true);
30637  }
30638  remflag = true;
30639  } // if (smoothpoint)
30640  } // if (trimbowatcavity)
30641 
30642  if (!remflag) {
30643  // p is rejected for BC(p) is not valid.
30644  pointdealloc(newpt);
30645  // Uninfect tets of BC(p).
30646  for (i = 0; i < tetlist->len(); i++) {
30647  starttet = * (triface *)(* tetlist)[i];
30648  uninfect(starttet);
30649  }
30650  }
30651  tetlist->clear();
30652  ceillist->clear();
30653 
30654  return remflag;
30655 }
30656 
30658 // //
30659 // tallslivers() Queue all the slivers in the mesh. //
30660 // //
30662 
30663 void tetgenmesh::tallslivers(bool optflag)
30664 {
30665  triface tetloop;
30666 
30667  tetrahedrons->traversalinit();
30668  tetloop.tet = tetrahedrontraverse();
30669  while (tetloop.tet != (tetrahedron *) NULL) {
30670  if (optflag) {
30671  checktet4opt(&tetloop, true);
30672  } else {
30673  checktet4ill(&tetloop, true);
30674  }
30675  tetloop.tet = tetrahedrontraverse();
30676  }
30677 }
30678 
30680 // //
30681 // optimizemesh() Improve mesh quality by mesh optimizations. //
30682 // //
30683 // Available mesh optimizing operations are: (1) multiple edge flips (3-to-2,//
30684 // 4-to-4, 5-to-6, etc), (2) free vertex deletion, (3) new vertex insertion. //
30685 // (1) is mandatory, while (2) and (3) are optionally. //
30686 // //
30687 // The variable 'b->optlevel' (set after '-s') determines the use of these //
30688 // operations. If it is: 0, do no optimization; 1, only do (1) operation; 2, //
30689 // do (1) and (2) operations; 3, do all operations. Deault, b->optlvel = 2. //
30690 // //
30692 
30693 void tetgenmesh::optimizemesh(bool optflag)
30694 {
30695  list *splittetlist, *tetlist, *ceillist;
30696  badface *remtet, *lastentry;
30697  //REAL maxdihed, objdihed, curdihed; // maxdihead commented out to get gcc 4.6 working
30698  REAL objdihed, curdihed;
30699  long oldnum;
30700  int iter, i;
30701 
30702  objdihed = 0.0;
30703 
30704  if (!b->quiet) {
30705  if (optflag) {
30706  printf("Optimizing mesh.\n");
30707  } else {
30708  printf("Repairing mesh.\n");
30709  }
30710  }
30711 
30712 #ifdef SELF_CHECK
30713  if (optflag && (b->verbose)) {
30714  printf(" level = %d.\n", b->optlevel);
30715  }
30716 #endif
30717 
30718  // Initialize the pool of bad tets.
30719  badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0);
30720  if (optflag) {
30721  cosmaxdihed = cos(b->maxdihedral * PI / 180.0);
30722  cosmindihed = cos(b->mindihedral * PI / 180.0);
30723  // The radian of the maximum dihedral angle.
30724  //maxdihed = b->maxdihedral / 180.0 * PI; // maxdihead commented out to get gcc 4.6 working
30725  // A sliver has an angle large than 'objdihed' will be split.
30726  objdihed = b->maxdihedral + 5.0;
30727  if (objdihed < 170.0) objdihed = 170.0;
30728  objdihed = objdihed / 180.0 * PI;
30729  }
30730  // Looking for non-optimal tets.
30731  tallslivers(optflag);
30732 
30733  optcount[0] = 0l; // tet strip count.
30734  optcount[1] = 0l; // face (2-3) and edge (2-2) flip count.
30735  optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
30736  optcount[9] = 0l; // combined flip count.
30737 
30738  // Perform edge flip to improve quality.
30739  lastentry = (badface *) NULL;
30740  // Loop until pool 'badtetrahedrons' is empty.
30741  while (badtetrahedrons->items > 0) {
30742  badtetrahedrons->traversalinit();
30743  remtet = badfacetraverse(badtetrahedrons);
30744  while (remtet != (badface *) NULL) {
30745  // Make sure that the tet is still the same one when it was tested.
30746  // Subsequent transformations may have made it a different tet.
30747  if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30748  dest(remtet->tt) == remtet->fdest &&
30749  apex(remtet->tt) == remtet->fapex &&
30750  oppo(remtet->tt) == remtet->foppo) {
30751  if (b->verbose > 1) {
30752  printf(" Repair tet (%d, %d, %d, %d) %g (degree).\n",
30753  pointmark(remtet->forg), pointmark(remtet->fdest),
30754  pointmark(remtet->fapex), pointmark(remtet->foppo),
30755  acos(remtet->key) / PI * 180.0);
30756  }
30757  if (!removeedge(remtet, optflag)) {
30758  // An unremoveable tet. Check if it forms a loop.
30759  if (lastentry != (badface *) NULL) {
30760  if (remtet == lastentry) break;
30761  } else {
30762  // Remember this tet as a breakpoint.
30763  lastentry = remtet;
30764  }
30765  } else {
30766  // Clear the breakpoint.
30767  lastentry = (badface *) NULL;
30768  // Remove the entry from the queue.
30769  badfacedealloc(badtetrahedrons, remtet);
30770  }
30771  } else {
30772  // Remove the entry from the queue.
30773  badfacedealloc(badtetrahedrons, remtet);
30774  }
30775  remtet = badfacetraverse(badtetrahedrons);
30776  }
30777  // Stop if the above loop was out by force.
30778  if (remtet != (badface *) NULL) break;
30779  }
30780 
30781  if (b->verbose) {
30782  if (optcount[0] > 0l) {
30783  printf(" %ld tets are peeled off.\n", optcount[0]);
30784  }
30785  if (optcount[1] > 0l) {
30786  printf(" %ld faces are flipped.\n", optcount[1]);
30787  }
30788  if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
30789  optcount[9] > 0l) {
30790  printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
30791  optcount[5] + optcount[6] + optcount[9]);
30792  }
30793  // if (badtetrahedrons->items > 0l) {
30794  // printf(" %ld edges remain.\n", badtetrahedrons->items);
30795  // }
30796  }
30797 
30798  if ((badtetrahedrons->items > 0l) && optflag && (b->optlevel > 2)) {
30799  splittetlist = new list(sizeof(badface), NULL, 256);
30800  tetlist = new list(sizeof(triface), NULL, 256);
30801  ceillist = new list(sizeof(triface), NULL, 256);
30802  oldnum = points->items;
30803  smoothsegverts = smoothvolverts = 0;
30804  optcount[1] = 0l;
30805  optcount[3] = optcount[4] = optcount[5] = optcount[6] = 0l; // edge flips.
30806  optcount[9] = 0l; // combined flip count.
30807  iter = 0;
30808 
30809  do {
30810  // Form a list of slivers to be split and clean the pool.
30811  badtetrahedrons->traversalinit();
30812  remtet = badfacetraverse(badtetrahedrons);
30813  while (remtet != (badface *) NULL) {
30814  splittetlist->append(remtet);
30815  // Remove the entry from the queue.
30816  badfacedealloc(badtetrahedrons, remtet);
30817  remtet = badfacetraverse(badtetrahedrons);
30818  }
30819  for (i = 0; i < splittetlist->len(); i++) {
30820  remtet = (badface *)(* splittetlist)[i];
30821  // Make sure that the tet is still the same one when it was tested.
30822  // Subsequent transformations may have made it a different tet.
30823  if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg &&
30824  dest(remtet->tt) == remtet->fdest &&
30825  apex(remtet->tt) == remtet->fapex &&
30826  oppo(remtet->tt) == remtet->foppo) {
30827  // The sliver may get smoothed due to a neighboring tet.
30828  curdihed = facedihedral(remtet->forg, remtet->fdest, remtet->fapex,
30829  remtet->foppo);
30830  // The dihedral angle of a tet must less than PI, correct it.
30831  if (curdihed > PI) curdihed = 2 * PI - curdihed;
30832  // Is it a large angle?
30833  if (curdihed > objdihed) {
30834  remtet->key = cos(curdihed);
30835  if (b->verbose > 1) {
30836  printf(" Get sliver (%d, %d, %d, %d) %g (degree).\n",
30837  pointmark(remtet->forg), pointmark(remtet->fdest),
30838  pointmark(remtet->fapex), pointmark(remtet->foppo),
30839  acos(remtet->key) / PI * 180.0);
30840  }
30841  if (!removeedge(remtet, optflag)) {
30842  if (!smoothsliver(remtet, tetlist)) {
30843  splitsliver(remtet, tetlist, ceillist);
30844  }
30845  }
30846  }
30847  }
30848  }
30849  iter++;
30850  } while ((badtetrahedrons->items > 0l) && (iter < b->optpasses));
30851 
30852  if (b->verbose) {
30853  printf(" %d passes.\n", iter);
30854  if ((points->items - oldnum) > 0l) {
30855  printf(" %ld points are inserted (%d on segment).\n",
30856  points->items - oldnum, smoothsegverts);
30857  }
30858  if (optcount[1] > 0l) {
30859  printf(" %ld faces are flipped.\n", optcount[1]);
30860  }
30861  if (optcount[3] + optcount[4] + optcount[5] + optcount[6] +
30862  optcount[9] > 0l) {
30863  printf(" %ld edges are flipped.\n", optcount[3] + optcount[4] +
30864  optcount[5] + optcount[6] + optcount[9]);
30865  }
30866  // if (badtetrahedrons->items > 0l) {
30867  // printf(" %ld edges remain.\n", badtetrahedrons->items);
30868  // }
30869  }
30870  delete tetlist;
30871  delete ceillist;
30872  delete splittetlist;
30873  }
30874 
30875  delete badtetrahedrons;
30876  badtetrahedrons = (memorypool *) NULL;
30877 }
30878 
30879 //
30880 // End of mesh optimization routines
30881 //
30882 
30883 //
30884 // Begin of I/O rouitnes
30885 //
30886 
30888 // //
30889 // transfernodes() Transfer nodes from 'io->pointlist' to 'this->points'. //
30890 // //
30891 // Initializing 'this->points'. Transferring all points from 'in->pointlist'//
30892 // into it. All points are indexed (start from in->firstnumber). Each point //
30893 // is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,//
30894 // zmin, zmax) and the diameter (longest) of the point set are calculated. //
30895 // //
30897 
30898 void tetgenmesh::transfernodes()
30899 {
30900  point pointloop;
30901  REAL x, y, z;
30902  int coordindex;
30903  int attribindex;
30904  int mtrindex;
30905  int i, j;
30906 
30907  // Read the points.
30908  coordindex = 0;
30909  attribindex = 0;
30910  mtrindex = 0;
30911  for (i = 0; i < in->numberofpoints; i++) {
30912  makepoint(&pointloop);
30913  // Read the point coordinates.
30914  x = pointloop[0] = in->pointlist[coordindex++];
30915  y = pointloop[1] = in->pointlist[coordindex++];
30916  z = pointloop[2] = in->pointlist[coordindex++];
30917  // Read the point attributes.
30918  for (j = 0; j < in->numberofpointattributes; j++) {
30919  pointloop[3 + j] = in->pointattributelist[attribindex++];
30920  }
30921  // Read the point metric tensor.
30922  for (j = 0; j < in->numberofpointmtrs; j++) {
30923  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
30924  }
30925  // Determine the smallest and largests x, y and z coordinates.
30926  if (i == 0) {
30927  xmin = xmax = x;
30928  ymin = ymax = y;
30929  zmin = zmax = z;
30930  } else {
30931  xmin = (x < xmin) ? x : xmin;
30932  xmax = (x > xmax) ? x : xmax;
30933  ymin = (y < ymin) ? y : ymin;
30934  ymax = (y > ymax) ? y : ymax;
30935  zmin = (z < zmin) ? z : zmin;
30936  zmax = (z > zmax) ? z : zmax;
30937  }
30938  }
30939  // 'longest' is the largest possible edge length formed by input vertices.
30940  x = xmax - xmin;
30941  y = ymax - ymin;
30942  z = zmax - zmin;
30943  longest = sqrt(x * x + y * y + z * z);
30944  if (longest == 0.0) {
30945  printf("Error: The point set is trivial.\n");
30946  terminatetetgen(1);
30947  }
30948  // Two identical points are distinguished by 'lengthlimit'.
30949  lengthlimit = longest * b->epsilon * 1e+2;
30950 }
30951 
30953 // //
30954 // jettisonnodes() Jettison unused or duplicated vertices. //
30955 // //
30956 // Unused points are those input points which are outside the mesh domain or //
30957 // have no connection (isolated) to the mesh. Duplicated points exist for //
30958 // example if the input PLC is read from a .stl mesh file (marked during the //
30959 // Delaunay tetrahedralization step. This routine remove these points from //
30960 // points list. All existing points are reindexed. //
30961 // //
30963 
30964 void tetgenmesh::jettisonnodes()
30965 {
30966  point pointloop;
30967  bool jetflag;
30968  int oldidx, newidx;
30969  int remcount;
30970 
30971  if (!b->quiet) {
30972  printf("Jettisoning redundants points.\n");
30973  }
30974 
30975  points->traversalinit();
30976  pointloop = pointtraverse();
30977  oldidx = newidx = 0; // in->firstnumber;
30978  remcount = 0;
30979  while (pointloop != (point) NULL) {
30980  jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
30981  (pointtype(pointloop) == UNUSEDVERTEX);
30982  if (jetflag) {
30983  // It is a duplicated point, delete it.
30984  pointdealloc(pointloop);
30985  remcount++;
30986  } else {
30987  // Re-index it.
30988  setpointmark(pointloop, newidx + in->firstnumber);
30989  if (in->pointmarkerlist != (int *) NULL) {
30990  if (oldidx < in->numberofpoints) {
30991  // Re-index the point marker as well.
30992  in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
30993  }
30994  }
30995  newidx++;
30996  }
30997  oldidx++;
30998  if (oldidx == in->numberofpoints) {
30999  // Update the numbe of input points (Because some were removed).
31000  in->numberofpoints -= remcount;
31001  // Remember this number for output original input nodes.
31002  jettisoninverts = remcount;
31003  }
31004  pointloop = pointtraverse();
31005  }
31006  if (b->verbose) {
31007  printf(" %d duplicated vertices have been removed.\n", dupverts);
31008  printf(" %d unused vertices have been removed.\n", unuverts);
31009  }
31010  dupverts = 0;
31011  unuverts = 0;
31012 
31013  // The following line ensures that dead items in the pool of nodes cannot
31014  // be allocated for the new created nodes. This ensures that the input
31015  // nodes will occur earlier in the output files, and have lower indices.
31016  points->deaditemstack = (void *) NULL;
31017 }
31018 
31020 // //
31021 // highorder() Create extra nodes for quadratic subparametric elements. //
31022 // //
31023 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
31024 // high-order nodes of each tetrahedron. This routine is used only when -o2 //
31025 // switch is used. //
31026 // //
31028 
31029 void tetgenmesh::highorder()
31030 {
31031  triface tetloop, worktet;
31032  triface spintet, adjtet;
31033  point torg, tdest, tapex;
31034  point *extralist, *adjextralist;
31035  point newpoint;
31036  int hitbdry, ptmark;
31037  int i, j;
31038 
31039  if (!b->quiet) {
31040  printf("Adding vertices for second-order tetrahedra.\n");
31041  }
31042 
31043  // Initialize the 'highordertable'.
31044  highordertable = new point[tetrahedrons->items * 6];
31045  if (highordertable == (point *) NULL) {
31046  printf("Error: Out of memory.\n");
31047  terminatetetgen(1);
31048  }
31049 
31050  // The following line ensures that dead items in the pool of nodes cannot
31051  // be allocated for the extra nodes associated with high order elements.
31052  // This ensures that the primary nodes (at the corners of elements) will
31053  // occur earlier in the output files, and have lower indices, than the
31054  // extra nodes.
31055  points->deaditemstack = (void *) NULL;
31056 
31057  // Assign an entry for each tetrahedron to find its extra nodes. At the
31058  // mean while, initialize all extra nodes be NULL.
31059  i = 0;
31060  tetrahedrons->traversalinit();
31061  tetloop.tet = tetrahedrontraverse();
31062  while (tetloop.tet != (tetrahedron *) NULL) {
31063  tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
31064  for (j = 0; j < 6; j++) {
31065  highordertable[i + j] = (point) NULL;
31066  }
31067  i += 6;
31068  tetloop.tet = tetrahedrontraverse();
31069  }
31070 
31071  // To create a unique node on each edge. Loop over all tetrahedra, and
31072  // look at the six edges of each tetrahedron. If the extra node in
31073  // the tetrahedron corresponding to this edge is NULL, create a node
31074  // for this edge, at the same time, set the new node into the extra
31075  // node lists of all other tetrahedra sharing this edge.
31076  tetrahedrons->traversalinit();
31077  tetloop.tet = tetrahedrontraverse();
31078  while (tetloop.tet != (tetrahedron *) NULL) {
31079  // Get the list of extra nodes.
31080  extralist = (point *) tetloop.tet[highorderindex];
31081  worktet.tet = tetloop.tet;
31082  for (i = 0; i < 6; i++) {
31083  if (extralist[i] == (point) NULL) {
31084  // Operate on this edge.
31085  worktet.loc = edge2locver[i][0];
31086  worktet.ver = edge2locver[i][1];
31087  // Create a new node on this edge.
31088  torg = org(worktet);
31089  tdest = dest(worktet);
31090  // Create a new node in the middle of the edge.
31091  newpoint = (point) points->alloc();
31092  // Interpolate its attributes.
31093  for (j = 0; j < 3 + in->numberofpointattributes; j++) {
31094  newpoint[j] = 0.5 * (torg[j] + tdest[j]);
31095  }
31096  ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1);
31097  setpointmark(newpoint, ptmark);
31098  // Add this node to its extra node list.
31099  extralist[i] = newpoint;
31100  // Set 'newpoint' into extra node lists of other tetrahedra
31101  // sharing this edge.
31102  tapex = apex(worktet);
31103  spintet = worktet;
31104  hitbdry = 0;
31105  while (hitbdry < 2) {
31106  if (fnextself(spintet)) {
31107  // Get the extra node list of 'spintet'.
31108  adjextralist = (point *) spintet.tet[highorderindex];
31109  // Find the index of its extra node list.
31110  j = locver2edge[spintet.loc][spintet.ver];
31111  // Only set 'newpoint' into 'adjextralist' if it is a NULL.
31112  // Because two faces can belong to the same tetrahedron.
31113  if (adjextralist[j] == (point) NULL) {
31114  adjextralist[j] = newpoint;
31115  }
31116  if (apex(spintet) == tapex) {
31117  break;
31118  }
31119  } else {
31120  hitbdry++;
31121  if (hitbdry < 2) {
31122  esym(worktet, spintet);
31123  }
31124  }
31125  }
31126  }
31127  }
31128  tetloop.tet = tetrahedrontraverse();
31129  }
31130 }
31131 
31133 // //
31134 // outnodes() Output the points to a .node file or a tetgenio structure. //
31135 // //
31136 // Note: each point has already been numbered on input (the first index is //
31137 // 'in->firstnumber'). //
31138 // //
31140 
31141 void tetgenmesh::outnodes(tetgenio* out)
31142 {
31143  FILE *outfile;
31144  char outnodefilename[FILENAMESIZE];
31145  shellface subptr;
31146  triface adjtet;
31147  face subloop;
31148  point pointloop;
31149  point *extralist, ep[3];
31150  int nextras, bmark, shmark, marker;
31151  int coordindex, attribindex;
31152  int pointnumber, firstindex;
31153  int index, i;
31154 
31155  if (out == (tetgenio *) NULL) {
31156  strcpy(outnodefilename, b->outfilename);
31157  strcat(outnodefilename, ".node");
31158  }
31159 
31160  if (!b->quiet) {
31161  if (out == (tetgenio *) NULL) {
31162  printf("Writing %s.\n", outnodefilename);
31163  } else {
31164  printf("Writing nodes.\n");
31165  }
31166  }
31167 
31168  nextras = in->numberofpointattributes;
31169  bmark = !b->nobound && in->pointmarkerlist;
31170 
31171  // Avoid compile warnings.
31172  outfile = (FILE *) NULL;
31173  marker = coordindex = 0;
31174 
31175  if (out == (tetgenio *) NULL) {
31176  outfile = fopen(outnodefilename, "w");
31177  if (outfile == (FILE *) NULL) {
31178  printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
31179  terminatetetgen(1);
31180  }
31181  // Number of points, number of dimensions, number of point attributes,
31182  // and number of boundary markers (zero or one).
31183  fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
31184  } else {
31185  // Allocate space for 'pointlist';
31186  out->pointlist = new REAL[points->items * 3];
31187  if (out->pointlist == (REAL *) NULL) {
31188  printf("Error: Out of memory.\n");
31189  terminatetetgen(1);
31190  }
31191  // Allocate space for 'pointattributelist' if necessary;
31192  if (nextras > 0) {
31193  out->pointattributelist = new REAL[points->items * nextras];
31194  if (out->pointattributelist == (REAL *) NULL) {
31195  printf("Error: Out of memory.\n");
31196  terminatetetgen(1);
31197  }
31198  }
31199  // Allocate space for 'pointmarkerlist' if necessary;
31200  if (bmark) {
31201  out->pointmarkerlist = new int[points->items];
31202  if (out->pointmarkerlist == (int *) NULL) {
31203  printf("Error: Out of memory.\n");
31204  terminatetetgen(1);
31205  }
31206  }
31207  out->numberofpoints = points->items;
31208  out->numberofpointattributes = nextras;
31209  coordindex = 0;
31210  attribindex = 0;
31211  }
31212 
31213  if (bmark && (b->plc || b->refine)) {
31214  // Initialize the point2tet field of each point.
31215  points->traversalinit();
31216  pointloop = pointtraverse();
31217  while (pointloop != (point) NULL) {
31218  setpoint2tet(pointloop, (tetrahedron) NULL);
31219  pointloop = pointtraverse();
31220  }
31221  // Make a map point-to-subface. Hence a boundary point will get the
31222  // facet marker from that facet where it lies on.
31223  subfaces->traversalinit();
31224  subloop.sh = shellfacetraverse(subfaces);
31225  while (subloop.sh != (shellface *) NULL) {
31226  subloop.shver = 0;
31227  // Check all three points of the subface.
31228  for (i = 0; i < 3; i++) {
31229  pointloop = (point) subloop.sh[3 + i];
31230  setpoint2tet(pointloop, (tetrahedron) sencode(subloop));
31231  }
31232  if (b->order == 2) {
31233  // '-o2' switch. Set markers for quadratic nodes of this subface.
31234  stpivot(subloop, adjtet);
31235  if (adjtet.tet == dummytet) {
31236  sesymself(subloop);
31237  stpivot(subloop, adjtet);
31238  }
31239  assert(adjtet.tet != dummytet);
31240  extralist = (point *) adjtet.tet[highorderindex];
31241  switch (adjtet.loc) {
31242  case 0:
31243  ep[0] = extralist[0];
31244  ep[1] = extralist[1];
31245  ep[2] = extralist[2];
31246  break;
31247  case 1:
31248  ep[0] = extralist[0];
31249  ep[1] = extralist[4];
31250  ep[2] = extralist[3];
31251  break;
31252  case 2:
31253  ep[0] = extralist[1];
31254  ep[1] = extralist[5];
31255  ep[2] = extralist[4];
31256  break;
31257  case 3:
31258  ep[0] = extralist[2];
31259  ep[1] = extralist[3];
31260  ep[2] = extralist[5];
31261  break;
31262  default: break;
31263  }
31264  for (i = 0; i < 3; i++) {
31265  setpoint2tet(ep[i], (tetrahedron) sencode(subloop));
31266  }
31267  }
31268  subloop.sh = shellfacetraverse(subfaces);
31269  }
31270  }
31271 
31272  // Determine the first index (0 or 1).
31273  firstindex = b->zeroindex ? 0 : in->firstnumber;
31274 
31275  points->traversalinit();
31276  pointloop = pointtraverse();
31277  pointnumber = firstindex; // in->firstnumber;
31278  index = 0;
31279  while (pointloop != (point) NULL) {
31280  if (bmark) {
31281  // Default the vertex has a zero marker.
31282  marker = 0;
31283  // Is it an input vertex?
31284  if (index < in->numberofpoints) {
31285  // Input point's marker is directly copied to output.
31286  marker = in->pointmarkerlist[index];
31287  }
31288  // Is it a boundary vertex has marker zero?
31289  if ((marker == 0) && (b->plc || b->refine)) {
31290  subptr = (shellface) point2tet(pointloop);
31291  if (subptr != (shellface) NULL) {
31292  // Default a boundary vertex has marker 1.
31293  marker = 1;
31294  if (in->facetmarkerlist != (int *) NULL) {
31295  // The vertex gets the marker from the facet it lies on.
31296  sdecode(subptr, subloop);
31297  shmark = shellmark(subloop);
31298  marker = in->facetmarkerlist[shmark - 1];
31299  }
31300  }
31301  }
31302  }
31303  if (out == (tetgenio *) NULL) {
31304  // Point number, x, y and z coordinates.
31305  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
31306  pointloop[0], pointloop[1], pointloop[2]);
31307  for (i = 0; i < nextras; i++) {
31308  // Write an attribute.
31309  fprintf(outfile, " %.17g", pointloop[3 + i]);
31310  }
31311  if (bmark) {
31312  // Write the boundary marker.
31313  fprintf(outfile, " %d", marker);
31314  }
31315  fprintf(outfile, "\n");
31316  } else {
31317  // X, y, and z coordinates.
31318  out->pointlist[coordindex++] = pointloop[0];
31319  out->pointlist[coordindex++] = pointloop[1];
31320  out->pointlist[coordindex++] = pointloop[2];
31321  // Point attributes.
31322  for (i = 0; i < nextras; i++) {
31323  // Output an attribute.
31324  out->pointattributelist[attribindex++] = pointloop[3 + i];
31325  }
31326  if (bmark) {
31327  // Output the boundary marker.
31328  out->pointmarkerlist[index] = marker;
31329  }
31330  }
31331  pointloop = pointtraverse();
31332  pointnumber++;
31333  index++;
31334  }
31335 
31336  if (out == (tetgenio *) NULL) {
31337  fprintf(outfile, "# Generated by %s\n", b->commandline);
31338  fclose(outfile);
31339  }
31340 }
31341 
31343 // //
31344 // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
31345 // //
31347 
31348 void tetgenmesh::outmetrics(tetgenio* out)
31349 {
31350  FILE *outfile;
31351  char outmtrfilename[FILENAMESIZE];
31352  list *tetlist, *ptlist;
31353  triface tetloop;
31354  point ptloop, neipt;
31355  REAL lave, len; // lmin, lmax,
31356  int mtrindex;
31357  int i;
31358 
31359  lave = 0.0;
31360 
31361  if (out == (tetgenio *) NULL) {
31362  strcpy(outmtrfilename, b->outfilename);
31363  strcat(outmtrfilename, ".mtr");
31364  }
31365 
31366  if (!b->quiet) {
31367  if (out == (tetgenio *) NULL) {
31368  printf("Writing %s.\n", outmtrfilename);
31369  } else {
31370  printf("Writing metrics.\n");
31371  }
31372  }
31373 
31374  // Avoid compile warnings.
31375  outfile = (FILE *) NULL;
31376  mtrindex = 0;
31377 
31378  if (out == (tetgenio *) NULL) {
31379  outfile = fopen(outmtrfilename, "w");
31380  if (outfile == (FILE *) NULL) {
31381  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
31382  terminatetetgen(1);
31383  }
31384  // Number of points, number of point metrices,
31385  // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3);
31386  fprintf(outfile, "%ld %d\n", points->items, 1);
31387  } else {
31388  // Allocate space for 'pointmtrlist' if necessary;
31389  // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
31390  out->pointmtrlist = new REAL[points->items];
31391  if (out->pointmtrlist == (REAL *) NULL) {
31392  printf("Error: Out of memory.\n");
31393  terminatetetgen(1);
31394  }
31395  out->numberofpointmtrs = 1; // (sizeoftensor + 3);
31396  mtrindex = 0;
31397  }
31398 
31399  // Initialize the point2tet field of each point.
31400  points->traversalinit();
31401  ptloop = pointtraverse();
31402  while (ptloop != (point) NULL) {
31403  setpoint2tet(ptloop, (tetrahedron) NULL);
31404  ptloop = pointtraverse();
31405  }
31406  // Create the point-to-tet map.
31407  tetrahedrons->traversalinit();
31408  tetloop.tet = tetrahedrontraverse();
31409  while (tetloop.tet != (tetrahedron *) NULL) {
31410  for (i = 0; i < 4; i++) {
31411  ptloop = (point) tetloop.tet[4 + i];
31412  setpoint2tet(ptloop, encode(tetloop));
31413  }
31414  tetloop.tet = tetrahedrontraverse();
31415  }
31416 
31417  tetlist = new list(sizeof(triface), NULL, 256);
31418  ptlist = new list(sizeof(point *), NULL, 256);
31419 
31420  points->traversalinit();
31421  ptloop = pointtraverse();
31422  while (ptloop != (point) NULL) {
31423  decode(point2tet(ptloop), tetloop);
31424  if (!isdead(&tetloop)) {
31425  // Form the star of p.
31426  tetlist->append(&tetloop);
31427  formstarpolyhedron(ptloop, tetlist, ptlist, true);
31428  // lmin = longest;
31429  // lmax = 0.0;
31430  lave = 0.0;
31431  for (i = 0; i < ptlist->len(); i++) {
31432  neipt = * (point *)(* ptlist)[i];
31433  len = distance(ptloop, neipt);
31434  // lmin = lmin < len ? lmin : len;
31435  // lmax = lmax > len ? lmax : len;
31436  lave += len;
31437  }
31438  lave /= ptlist->len();
31439  }
31440  if (out == (tetgenio *) NULL) {
31441  // for (i = 0; i < sizeoftensor; i++) {
31442  // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
31443  // }
31444  if (ptlist->len() > 0) {
31445  // fprintf(outfile, "%-16.8e %-16.8e %-16.8e", lmin, lmax, lave);
31446  fprintf(outfile, "%-16.8e ", lave);
31447  } else {
31448  fprintf(outfile, "0.0 "); // fprintf(outfile, "0.0 0.0 0.0");
31449  }
31450  fprintf(outfile, "\n");
31451  } else {
31452  // for (i = 0; i < sizeoftensor; i++) {
31453  // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
31454  // }
31455  if (ptlist->len() > 0) {
31456  // out->pointmtrlist[mtrindex++] = lmin;
31457  // out->pointmtrlist[mtrindex++] = lmax;
31458  out->pointmtrlist[mtrindex++] = lave;
31459  } else {
31460  // out->pointmtrlist[mtrindex++] = 0.0;
31461  // out->pointmtrlist[mtrindex++] = 0.0;
31462  out->pointmtrlist[mtrindex++] = 0.0;
31463  }
31464  }
31465  tetlist->clear();
31466  ptlist->clear();
31467  ptloop = pointtraverse();
31468  }
31469 
31470  delete tetlist;
31471  delete ptlist;
31472 
31473  if (out == (tetgenio *) NULL) {
31474  fprintf(outfile, "# Generated by %s\n", b->commandline);
31475  fclose(outfile);
31476  }
31477 }
31478 
31480 // //
31481 // outelements() Output the tetrahedra to an .ele file or a tetgenio //
31482 // structure. //
31483 // //
31485 
31486 void tetgenmesh::outelements(tetgenio* out)
31487 {
31488  FILE *outfile;
31489  char outelefilename[FILENAMESIZE];
31490  tetrahedron* tptr;
31491  int *tlist;
31492  REAL *talist;
31493  int firstindex, shift;
31494  int pointindex;
31495  int attribindex;
31496  point p1, p2, p3, p4;
31497  point *extralist;
31498  int elementnumber;
31499  int eextras;
31500  int i;
31501 
31502  if (out == (tetgenio *) NULL) {
31503  strcpy(outelefilename, b->outfilename);
31504  strcat(outelefilename, ".ele");
31505  }
31506 
31507  if (!b->quiet) {
31508  if (out == (tetgenio *) NULL) {
31509  printf("Writing %s.\n", outelefilename);
31510  } else {
31511  printf("Writing elements.\n");
31512  }
31513  }
31514 
31515  // Avoid compile warnings.
31516  outfile = (FILE *) NULL;
31517  tlist = (int *) NULL;
31518  talist = (double *) NULL;
31519  pointindex = attribindex = 0;
31520 
31521  eextras = in->numberoftetrahedronattributes;
31522  if (out == (tetgenio *) NULL) {
31523  outfile = fopen(outelefilename, "w");
31524  if (outfile == (FILE *) NULL) {
31525  printf("File I/O Error: Cannot create file %s.\n", outelefilename);
31526  terminatetetgen(1);
31527  }
31528  // Number of tetras, points per tetra, attributes per tetra.
31529  fprintf(outfile, "%ld %d %d\n", tetrahedrons->items,
31530  b->order == 1 ? 4 : 10, eextras);
31531  } else {
31532  // Allocate memory for output tetrahedra.
31533  out->tetrahedronlist = new int[tetrahedrons->items *
31534  (b->order == 1 ? 4 : 10)];
31535  if (out->tetrahedronlist == (int *) NULL) {
31536  printf("Error: Out of memory.\n");
31537  terminatetetgen(1);
31538  }
31539  // Allocate memory for output tetrahedron attributes if necessary.
31540  if (eextras > 0) {
31541  out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras];
31542  if (out->tetrahedronattributelist == (REAL *) NULL) {
31543  printf("Error: Out of memory.\n");
31544  terminatetetgen(1);
31545  }
31546  }
31547  out->numberoftetrahedra = tetrahedrons->items;
31548  out->numberofcorners = b->order == 1 ? 4 : 10;
31549  out->numberoftetrahedronattributes = eextras;
31550  tlist = out->tetrahedronlist;
31551  talist = out->tetrahedronattributelist;
31552  pointindex = 0;
31553  attribindex = 0;
31554  }
31555 
31556  // Determine the first index (0 or 1).
31557  firstindex = b->zeroindex ? 0 : in->firstnumber;
31558  shift = 0; // Default no shiftment.
31559  if ((in->firstnumber == 1) && (firstindex == 0)) {
31560  shift = 1; // Shift the output indices by 1.
31561  }
31562 
31563  tetrahedrons->traversalinit();
31564  tptr = tetrahedrontraverse();
31565  elementnumber = firstindex; // in->firstnumber;
31566  while (tptr != (tetrahedron *) NULL) {
31567  p1 = (point) tptr[4];
31568  p2 = (point) tptr[5];
31569  p3 = (point) tptr[6];
31570  p4 = (point) tptr[7];
31571  if (out == (tetgenio *) NULL) {
31572  // Tetrahedron number, indices for four points.
31573  fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
31574  pointmark(p1) - shift, pointmark(p2) - shift,
31575  pointmark(p3) - shift, pointmark(p4) - shift);
31576  if (b->order == 2) {
31577  extralist = (point *) tptr[highorderindex];
31578  // Tetrahedron number, indices for four points plus six extra points.
31579  fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
31580  pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
31581  pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
31582  pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
31583  }
31584  for (i = 0; i < eextras; i++) {
31585  fprintf(outfile, " %.17g", elemattribute(tptr, i));
31586  }
31587  fprintf(outfile, "\n");
31588  } else {
31589  tlist[pointindex++] = pointmark(p1) - shift;
31590  tlist[pointindex++] = pointmark(p2) - shift;
31591  tlist[pointindex++] = pointmark(p3) - shift;
31592  tlist[pointindex++] = pointmark(p4) - shift;
31593  if (b->order == 2) {
31594  extralist = (point *) tptr[highorderindex];
31595  tlist[pointindex++] = pointmark(extralist[0]) - shift;
31596  tlist[pointindex++] = pointmark(extralist[1]) - shift;
31597  tlist[pointindex++] = pointmark(extralist[2]) - shift;
31598  tlist[pointindex++] = pointmark(extralist[3]) - shift;
31599  tlist[pointindex++] = pointmark(extralist[4]) - shift;
31600  tlist[pointindex++] = pointmark(extralist[5]) - shift;
31601  }
31602  for (i = 0; i < eextras; i++) {
31603  talist[attribindex++] = elemattribute(tptr, i);
31604  }
31605  }
31606  if (b->neighout) {
31607  // Remember the index of this element.
31608  * (int *) (tptr + elemmarkerindex) = elementnumber;
31609  }
31610  tptr = tetrahedrontraverse();
31611  elementnumber++;
31612  }
31613  if (b->neighout) {
31614  // Set the outside element marker.
31615  * (int *) (dummytet + elemmarkerindex) = -1;
31616  }
31617 
31618  if (out == (tetgenio *) NULL) {
31619  fprintf(outfile, "# Generated by %s\n", b->commandline);
31620  fclose(outfile);
31621  }
31622 }
31623 
31625 // //
31626 // outfaces() Output all faces to a .face file or a tetgenio structure. //
31627 // //
31628 // This routines outputs all triangular faces (including outer boundary //
31629 // faces and inner faces) of this mesh. //
31630 // //
31632 
31633 void tetgenmesh::outfaces(tetgenio* out)
31634 {
31635  FILE *outfile;
31636  char facefilename[FILENAMESIZE];
31637  int *elist;
31638  int *emlist;
31639  int neigh1, neigh2;
31640  int index;
31641  triface tface, tsymface;
31642  face checkmark;
31643  point torg, tdest, tapex;
31644  long faces;
31645  int bmark, faceid, marker;
31646  int firstindex, shift;
31647  int facenumber;
31648 
31649  neigh1 = 0;
31650  neigh2 = 0;
31651 
31652  if (out == (tetgenio *) NULL) {
31653  strcpy(facefilename, b->outfilename);
31654  strcat(facefilename, ".face");
31655  }
31656 
31657  if (!b->quiet) {
31658  if (out == (tetgenio *) NULL) {
31659  printf("Writing %s.\n", facefilename);
31660  } else {
31661  printf("Writing faces.\n");
31662  }
31663  }
31664 
31665  // Avoid compile warnings.
31666  outfile = (FILE *) NULL;
31667  elist = (int *) NULL;
31668  emlist = (int *) NULL;
31669  index = marker = 0;
31670 
31671  faces = (4l * tetrahedrons->items + hullsize) / 2l;
31672  bmark = !b->nobound && in->facetmarkerlist;
31673 
31674  if (out == (tetgenio *) NULL) {
31675  outfile = fopen(facefilename, "w");
31676  if (outfile == (FILE *) NULL) {
31677  printf("File I/O Error: Cannot create file %s.\n", facefilename);
31678  terminatetetgen(1);
31679  }
31680  fprintf(outfile, "%ld %d\n", faces, bmark);
31681  } else {
31682  // Allocate memory for 'trifacelist'.
31683  out->trifacelist = new int[faces * 3];
31684  if (out->trifacelist == (int *) NULL) {
31685  printf("Error: Out of memory.\n");
31686  terminatetetgen(1);
31687  }
31688  // Allocate memory for 'trifacemarkerlist' if necessary.
31689  if (bmark) {
31690  out->trifacemarkerlist = new int[faces];
31691  if (out->trifacemarkerlist == (int *) NULL) {
31692  printf("Error: Out of memory.\n");
31693  terminatetetgen(1);
31694  }
31695  }
31696  if (b->neighout > 1) {
31697  // '-nn' switch.
31698  out->adjtetlist = new int[subfaces->items * 2];
31699  if (out->adjtetlist == (int *) NULL) {
31700  printf("Error: Out of memory.\n");
31701  terminatetetgen(1);
31702  }
31703  }
31704  out->numberoftrifaces = faces;
31705  elist = out->trifacelist;
31706  emlist = out->trifacemarkerlist;
31707  index = 0;
31708  }
31709 
31710  // Determine the first index (0 or 1).
31711  firstindex = b->zeroindex ? 0 : in->firstnumber;
31712  shift = 0; // Default no shiftment.
31713  if ((in->firstnumber == 1) && (firstindex == 0)) {
31714  shift = 1; // Shift the output indices by 1.
31715  }
31716 
31717  tetrahedrons->traversalinit();
31718  tface.tet = tetrahedrontraverse();
31719  facenumber = firstindex; // in->firstnumber;
31720  // To loop over the set of faces, loop over all tetrahedra, and look at
31721  // the four faces of each one. If there isn't another tetrahedron
31722  // adjacent to this face, operate on the face. If there is another
31723  // adjacent tetrahedron, operate on the face only if the current
31724  // tetrahedron has a smaller pointer than its neighbor. This way, each
31725  // face is considered only once.
31726  while (tface.tet != (tetrahedron *) NULL) {
31727  for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
31728  sym(tface, tsymface);
31729  if ((tsymface.tet == dummytet) || (tface.tet < tsymface.tet)) {
31730  torg = org(tface);
31731  tdest = dest(tface);
31732  tapex = apex(tface);
31733  if (bmark) {
31734  // Get the boundary marker of this face. If it is an inner face,
31735  // it has no boundary marker, set it be zero.
31736  if (b->useshelles) {
31737  // Shell face is used.
31738  tspivot(tface, checkmark);
31739  if (checkmark.sh == dummysh) {
31740  marker = 0; // It is an inner face.
31741  } else {
31742  faceid = shellmark(checkmark) - 1;
31743  marker = in->facetmarkerlist[faceid];
31744  }
31745  } else {
31746  // Shell face is not used, only distinguish outer and inner face.
31747  marker = tsymface.tet != dummytet ? 1 : 0;
31748  }
31749  }
31750  if (b->neighout > 1) {
31751  // '-nn' switch. Output adjacent tets indices.
31752  neigh1 = * (int *)(tface.tet + elemmarkerindex);
31753  if (tsymface.tet != dummytet) {
31754  neigh2 = * (int *)(tsymface.tet + elemmarkerindex);
31755  } else {
31756  neigh2 = -1;
31757  }
31758  }
31759  if (out == (tetgenio *) NULL) {
31760  // Face number, indices of three vertices.
31761  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
31762  pointmark(torg) - shift, pointmark(tdest) - shift,
31763  pointmark(tapex) - shift);
31764  if (bmark) {
31765  // Output a boundary marker.
31766  fprintf(outfile, " %d", marker);
31767  }
31768  if (b->neighout > 1) {
31769  fprintf(outfile, " %5d %5d", neigh1, neigh2);
31770  }
31771  fprintf(outfile, "\n");
31772  } else {
31773  // Output indices of three vertices.
31774  elist[index++] = pointmark(torg) - shift;
31775  elist[index++] = pointmark(tdest) - shift;
31776  elist[index++] = pointmark(tapex) - shift;
31777  if (bmark) {
31778  emlist[facenumber - in->firstnumber] = marker;
31779  }
31780  if (b->neighout > 1) {
31781  out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
31782  out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
31783  }
31784  }
31785  facenumber++;
31786  }
31787  }
31788  tface.tet = tetrahedrontraverse();
31789  }
31790 
31791  if (out == (tetgenio *) NULL) {
31792  fprintf(outfile, "# Generated by %s\n", b->commandline);
31793  fclose(outfile);
31794  }
31795 }
31796 
31798 // //
31799 // outhullfaces() Output outer boundary faces to a .face file or a //
31800 // tetgenio structure. //
31801 // //
31802 // The normal of each face is arranged to point inside of the domain (use //
31803 // right-hand rule). This routines will outputs convex hull faces if the //
31804 // mesh is a Delaunay tetrahedralization. //
31805 // //
31807 
31808 void tetgenmesh::outhullfaces(tetgenio* out)
31809 {
31810  FILE *outfile;
31811  char facefilename[FILENAMESIZE];
31812  int *elist;
31813  int index;
31814  triface tface, tsymface;
31815  face checkmark;
31816  point torg, tdest, tapex;
31817  int firstindex, shift;
31818  int facenumber;
31819 
31820  if (out == (tetgenio *) NULL) {
31821  strcpy(facefilename, b->outfilename);
31822  strcat(facefilename, ".face");
31823  }
31824 
31825  if (!b->quiet) {
31826  if (out == (tetgenio *) NULL) {
31827  printf("Writing %s.\n", facefilename);
31828  } else {
31829  printf("Writing faces.\n");
31830  }
31831  }
31832 
31833  // Avoid compile warnings.
31834  outfile = (FILE *) NULL;
31835  elist = (int *) NULL;
31836  index = 0;
31837 
31838  if (out == (tetgenio *) NULL) {
31839  outfile = fopen(facefilename, "w");
31840  if (outfile == (FILE *) NULL) {
31841  printf("File I/O Error: Cannot create file %s.\n", facefilename);
31842  terminatetetgen(1);
31843  }
31844  fprintf(outfile, "%ld 0\n", hullsize);
31845  } else {
31846  // Allocate memory for 'trifacelist'.
31847  out->trifacelist = new int[hullsize * 3];
31848  if (out->trifacelist == (int *) NULL) {
31849  printf("Error: Out of memory.\n");
31850  terminatetetgen(1);
31851  }
31852  out->numberoftrifaces = hullsize;
31853  elist = out->trifacelist;
31854  index = 0;
31855  }
31856 
31857  // Determine the first index (0 or 1).
31858  firstindex = b->zeroindex ? 0 : in->firstnumber;
31859  shift = 0; // Default no shiftment.
31860  if ((in->firstnumber == 1) && (firstindex == 0)) {
31861  shift = 1; // Shift the output indices by 1.
31862  }
31863 
31864  tetrahedrons->traversalinit();
31865  tface.tet = tetrahedrontraverse();
31866  facenumber = firstindex; // in->firstnumber;
31867  // To loop over the set of hull faces, loop over all tetrahedra, and look
31868  // at the four faces of each one. If there isn't another tetrahedron
31869  // adjacent to this face, operate on the face.
31870  while (tface.tet != (tetrahedron *) NULL) {
31871  for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
31872  sym(tface, tsymface);
31873  if (tsymface.tet == dummytet) {
31874  torg = org(tface);
31875  tdest = dest(tface);
31876  tapex = apex(tface);
31877  if (out == (tetgenio *) NULL) {
31878  // Face number, indices of three vertices.
31879  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
31880  pointmark(torg) - shift, pointmark(tdest) - shift,
31881  pointmark(tapex) - shift);
31882  fprintf(outfile, "\n");
31883  } else {
31884  // Output indices of three vertices.
31885  elist[index++] = pointmark(torg) - shift;
31886  elist[index++] = pointmark(tdest) - shift;
31887  elist[index++] = pointmark(tapex) - shift;
31888  }
31889  facenumber++;
31890  }
31891  }
31892  tface.tet = tetrahedrontraverse();
31893  }
31894 
31895  if (out == (tetgenio *) NULL) {
31896  fprintf(outfile, "# Generated by %s\n", b->commandline);
31897  fclose(outfile);
31898  }
31899 }
31900 
31902 // //
31903 // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
31904 // a tetgenio structure. //
31905 // //
31906 // The boundary faces are exist in 'subfaces'. For listing triangle vertices //
31907 // in the same sense for all triangles in the mesh, the direction determined //
31908 // by right-hand rule is pointer to the inside of the volume. //
31909 // //
31911 
31912 void tetgenmesh::outsubfaces(tetgenio* out)
31913 {
31914  FILE *outfile;
31915  char facefilename[FILENAMESIZE];
31916  int *elist;
31917  int *emlist;
31918  int index, index1, index2;
31919  triface abuttingtet;
31920  face faceloop;
31921  point torg, tdest, tapex;
31922  int bmark, faceid, marker;
31923  int firstindex, shift;
31924  int neigh1, neigh2;
31925  int facenumber;
31926 
31927  if (out == (tetgenio *) NULL) {
31928  strcpy(facefilename, b->outfilename);
31929  strcat(facefilename, ".face");
31930  }
31931 
31932  if (!b->quiet) {
31933  if (out == (tetgenio *) NULL) {
31934  printf("Writing %s.\n", facefilename);
31935  } else {
31936  printf("Writing faces.\n");
31937  }
31938  }
31939 
31940  // Avoid compile warnings.
31941  outfile = (FILE *) NULL;
31942  elist = (int *) NULL;
31943  emlist = (int *) NULL;
31944  index = index1 = index2 = 0;
31945  faceid = marker = 0;
31946  neigh1 = neigh2 = 0;
31947 
31948  bmark = !b->nobound && in->facetmarkerlist;
31949 
31950  if (out == (tetgenio *) NULL) {
31951  outfile = fopen(facefilename, "w");
31952  if (outfile == (FILE *) NULL) {
31953  printf("File I/O Error: Cannot create file %s.\n", facefilename);
31954  terminatetetgen(1);
31955  }
31956  // Number of subfaces.
31957  fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
31958  } else {
31959  // Allocate memory for 'trifacelist'.
31960  out->trifacelist = new int[subfaces->items * 3];
31961  if (out->trifacelist == (int *) NULL) {
31962  printf("Error: Out of memory.\n");
31963  terminatetetgen(1);
31964  }
31965  if (bmark) {
31966  // Allocate memory for 'trifacemarkerlist'.
31967  out->trifacemarkerlist = new int[subfaces->items];
31968  if (out->trifacemarkerlist == (int *) NULL) {
31969  printf("Error: Out of memory.\n");
31970  terminatetetgen(1);
31971  }
31972  }
31973  if (b->neighout > 1) {
31974  // '-nn' switch.
31975  out->adjtetlist = new int[subfaces->items * 2];
31976  if (out->adjtetlist == (int *) NULL) {
31977  printf("Error: Out of memory.\n");
31978  terminatetetgen(1);
31979  }
31980  }
31981  out->numberoftrifaces = subfaces->items;
31982  elist = out->trifacelist;
31983  emlist = out->trifacemarkerlist;
31984  }
31985 
31986  // Determine the first index (0 or 1).
31987  firstindex = b->zeroindex ? 0 : in->firstnumber;
31988  shift = 0; // Default no shiftment.
31989  if ((in->firstnumber == 1) && (firstindex == 0)) {
31990  shift = 1; // Shift the output indices by 1.
31991  }
31992 
31993  subfaces->traversalinit();
31994  faceloop.sh = shellfacetraverse(subfaces);
31995  facenumber = firstindex; // in->firstnumber;
31996  while (faceloop.sh != (shellface *) NULL) {
31997  stpivot(faceloop, abuttingtet);
31998  if (abuttingtet.tet == dummytet) {
31999  sesymself(faceloop);
32000  stpivot(faceloop, abuttingtet);
32001  }
32002  if (abuttingtet.tet != dummytet) {
32003  // If there is a tetrahedron containing this subface, orient it so
32004  // that the normal of this face points to inside of the volume by
32005  // right-hand rule.
32006  adjustedgering(abuttingtet, CCW);
32007  torg = org(abuttingtet);
32008  tdest = dest(abuttingtet);
32009  tapex = apex(abuttingtet);
32010  } else {
32011  // This may happen when only a surface mesh be generated.
32012  torg = sorg(faceloop);
32013  tdest = sdest(faceloop);
32014  tapex = sapex(faceloop);
32015  }
32016  if (bmark) {
32017  faceid = shellmark(faceloop) - 1;
32018  marker = in->facetmarkerlist[faceid];
32019  }
32020  if (b->neighout > 1) {
32021  // '-nn' switch. Output adjacent tets indices.
32022  neigh1 = -1;
32023  stpivot(faceloop, abuttingtet);
32024  if (abuttingtet.tet != dummytet) {
32025  neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex);
32026  }
32027  neigh2 = -1;
32028  sesymself(faceloop);
32029  stpivot(faceloop, abuttingtet);
32030  if (abuttingtet.tet != dummytet) {
32031  neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex);
32032  }
32033  }
32034  if (out == (tetgenio *) NULL) {
32035  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
32036  pointmark(torg) - shift, pointmark(tdest) - shift,
32037  pointmark(tapex) - shift);
32038  if (bmark) {
32039  fprintf(outfile, " %d", marker);
32040  }
32041  if (b->neighout > 1) {
32042  fprintf(outfile, " %5d %5d", neigh1, neigh2);
32043  }
32044  fprintf(outfile, "\n");
32045  } else {
32046  // Output three vertices of this face;
32047  elist[index++] = pointmark(torg) - shift;
32048  elist[index++] = pointmark(tdest) - shift;
32049  elist[index++] = pointmark(tapex) - shift;
32050  if (bmark) {
32051  emlist[index1++] = marker;
32052  }
32053  if (b->neighout > 1) {
32054  out->adjtetlist[index2++] = neigh1;
32055  out->adjtetlist[index2++] = neigh2;
32056  }
32057  }
32058  facenumber++;
32059  faceloop.sh = shellfacetraverse(subfaces);
32060  }
32061 
32062  if (out == (tetgenio *) NULL) {
32063  fprintf(outfile, "# Generated by %s\n", b->commandline);
32064  fclose(outfile);
32065  }
32066 }
32067 
32069 // //
32070 // outedges() Output all edges to a .edge file or a structure. //
32071 // //
32073 
32074 void tetgenmesh::outedges(tetgenio* out)
32075 {
32076  FILE *outfile;
32077  char edgefilename[FILENAMESIZE];
32078  int *elist, *emlist;
32079  int index, index1;
32080  triface tetloop, worktet, spintet;
32081  face checksh;
32082  point torg, tdest;
32083  long faces, edges;
32084  int firstindex, shift;
32085  int edgenumber, faceid, marker;
32086  int hitbdry, i;
32087 
32088  if (out == (tetgenio *) NULL) {
32089  strcpy(edgefilename, b->outfilename);
32090  strcat(edgefilename, ".edge");
32091  }
32092 
32093  if (!b->quiet) {
32094  if (out == (tetgenio *) NULL) {
32095  printf("Writing %s.\n", edgefilename);
32096  } else {
32097  printf("Writing edges.\n");
32098  }
32099  }
32100 
32101  // Avoid compile warnings.
32102  outfile = (FILE *) NULL;
32103  elist = (int *) NULL;
32104  emlist = (int *) NULL;
32105  index = index1 = 0;
32106  faceid = marker = 0;
32107 
32108  // Using the Euler formula (V-E+F-T=1) to get the total number of edges.
32109  faces = (4l * tetrahedrons->items + hullsize) / 2l;
32110  edges = points->items + faces - tetrahedrons->items - 1l;
32111 
32112  if (out == (tetgenio *) NULL) {
32113  outfile = fopen(edgefilename, "w");
32114  if (outfile == (FILE *) NULL) {
32115  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
32116  terminatetetgen(1);
32117  }
32118  // Write the number of edges, boundary markers (0 or 1).
32119  fprintf(outfile, "%ld %d\n", edges, !b->nobound);
32120  } else {
32121  // Allocate memory for 'edgelist'.
32122  out->edgelist = new int[edges * 2];
32123  if (out->edgelist == (int *) NULL) {
32124  printf("Error: Out of memory.\n");
32125  terminatetetgen(1);
32126  }
32127  if (!b->nobound) {
32128  out->edgemarkerlist = new int[edges];
32129  }
32130  out->numberofedges = edges;
32131  elist = out->edgelist;
32132  emlist = out->edgemarkerlist;
32133  }
32134 
32135  // Determine the first index (0 or 1).
32136  firstindex = b->zeroindex ? 0 : in->firstnumber;
32137  shift = 0; // Default no shiftment.
32138  if ((in->firstnumber == 1) && (firstindex == 0)) {
32139  shift = 1; // Shift (reduce) the output indices by 1.
32140  }
32141 
32142  tetrahedrons->traversalinit();
32143  tetloop.tet = tetrahedrontraverse();
32144  edgenumber = firstindex; // in->firstnumber;
32145  while (tetloop.tet != (tetrahedron *) NULL) {
32146  // Count the number of Voronoi faces. Look at the six edges of each
32147  // tetrahedron. Count the edge only if the tetrahedron's pointer is
32148  // smaller than those of all other tetrahedra that share the edge.
32149  worktet.tet = tetloop.tet;
32150  for (i = 0; i < 6; i++) {
32151  worktet.loc = edge2locver[i][0];
32152  worktet.ver = edge2locver[i][1];
32153  adjustedgering(worktet, CW);
32154  spintet = worktet;
32155  hitbdry = 0;
32156  while (hitbdry < 2) {
32157  if (fnextself(spintet)) {
32158  if (apex(spintet) == apex(worktet)) break;
32159  if (spintet.tet < worktet.tet) break;
32160  } else {
32161  hitbdry++;
32162  if (hitbdry < 2) {
32163  esym(worktet, spintet);
32164  fnextself(spintet); // In the same tet.
32165  }
32166  }
32167  }
32168  // Count this edge if no adjacent tets are smaller than this tet.
32169  if (spintet.tet >= worktet.tet) {
32170  torg = org(worktet);
32171  tdest = dest(worktet);
32172  if (out == (tetgenio *) NULL) {
32173  fprintf(outfile, "%5d %4d %4d", edgenumber,
32174  pointmark(torg) - shift, pointmark(tdest) - shift);
32175  } else {
32176  // Output three vertices of this face;
32177  elist[index++] = pointmark(torg) - shift;
32178  elist[index++] = pointmark(tdest) - shift;
32179  }
32180  if (!b->nobound) {
32181  if (hitbdry > 0) {
32182  // It is a boundary edge. Get the boundary marker of the facet
32183  // containing this edge. Note there may have more than one
32184  // facet, choose one arbitrarily.
32185  if ((b->plc || b->refine) && in->facetmarkerlist) {
32186  tspivot(spintet, checksh);
32187  faceid = shellmark(checksh) - 1;
32188  marker = in->facetmarkerlist[faceid];
32189  } else {
32190  marker = 1; // Indicate it's a boundary edge.
32191  }
32192  } else {
32193  marker = 0;
32194  }
32195  if (out == (tetgenio *) NULL) {
32196  fprintf(outfile, " %d", marker);
32197  } else {
32198  emlist[index1++] = marker;
32199  }
32200  }
32201  if (out == (tetgenio *) NULL) {
32202  fprintf(outfile, "\n");
32203  }
32204  edgenumber++;
32205  }
32206  }
32207  tetloop.tet = tetrahedrontraverse();
32208  }
32209 
32210  if (out == (tetgenio *) NULL) {
32211  fprintf(outfile, "# Generated by %s\n", b->commandline);
32212  fclose(outfile);
32213  }
32214 }
32215 
32217 // //
32218 // outsubsegments() Output segments to a .edge file or a structure. //
32219 // //
32221 
32222 void tetgenmesh::outsubsegments(tetgenio* out)
32223 {
32224  FILE *outfile;
32225  char edgefilename[FILENAMESIZE];
32226  int *elist;
32227  int index;
32228  face edgeloop;
32229  point torg, tdest;
32230  int firstindex, shift;
32231  int edgenumber;
32232 
32233  if (out == (tetgenio *) NULL) {
32234  strcpy(edgefilename, b->outfilename);
32235  strcat(edgefilename, ".edge");
32236  }
32237 
32238  if (!b->quiet) {
32239  if (out == (tetgenio *) NULL) {
32240  printf("Writing %s.\n", edgefilename);
32241  } else {
32242  printf("Writing edges.\n");
32243  }
32244  }
32245 
32246  // Avoid compile warnings.
32247  outfile = (FILE *) NULL;
32248  elist = (int *) NULL;
32249  index = 0;
32250 
32251  if (out == (tetgenio *) NULL) {
32252  outfile = fopen(edgefilename, "w");
32253  if (outfile == (FILE *) NULL) {
32254  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
32255  terminatetetgen(1);
32256  }
32257  // Number of subsegments.
32258  fprintf(outfile, "%ld\n", subsegs->items);
32259  } else {
32260  // Allocate memory for 'edgelist'.
32261  out->edgelist = new int[subsegs->items * 2];
32262  if (out->edgelist == (int *) NULL) {
32263  printf("Error: Out of memory.\n");
32264  terminatetetgen(1);
32265  }
32266  out->numberofedges = subsegs->items;
32267  elist = out->edgelist;
32268  }
32269 
32270  // Determine the first index (0 or 1).
32271  firstindex = b->zeroindex ? 0 : in->firstnumber;
32272  shift = 0; // Default no shiftment.
32273  if ((in->firstnumber == 1) && (firstindex == 0)) {
32274  shift = 1; // Shift the output indices by 1.
32275  }
32276 
32277  subsegs->traversalinit();
32278  edgeloop.sh = shellfacetraverse(subsegs);
32279  edgenumber = firstindex; // in->firstnumber;
32280  while (edgeloop.sh != (shellface *) NULL) {
32281  torg = sorg(edgeloop);
32282  tdest = sdest(edgeloop);
32283  if (out == (tetgenio *) NULL) {
32284  fprintf(outfile, "%5d %4d %4d\n", edgenumber,
32285  pointmark(torg) - shift, pointmark(tdest) - shift);
32286  } else {
32287  // Output three vertices of this face;
32288  elist[index++] = pointmark(torg) - shift;
32289  elist[index++] = pointmark(tdest) - shift;
32290  }
32291  edgenumber++;
32292  edgeloop.sh = shellfacetraverse(subsegs);
32293  }
32294 
32295  if (out == (tetgenio *) NULL) {
32296  fprintf(outfile, "# Generated by %s\n", b->commandline);
32297  fclose(outfile);
32298  }
32299 }
32300 
32302 // //
32303 // outneighbors() Output tet neighbors to a .neigh file or a structure. //
32304 // //
32306 
32307 void tetgenmesh::outneighbors(tetgenio* out)
32308 {
32309  FILE *outfile;
32310  char neighborfilename[FILENAMESIZE];
32311  int *nlist;
32312  int index;
32313  triface tetloop, tetsym;
32314  int neighbor1, neighbor2, neighbor3, neighbor4;
32315  int firstindex;
32316  int elementnumber;
32317 
32318  if (out == (tetgenio *) NULL) {
32319  strcpy(neighborfilename, b->outfilename);
32320  strcat(neighborfilename, ".neigh");
32321  }
32322 
32323  if (!b->quiet) {
32324  if (out == (tetgenio *) NULL) {
32325  printf("Writing %s.\n", neighborfilename);
32326  } else {
32327  printf("Writing neighbors.\n");
32328  }
32329  }
32330 
32331  // Avoid compile warnings.
32332  outfile = (FILE *) NULL;
32333  nlist = (int *) NULL;
32334  index = 0;
32335 
32336  if (out == (tetgenio *) NULL) {
32337  outfile = fopen(neighborfilename, "w");
32338  if (outfile == (FILE *) NULL) {
32339  printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
32340  terminatetetgen(1);
32341  }
32342  // Number of tetrahedra, four faces per tetrahedron.
32343  fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4);
32344  } else {
32345  // Allocate memory for 'neighborlist'.
32346  out->neighborlist = new int[tetrahedrons->items * 4];
32347  if (out->neighborlist == (int *) NULL) {
32348  printf("Error: Out of memory.\n");
32349  terminatetetgen(1);
32350  }
32351  nlist = out->neighborlist;
32352  }
32353 
32354  // Determine the first index (0 or 1).
32355  firstindex = b->zeroindex ? 0 : in->firstnumber;
32356 
32357  tetrahedrons->traversalinit();
32358  tetloop.tet = tetrahedrontraverse();
32359  elementnumber = firstindex; // in->firstnumber;
32360  while (tetloop.tet != (tetrahedron *) NULL) {
32361  tetloop.loc = 2;
32362  sym(tetloop, tetsym);
32363  neighbor1 = * (int *) (tetsym.tet + elemmarkerindex);
32364  tetloop.loc = 3;
32365  sym(tetloop, tetsym);
32366  neighbor2 = * (int *) (tetsym.tet + elemmarkerindex);
32367  tetloop.loc = 1;
32368  sym(tetloop, tetsym);
32369  neighbor3 = * (int *) (tetsym.tet + elemmarkerindex);
32370  tetloop.loc = 0;
32371  sym(tetloop, tetsym);
32372  neighbor4 = * (int *) (tetsym.tet + elemmarkerindex);
32373  if (out == (tetgenio *) NULL) {
32374  // Tetrahedra number, neighboring tetrahedron numbers.
32375  fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
32376  neighbor1, neighbor2, neighbor3, neighbor4);
32377  } else {
32378  nlist[index++] = neighbor1;
32379  nlist[index++] = neighbor2;
32380  nlist[index++] = neighbor3;
32381  nlist[index++] = neighbor4;
32382  }
32383  tetloop.tet = tetrahedrontraverse();
32384  elementnumber++;
32385  }
32386 
32387  if (out == (tetgenio *) NULL) {
32388  fprintf(outfile, "# Generated by %s\n", b->commandline);
32389  fclose(outfile);
32390  }
32391 }
32392 
32394 // //
32395 // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
32396 // and .v.cell. //
32397 // //
32398 // The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
32399 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
32400 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
32401 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
32402 // A Voronoi face is the convex hull of all Voronoi vertices around a common //
32403 // Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a //
32404 // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
32405 // onoi vertices around a common Delaunay vertex. It is a polytope for any //
32406 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
32407 // vertex belonging to the convex hull. //
32408 // //
32410 
32411 void tetgenmesh::outvoronoi(tetgenio* out)
32412 {
32413  FILE *outfile;
32414  char outfilename[FILENAMESIZE];
32415  tetgenio::voroedge *vedge;
32416  tetgenio::vorofacet *vfacet;
32417  list *tetlist, *ptlist;
32418  triface tetloop, worktet, spintet;
32419  point pt[4], ptloop, neipt;
32420  REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
32421  long faces, edges;
32422  int *tetfaceindexarray, *tetedgeindexarray;
32423  int arraysize, *vertarray;
32424  int vpointcount, vedgecount, vfacecount, tcount;
32425  int index, shift;
32426  int end1, end2;
32427  int hitbdry, i, j, k;
32428 
32429  vedge = NULL;
32430  vertarray = NULL;
32431  vfacet = NULL;
32432  k = 0;
32433 
32434  // Output Voronoi vertices to .v.node file.
32435  if (out == (tetgenio *) NULL) {
32436  strcpy(outfilename, b->outfilename);
32437  strcat(outfilename, ".v.node");
32438  }
32439 
32440  if (!b->quiet) {
32441  if (out == (tetgenio *) NULL) {
32442  printf("Writing %s.\n", outfilename);
32443  } else {
32444  printf("Writing Voronoi vertices.\n");
32445  }
32446  }
32447 
32448  // Determine the first index (0 or 1).
32449  shift = (b->zeroindex ? 0 : in->firstnumber);
32450  // The number of Delaunay faces (= the number of Voronoi edges).
32451  faces = (4l * tetrahedrons->items + hullsize) / 2l;
32452  // The number of Delaunay edges (= the number of Voronoi faces).
32453  edges = points->items + faces - tetrahedrons->items - 1;
32454  outfile = (FILE *) NULL; // Avoid compile warnings.
32455 
32456  if (out == (tetgenio *) NULL) {
32457  outfile = fopen(outfilename, "w");
32458  if (outfile == (FILE *) NULL) {
32459  printf("File I/O Error: Cannot create file %s.\n", outfilename);
32460  terminatetetgen(1);
32461  }
32462  // Number of voronoi points, 3 dim, no attributes, no marker.
32463  fprintf(outfile, "%ld 3 0 0\n", tetrahedrons->items);
32464  } else {
32465  // Allocate space for 'vpointlist'.
32466  out->numberofvpoints = (int) tetrahedrons->items;
32467  out->vpointlist = new REAL[out->numberofvpoints * 3];
32468  if (out->vpointlist == (REAL *) NULL) {
32469  printf("Error: Out of memory.\n");
32470  terminatetetgen(1);
32471  }
32472  }
32473 
32474  // Loop the tetrahedronlist once, do the following:
32475  // (1) Output Voronoi vertices (the circumcenter of the tetrahedron).
32476  // (2) Make a map from points-to-tetrahedra (for Voronoi cells).
32477  tetrahedrons->traversalinit();
32478  tetloop.tet = tetrahedrontraverse();
32479  vpointcount = 0;
32480  index = 0;
32481  while (tetloop.tet != (tetrahedron *) NULL) {
32482  // Calculate the circumcenter.
32483  for (i = 0; i < 4; i++) {
32484  pt[i] = (point) tetloop.tet[4 + i];
32485  setpoint2tet(pt[i], encode(tetloop));
32486  }
32487  circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
32488  if (out == (tetgenio *) NULL) {
32489  fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
32490  ccent[0], ccent[1], ccent[2]);
32491  } else {
32492  out->vpointlist[index++] = ccent[0];
32493  out->vpointlist[index++] = ccent[1];
32494  out->vpointlist[index++] = ccent[2];
32495  }
32496  // Remember the index of this element.
32497  * (int *) (tetloop.tet + elemmarkerindex) = vpointcount;
32498  vpointcount++;
32499  tetloop.tet = tetrahedrontraverse();
32500  }
32501  // Set the outside element marker.
32502  * (int *) (dummytet + elemmarkerindex) = -1;
32503 
32504  if (out == (tetgenio *) NULL) {
32505  fprintf(outfile, "# Generated by %s\n", b->commandline);
32506  fclose(outfile);
32507  }
32508 
32509  // Output Voronoi edges to .v.edge file.
32510  if (out == (tetgenio *) NULL) {
32511  strcpy(outfilename, b->outfilename);
32512  strcat(outfilename, ".v.edge");
32513  }
32514 
32515  if (!b->quiet) {
32516  if (out == (tetgenio *) NULL) {
32517  printf("Writing %s.\n", outfilename);
32518  } else {
32519  printf("Writing Voronoi edges.\n");
32520  }
32521  }
32522 
32523  if (out == (tetgenio *) NULL) {
32524  outfile = fopen(outfilename, "w");
32525  if (outfile == (FILE *) NULL) {
32526  printf("File I/O Error: Cannot create file %s.\n", outfilename);
32527  terminatetetgen(1);
32528  }
32529  // Number of Voronoi edges, no marker.
32530  fprintf(outfile, "%ld 0\n", faces);
32531  } else {
32532  // Allocate space for 'vpointlist'.
32533  out->numberofedges = (int) faces;
32534  out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
32535  }
32536 
32537  // Loop the tetrahedronlist once, output the Voronoi edges. The index of
32538  // each Voronoi edge corresponding to the index of the Delaunay face.
32539  // The four faces' indices of each tetrahedron are saved in the list
32540  // 'tetfaceindexarray', in the entry of i, where i (0-based) is the
32541  // index of this tetrahedron (= vpointcount).
32542  tetfaceindexarray = new int[tetrahedrons->items * 4];
32543  tetrahedrons->traversalinit();
32544  tetloop.tet = tetrahedrontraverse();
32545  vedgecount = 0;
32546  index = 0;
32547  while (tetloop.tet != (tetrahedron *) NULL) {
32548  // Count the number of Voronoi edges. Look at the four faces of each
32549  // tetrahedron. Count the face if the tetrahedron's pointer is
32550  // smaller than its neighbor's or the neighbor is outside.
32551  end1 = * (int *) (tetloop.tet + elemmarkerindex);
32552  for (i = 0; i < 4; i++) {
32553  decode(tetloop.tet[i], worktet);
32554  if ((worktet.tet == dummytet) || (tetloop.tet < worktet.tet)) {
32555  if (out == (tetgenio *) NULL) {
32556  fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
32557  } else {
32558  vedge = &(out->vedgelist[index++]);
32559  vedge->v1 = end1 + shift;
32560  }
32561  end2 = * (int *) (worktet.tet + elemmarkerindex);
32562  // Note that end2 may be -1 (worktet.tet is outside).
32563  if (end2 == -1) {
32564  // Calculate the out normal of this hull face.
32565  worktet.tet = tetloop.tet;
32566  worktet.loc = i;
32567  worktet.ver = 1; // The CW edge ring.
32568  pt[0] = org(worktet);
32569  pt[1] = dest(worktet);
32570  pt[2] = apex(worktet);
32571  for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
32572  for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
32573  cross(vec1, vec2, infvec);
32574  // Normalize it.
32575  L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
32576  + infvec[2] * infvec[2]);
32577  if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
32578  if (out == (tetgenio *) NULL) {
32579  fprintf(outfile, " -1");
32580  fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
32581  } else {
32582  vedge->v2 = -1;
32583  vedge->vnormal[0] = infvec[0];
32584  vedge->vnormal[1] = infvec[1];
32585  vedge->vnormal[2] = infvec[2];
32586  }
32587  } else {
32588  if (out == (tetgenio *) NULL) {
32589  fprintf(outfile, " %4d\n", end2 + shift);
32590  } else {
32591  vedge->v2 = end2 + shift;
32592  vedge->vnormal[0] = 0.0;
32593  vedge->vnormal[1] = 0.0;
32594  vedge->vnormal[2] = 0.0;
32595  }
32596  }
32597  // Save the face index in this tet and its neighbor if exists.
32598  tetfaceindexarray[end1 * 4 + i] = vedgecount;
32599  if (end2 != -1) {
32600  tetfaceindexarray[end2 * 4 + worktet.loc] = vedgecount;
32601  }
32602  vedgecount++;
32603  }
32604  }
32605  tetloop.tet = tetrahedrontraverse();
32606  }
32607 
32608  if (out == (tetgenio *) NULL) {
32609  fprintf(outfile, "# Generated by %s\n", b->commandline);
32610  fclose(outfile);
32611  }
32612 
32613  // Output Voronoi faces to .v.face file.
32614  if (out == (tetgenio *) NULL) {
32615  strcpy(outfilename, b->outfilename);
32616  strcat(outfilename, ".v.face");
32617  }
32618 
32619  if (!b->quiet) {
32620  if (out == (tetgenio *) NULL) {
32621  printf("Writing %s.\n", outfilename);
32622  } else {
32623  printf("Writing Voronoi faces.\n");
32624  }
32625  }
32626 
32627  if (out == (tetgenio *) NULL) {
32628  outfile = fopen(outfilename, "w");
32629  if (outfile == (FILE *) NULL) {
32630  printf("File I/O Error: Cannot create file %s.\n", outfilename);
32631  terminatetetgen(1);
32632  }
32633  // Number of Voronoi faces.
32634  fprintf(outfile, "%ld 0\n", edges);
32635  } else {
32636  out->numberofvfacets = edges;
32637  out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
32638  if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
32639  printf("Error: Out of memory.\n");
32640  terminatetetgen(1);
32641  }
32642  }
32643 
32644  // Loop the tetrahedronlist once, Output Voronoi facets. The index of each
32645  // Voronoi facet corresponding to the index of the Delaunay edge. The
32646  // six edges' indices of each tetrahedron are saved in the list 'tetedge-
32647  // indexarray', in the entry of i, where i (0-based) is the index of
32648  // this tetrahedron (= vpointcount).
32649  tetedgeindexarray = new int[tetrahedrons->items * 6];
32650  tetrahedrons->traversalinit();
32651  tetloop.tet = tetrahedrontraverse();
32652  vfacecount = 0;
32653  while (tetloop.tet != (tetrahedron *) NULL) {
32654  // Count the number of Voronoi faces. Look at the six edges of each
32655  // tetrahedron. Count the edge only if the tetrahedron's pointer is
32656  // smaller than those of all other tetrahedra that share the edge.
32657  worktet = tetloop;
32658  for (i = 0; i < 6; i++) {
32659  worktet.loc = edge2locver[i][0];
32660  worktet.ver = edge2locver[i][1];
32661  // Now count the number of tets surrounding this edge.
32662  tcount = 1;
32663  adjustedgering(worktet, CW);
32664  spintet = worktet;
32665  hitbdry = 0;
32666  while (hitbdry < 2) {
32667  if (fnextself(spintet)) {
32668  if (apex(spintet) == apex(worktet)) break;
32669  if (spintet.tet < worktet.tet) break;
32670  tcount++;
32671  } else {
32672  hitbdry++;
32673  if (hitbdry < 2) {
32674  esym(worktet, spintet);
32675  fnextself(spintet); // In the same tet.
32676  }
32677  }
32678  }
32679  // Count this edge if no adjacent tets are smaller than this tet.
32680  if (spintet.tet >= worktet.tet) {
32681  // Get the two endpoints of this edge.
32682  pt[0] = org(worktet);
32683  pt[1] = dest(worktet);
32684  end1 = pointmark(pt[0]) - in->firstnumber;
32685  end2 = pointmark(pt[1]) - in->firstnumber;
32686  if (out == (tetgenio *) NULL) {
32687  fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
32688  end1 + shift, end2 + shift, tcount + (hitbdry > 0));
32689  } else {
32690  vfacet = &(out->vfacetlist[vfacecount]);
32691  vfacet->c1 = end1 + shift;
32692  vfacet->c2 = end2 + shift;
32693  vfacet->elist = new int[tcount + (hitbdry > 0) + 1];
32694  vfacet->elist[0] = tcount + (hitbdry > 0);
32695  index = 1;
32696  }
32697  // If hitbdry > 0, then spintet is a hull face.
32698  if (hitbdry > 0) {
32699  // The edge list starts with a ray.
32700  vpointcount = * (int *) (spintet.tet + elemmarkerindex);
32701  vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
32702  if (out == (tetgenio *) NULL) {
32703  fprintf(outfile, " %d", vedgecount + shift);
32704  } else {
32705  vfacet->elist[index++] = vedgecount + shift;
32706  }
32707  // Save this facet number in tet.
32708  tetedgeindexarray[vpointcount * 6 +
32709  locver2edge[spintet.loc][spintet.ver]] = vfacecount;
32710  esymself(spintet);
32711  fnextself(spintet); // In the same tet.
32712  }
32713  // Output internal Voronoi edges.
32714  for (j = 0; j < tcount; j++) {
32715  vpointcount = * (int *) (spintet.tet + elemmarkerindex);
32716  vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc];
32717  if (out == (tetgenio *) NULL) {
32718  fprintf(outfile, " %d", vedgecount + shift);
32719  } else {
32720  vfacet->elist[index++] = vedgecount + shift;
32721  }
32722  // Save this facet number in tet.
32723  tetedgeindexarray[vpointcount * 6 +
32724  locver2edge[spintet.loc][spintet.ver]] = vfacecount;
32725  fnextself(spintet);
32726  }
32727  if (out == (tetgenio *) NULL) {
32728  fprintf(outfile, "\n");
32729  }
32730  vfacecount++;
32731  }
32732  } // if (i = 0; i < 6; i++)
32733  tetloop.tet = tetrahedrontraverse();
32734  }
32735 
32736  if (out == (tetgenio *) NULL) {
32737  fprintf(outfile, "# Generated by %s\n", b->commandline);
32738  fclose(outfile);
32739  }
32740 
32741  // Output Voronoi cells to .v.cell file.
32742  if (out == (tetgenio *) NULL) {
32743  strcpy(outfilename, b->outfilename);
32744  strcat(outfilename, ".v.cell");
32745  }
32746 
32747  if (!b->quiet) {
32748  if (out == (tetgenio *) NULL) {
32749  printf("Writing %s.\n", outfilename);
32750  } else {
32751  printf("Writing Voronoi cells.\n");
32752  }
32753  }
32754 
32755  if (out == (tetgenio *) NULL) {
32756  outfile = fopen(outfilename, "w");
32757  if (outfile == (FILE *) NULL) {
32758  printf("File I/O Error: Cannot create file %s.\n", outfilename);
32759  terminatetetgen(1);
32760  }
32761  // Number of Voronoi cells.
32762  fprintf(outfile, "%ld\n", points->items);
32763  } else {
32764  out->numberofvcells = points->items;
32765  out->vcelllist = new int*[out->numberofvcells];
32766  if (out->vcelllist == (int **) NULL) {
32767  printf("Error: Out of memory.\n");
32768  terminatetetgen(1);
32769  }
32770  }
32771 
32772  // Loop through point list, for each point, output a Voronoi cell.
32773  tetlist = new list(sizeof(triface), NULL, 256);
32774  ptlist = new list(sizeof(point *), NULL, 256);
32775  points->traversalinit();
32776  ptloop = pointtraverse();
32777  vpointcount = 0;
32778  while (ptloop != (point) NULL) {
32779  decode(point2tet(ptloop), tetloop);
32780  // assert(!isdead(&tetloop));
32781  if (!isdead(&tetloop)) {
32782  // Form the star of p.
32783  tetlist->append(&tetloop);
32784  formstarpolyhedron(ptloop, tetlist, ptlist, true);
32785  tcount = ptlist->len();
32786  if (out == (tetgenio *) NULL) {
32787  fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
32788  } else {
32789  arraysize = tcount;
32790  vertarray = out->vcelllist[vpointcount];
32791  vertarray = new int[arraysize + 1];
32792  vertarray[0] = arraysize;
32793  index = 1;
32794  }
32795  // List Voronoi facets bounding this cell.
32796  for (i = 0; i < ptlist->len(); i++) {
32797  neipt = * (point *)(* ptlist)[i];
32798  // Find a tet in tetlist having edge (ptloop, neipt) -- Very Slow.
32799  for (j = 0; j < tetlist->len(); j++) {
32800  tetloop = * (triface *)(* tetlist)[j];
32801  for (k = 0; k < 6; k++) {
32802  tetloop.loc = edge2locver[k][0];
32803  tetloop.ver = edge2locver[k][1];
32804  if (org(tetloop) == ptloop) {
32805  if (dest(tetloop) == neipt) break;
32806  } else if (org(tetloop) == neipt) {
32807  if (dest(tetloop) == ptloop) break;
32808  }
32809  }
32810  if (k < 6) break; // Found this edge.
32811  }
32812  assert(j < tetlist->len());
32813  // k is the right edge number.
32814  end1 = * (int *) (tetloop.tet + elemmarkerindex);
32815  vfacecount = tetedgeindexarray[end1 * 6 + k];
32816  if (out == (tetgenio *) NULL) {
32817  fprintf(outfile, " %d", vfacecount + shift);
32818  } else {
32819  vertarray[index++] = vfacecount + shift;
32820  }
32821  } // for (i = 0; i < ptlist->len(); i++) {
32822  if (out == (tetgenio *) NULL) {
32823  fprintf(outfile, "\n");
32824  }
32825  vpointcount++;
32826  }
32827  tetlist->clear();
32828  ptlist->clear();
32829  ptloop = pointtraverse();
32830  }
32831  delete tetlist;
32832  delete ptlist;
32833  delete [] tetfaceindexarray;
32834  delete [] tetedgeindexarray;
32835 
32836  if (out == (tetgenio *) NULL) {
32837  fprintf(outfile, "# Generated by %s\n", b->commandline);
32838  fclose(outfile);
32839  }
32840 }
32841 
32843 // //
32844 // outpbcnodes() Output pbc node pairs to a .pbc file or a structure. //
32845 // //
32847 
32848 void tetgenmesh::outpbcnodes(tetgenio* out)
32849 {
32850  FILE *outfile;
32851  char pbcfilename[FILENAMESIZE];
32852  list *ptpairlist;
32853  tetgenio::pbcgroup *pgi, *pgo;
32854  pbcdata *pd;
32855  face faceloop;
32856  face checkseg, symseg;
32857  point *ptpair, pa, pb;
32858  enum locateresult loc;
32859  REAL sympt[3], d1, d2;
32860  int *worklist;
32861  int firstindex, shift;
32862  int index, idx;
32863  int i, j, k, l;
32864 
32865  if (out == (tetgenio *) NULL) {
32866  strcpy(pbcfilename, b->outfilename);
32867  strcat(pbcfilename, ".pbc");
32868  }
32869 
32870  if (!b->quiet) {
32871  if (out == (tetgenio *) NULL) {
32872  printf("Writing %s.\n", pbcfilename);
32873  } else {
32874  printf("Writing pbc nodes.\n");
32875  }
32876  }
32877 
32878  // Avoid compilation warnings.
32879  outfile = (FILE *) NULL;
32880  pgo = (tetgenio::pbcgroup *) NULL;
32881  index = 0;
32882 
32883  if (out == (tetgenio *) NULL) {
32884  outfile = fopen(pbcfilename, "w");
32885  if (outfile == (FILE *) NULL) {
32886  printf("File I/O Error: Cannot create file %s.\n", pbcfilename);
32887  terminatetetgen(1);
32888  }
32889  // Number of pbc groups.
32890  fprintf(outfile, "# number of PBCs.\n");
32891  fprintf(outfile, "%d\n\n", in->numberofpbcgroups);
32892  } else {
32893  out->numberofpbcgroups = in->numberofpbcgroups;
32894  // Allocate memory for 'out->pbcgrouplist'.
32895  out->pbcgrouplist = new tetgenio::pbcgroup[in->numberofpbcgroups];
32896  // (Next line was a bug, reported by Murry Nigel).
32897  if (out->pbcgrouplist == (tetgenio::pbcgroup *) NULL) {
32898  printf("Error: Out of memory.\n");
32899  terminatetetgen(1);
32900  }
32901  }
32902 
32903  ptpairlist = new list(2 * sizeof(point *), NULL, 256);
32904  worklist = new int[points->items + 1];
32905  for (i = 0; i < points->items + 1; i++) worklist[i] = 0;
32906 
32907  // Determine the first index (0 or 1).
32908  firstindex = b->zeroindex ? 0 : in->firstnumber;
32909  shift = 0; // Default no shiftment.
32910  if ((in->firstnumber == 1) && (firstindex == 0)) {
32911  shift = 1; // Shift the output indices by 1.
32912  }
32913 
32914  for (i = 0; i < in->numberofpbcgroups; i++) {
32915  // Group i.
32916  pgi = &(in->pbcgrouplist[i]);
32917  if (out == (tetgenio *) NULL) {
32918  fprintf(outfile, "# PBC %d\n", in->firstnumber + i);
32919  // Output facet markers.
32920  fprintf(outfile, "%d %d\n", pgi->fmark1, pgi->fmark2);
32921  // Output transformation matrix.
32922  fprintf(outfile, "[\n");
32923  for (j = 0; j < 4; j++) {
32924  fprintf(outfile, " %.12g %.12g %.12g %.12g\n", pgi->transmat[j][0],
32925  pgi->transmat[j][1], pgi->transmat[j][2], pgi->transmat[j][3]);
32926  }
32927  fprintf(outfile, "]\n");
32928  } else {
32929  pgo = &(out->pbcgrouplist[i]);
32930  // Copy data from pgi to pgo.
32931  pgo->fmark1 = pgi->fmark1;
32932  pgo->fmark2 = pgi->fmark2;
32933  for (j = 0; j < 4; j++) {
32934  for (k = 0; k < 4; k++) pgo->transmat[j][k] = pgi->transmat[j][k];
32935  }
32936  }
32937 
32938  // Find the point pairs of group i.
32939  subfaces->traversalinit();
32940  faceloop.sh = shellfacetraverse(subfaces);
32941  while (faceloop.sh != (shellface *) NULL) {
32942  if (shellpbcgroup(faceloop) == i) {
32943  // It is in group i. Operate on it if it has pgi->fmark1.
32944  idx = shellmark(faceloop) - 1;
32945  if (in->facetmarkerlist[idx] == pgi->fmark1) {
32946  // Loop three edges of the subface.
32947  for (j = 0; j < 3; j++) {
32948  sspivot(faceloop, checkseg);
32949  // Loop two vertices of the edge.
32950  for (k = 0; k < 2; k++) {
32951  if (k == 0) pa = sorg(faceloop);
32952  else pa = sdest(faceloop);
32953  if (worklist[pointmark(pa)] == 0) {
32954  pb = (point) NULL;
32955  if (checkseg.sh != dummysh) {
32956  // pa is on a segment. Find pb.
32957  // Find the incident pbcgroup of checkseg.
32958  idx = shellmark(checkseg) - 1;
32959  for (l = idx2segpglist[idx]; l < idx2segpglist[idx + 1];
32960  l++) {
32961  pd = (pbcdata *)(* segpbcgrouptable)[segpglist[l]];
32962  if (((pd->fmark[0] == pgi->fmark1) &&
32963  (pd->fmark[1] == pgi->fmark2)) ||
32964  ((pd->fmark[0] == pgi->fmark2) &&
32965  (pd->fmark[1] == pgi->fmark1))) break;
32966  }
32967 #ifdef SELF_CHECK
32968  assert(l < idx2segpglist[idx + 1]);
32969 #endif
32970  loc = getsegpbcsympoint(pa, &checkseg, sympt, &symseg,
32971  segpglist[l]);
32972  if (loc != ONVERTEX) {
32973  // Not found a match point! It may be caused by the
32974  // pair of input vertices don't have enough digits.
32975  // Choose a near vertex.
32976  d1 = distance(sympt, sorg(symseg));
32977  d2 = distance(sympt, sdest(symseg));
32978  if (d1 > d2) sesymself(symseg);
32979  }
32980  pb = sorg(symseg);
32981  } else {
32982  // Operate on pa if it is inside the facet.
32983  if (pointtype(pa) == FREESUBVERTEX) {
32984  pb = point2pbcpt(pa);
32985  }
32986  }
32987  if (pb != (point) NULL) {
32988  // Add the pair (pa, pb) into list.
32989  ptpair = (point *) ptpairlist->append(NULL);
32990  ptpair[0] = pa;
32991  ptpair[1] = pb;
32992  // Mark pa (avoid to operate on it later).
32993  worklist[pointmark(pa)] = 1;
32994  }
32995  }
32996  }
32997  // Get the next edge.
32998  senextself(faceloop);
32999  }
33000  }
33001  }
33002  faceloop.sh = shellfacetraverse(subfaces);
33003  }
33004 
33005  // Output the list of pbc points.
33006  if (out == (tetgenio *) NULL) {
33007  fprintf(outfile, "%d\n", ptpairlist->len());
33008  } else {
33009  pgo->numberofpointpairs = ptpairlist->len();
33010  pgo->pointpairlist = new int[pgo->numberofpointpairs * 2];
33011  index = 0;
33012  }
33013  for (j = 0; j < ptpairlist->len(); j++) {
33014  ptpair = (point *)(* ptpairlist)[j];
33015  pa = ptpair[0];
33016  pb = ptpair[1];
33017  if (out == (tetgenio *) NULL) {
33018  fprintf(outfile, " %4d %4d\n", pointmark(pa) - shift,
33019  pointmark(pb) - shift);
33020  } else {
33021  pgo->pointpairlist[index++] = pointmark(pa) - shift;
33022  pgo->pointpairlist[index++] = pointmark(pb) - shift;
33023  }
33024  // Unmark pa.
33025  worklist[pointmark(pa)] = 0;
33026  }
33027  if (out == (tetgenio *) NULL) {
33028  fprintf(outfile, "\n");
33029  }
33030  ptpairlist->clear();
33031  }
33032 
33033  delete [] worklist;
33034  delete ptpairlist;
33035 
33036  if (out == (tetgenio *) NULL) {
33037  fprintf(outfile, "# Generated by %s\n", b->commandline);
33038  fclose(outfile);
33039  }
33040 }
33041 
33043 // //
33044 // outsmesh() Write surface mesh to a .smesh file, which can be read and //
33045 // tetrahedralized by TetGen. //
33046 // //
33047 // You can specify a filename (without suffix) in 'smfilename'. If you don't //
33048 // supply a filename (let smfilename be NULL), the default name stored in //
33049 // 'tetgenbehavior' will be used. //
33050 // //
33052 
33053 void tetgenmesh::outsmesh(char* smfilename)
33054 {
33055  FILE *outfile;
33056  char nodfilename[FILENAMESIZE];
33057  char smefilename[FILENAMESIZE];
33058  face faceloop;
33059  point p1, p2, p3;
33060  int firstindex, shift;
33061  int bmark;
33062  int faceid, marker;
33063  int i;
33064 
33065  if (smfilename != (char *) NULL && smfilename[0] != '\0') {
33066  strcpy(smefilename, smfilename);
33067  } else if (b->outfilename[0] != '\0') {
33068  strcpy(smefilename, b->outfilename);
33069  } else {
33070  strcpy(smefilename, "unnamed");
33071  }
33072  strcpy(nodfilename, smefilename);
33073  strcat(smefilename, ".smesh");
33074  strcat(nodfilename, ".node");
33075 
33076  if (!b->quiet) {
33077  printf("Writing %s.\n", smefilename);
33078  }
33079  outfile = fopen(smefilename, "w");
33080  if (outfile == (FILE *) NULL) {
33081  printf("File I/O Error: Cannot create file %s.\n", smefilename);
33082  return;
33083  }
33084 
33085  // Determine the first index (0 or 1).
33086  firstindex = b->zeroindex ? 0 : in->firstnumber;
33087  shift = 0; // Default no shiftment.
33088  if ((in->firstnumber == 1) && (firstindex == 0)) {
33089  shift = 1; // Shift the output indices by 1.
33090  }
33091 
33092  fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
33093  fprintf(outfile, "\n# part 1: node list.\n");
33094  fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
33095 
33096  marker = 0; // avoid compile warning.
33097  bmark = !b->nobound && in->facetmarkerlist;
33098 
33099  fprintf(outfile, "\n# part 2: facet list.\n");
33100  // Number of facets, boundary marker.
33101  fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
33102 
33103  subfaces->traversalinit();
33104  faceloop.sh = shellfacetraverse(subfaces);
33105  while (faceloop.sh != (shellface *) NULL) {
33106  p1 = sorg(faceloop);
33107  p2 = sdest(faceloop);
33108  p3 = sapex(faceloop);
33109  if (bmark) {
33110  faceid = shellmark(faceloop) - 1;
33111  if (faceid >= 0) {
33112  marker = in->facetmarkerlist[faceid];
33113  } else {
33114  marker = 0; // This subface must be added manually later.
33115  }
33116  }
33117  fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
33118  pointmark(p2) - shift, pointmark(p3) - shift);
33119  if (bmark) {
33120  fprintf(outfile, " %d", marker);
33121  }
33122  fprintf(outfile, "\n");
33123  faceloop.sh = shellfacetraverse(subfaces);
33124  }
33125 
33126  // Copy input holelist.
33127  fprintf(outfile, "\n# part 3: hole list.\n");
33128  fprintf(outfile, "%d\n", in->numberofholes);
33129  for (i = 0; i < in->numberofholes; i++) {
33130  fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
33131  in->holelist[i * 3], in->holelist[i * 3 + 1],
33132  in->holelist[i * 3 + 2]);
33133  }
33134 
33135  // Copy input regionlist.
33136  fprintf(outfile, "\n# part 4: region list.\n");
33137  fprintf(outfile, "%d\n", in->numberofregions);
33138  for (i = 0; i < in->numberofregions; i++) {
33139  fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
33140  in->regionlist[i * 5], in->regionlist[i * 5 + 1],
33141  in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
33142  in->regionlist[i * 5 + 4]);
33143  }
33144 
33145  fprintf(outfile, "# Generated by %s\n", b->commandline);
33146  fclose(outfile);
33147 }
33148 
33150 // //
33151 // outmesh2medit() Write mesh to a .mesh file, which can be read and //
33152 // rendered by Medit (a free mesh viewer from INRIA). //
33153 // //
33154 // You can specify a filename (without suffix) in 'mfilename'. If you don't //
33155 // supply a filename (let mfilename be NULL), the default name stored in //
33156 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
33157 // //
33159 
33160 void tetgenmesh::outmesh2medit(char* mfilename)
33161 {
33162  FILE *outfile;
33163  char mefilename[FILENAMESIZE];
33164  tetrahedron* tetptr;
33165  triface tface, tsymface;
33166  face segloop, checkmark;
33167  point ptloop, p1, p2, p3, p4;
33168  long faces;
33169  int pointnumber;
33170  int i;
33171 
33172  if (mfilename != (char *) NULL && mfilename[0] != '\0') {
33173  strcpy(mefilename, mfilename);
33174  } else if (b->outfilename[0] != '\0') {
33175  strcpy(mefilename, b->outfilename);
33176  } else {
33177  strcpy(mefilename, "unnamed");
33178  }
33179  strcat(mefilename, ".mesh");
33180 
33181  if (!b->quiet) {
33182  printf("Writing %s.\n", mefilename);
33183  }
33184  outfile = fopen(mefilename, "w");
33185  if (outfile == (FILE *) NULL) {
33186  printf("File I/O Error: Cannot create file %s.\n", mefilename);
33187  return;
33188  }
33189 
33190  fprintf(outfile, "MeshVersionFormatted 1\n");
33191  fprintf(outfile, "\n");
33192  fprintf(outfile, "Dimension\n");
33193  fprintf(outfile, "3\n");
33194  fprintf(outfile, "\n");
33195 
33196  fprintf(outfile, "\n# Set of mesh vertices\n");
33197  fprintf(outfile, "Vertices\n");
33198  fprintf(outfile, "%ld\n", points->items);
33199 
33200  points->traversalinit();
33201  ptloop = pointtraverse();
33202  pointnumber = 1; // Medit need start number form 1.
33203  while (ptloop != (point) NULL) {
33204  // Point coordinates.
33205  fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
33206  if (in->numberofpointattributes > 0) {
33207  // Write an attribute, ignore others if more than one.
33208  fprintf(outfile, " %.17g\n", ptloop[3]);
33209  } else {
33210  fprintf(outfile, " 0\n");
33211  }
33212  setpointmark(ptloop, pointnumber);
33213  ptloop = pointtraverse();
33214  pointnumber++;
33215  }
33216 
33217  // Compute the number of edges.
33218  faces = (4l * tetrahedrons->items + hullsize) / 2l;
33219 
33220  fprintf(outfile, "\n# Set of Triangles\n");
33221  fprintf(outfile, "Triangles\n");
33222  fprintf(outfile, "%ld\n", faces);
33223 
33224  tetrahedrons->traversalinit();
33225  tface.tet = tetrahedrontraverse();
33226  // To loop over the set of faces, loop over all tetrahedra, and look at
33227  // the four faces of each tetrahedron. If there isn't another tetrahedron
33228  // adjacent to the face, operate on the face. If there is another adj-
33229  // acent tetrahedron, operate on the face only if the current tetrahedron
33230  // has a smaller pointer than its neighbor. This way, each face is
33231  // considered only once.
33232  while (tface.tet != (tetrahedron *) NULL) {
33233  for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33234  sym(tface, tsymface);
33235  if (tface.tet < tsymface.tet || tsymface.tet == dummytet) {
33236  p1 = org (tface);
33237  p2 = dest(tface);
33238  p3 = apex(tface);
33239  fprintf(outfile, "%5d %5d %5d",
33240  pointmark(p1), pointmark(p2), pointmark(p3));
33241  fprintf(outfile, " 0\n");
33242  }
33243  }
33244  tface.tet = tetrahedrontraverse();
33245  }
33246 
33247  fprintf(outfile, "\n# Set of Tetrahedra\n");
33248  fprintf(outfile, "Tetrahedra\n");
33249  fprintf(outfile, "%ld\n", tetrahedrons->items);
33250 
33251  tetrahedrons->traversalinit();
33252  tetptr = tetrahedrontraverse();
33253  while (tetptr != (tetrahedron *) NULL) {
33254  p1 = (point) tetptr[4];
33255  p2 = (point) tetptr[5];
33256  p3 = (point) tetptr[6];
33257  p4 = (point) tetptr[7];
33258  fprintf(outfile, "%5d %5d %5d %5d",
33259  pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
33260  if (in->numberoftetrahedronattributes > 0) {
33261  fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
33262  } else {
33263  fprintf(outfile, " 0");
33264  }
33265  fprintf(outfile, "\n");
33266  tetptr = tetrahedrontraverse();
33267  }
33268 
33269  fprintf(outfile, "\nCorners\n");
33270  fprintf(outfile, "%d\n", in->numberofpoints);
33271 
33272  for (i = 0; i < in->numberofpoints; i++) {
33273  fprintf(outfile, "%4d\n", i + 1);
33274  }
33275 
33276  if (b->useshelles) {
33277  fprintf(outfile, "\nEdges\n");
33278  fprintf(outfile, "%ld\n", subsegs->items);
33279 
33280  subsegs->traversalinit();
33281  segloop.sh = shellfacetraverse(subsegs);
33282  while (segloop.sh != (shellface *) NULL) {
33283  p1 = sorg(segloop);
33284  p2 = sdest(segloop);
33285  fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
33286  fprintf(outfile, " 0\n");
33287  segloop.sh = shellfacetraverse(subsegs);
33288  }
33289  }
33290 
33291  fprintf(outfile, "\nEnd\n");
33292  fclose(outfile);
33293 }
33294 
33296 // //
33297 // outmesh2gid() Write mesh to a .ele.msh file and a .face.msh file, //
33298 // which can be imported and rendered by Gid. //
33299 // //
33300 // You can specify a filename (without suffix) in 'gfilename'. If you don't //
33301 // supply a filename (let gfilename be NULL), the default name stored in //
33302 // 'tetgenbehavior' will be used. The suffixes (.ele.msh and .face.msh) will //
33303 // be automatically added. //
33304 // //
33306 
33307 void tetgenmesh::outmesh2gid(char* gfilename)
33308 {
33309  FILE *outfile;
33310  char gidfilename[FILENAMESIZE];
33311  tetrahedron* tetptr;
33312  triface tface, tsymface;
33313  face sface;
33314  point ptloop, p1, p2, p3, p4;
33315  int pointnumber;
33316  int elementnumber;
33317 
33318  if (gfilename != (char *) NULL && gfilename[0] != '\0') {
33319  strcpy(gidfilename, gfilename);
33320  } else if (b->outfilename[0] != '\0') {
33321  strcpy(gidfilename, b->outfilename);
33322  } else {
33323  strcpy(gidfilename, "unnamed");
33324  }
33325  strcat(gidfilename, ".ele.msh");
33326 
33327  if (!b->quiet) {
33328  printf("Writing %s.\n", gidfilename);
33329  }
33330  outfile = fopen(gidfilename, "w");
33331  if (outfile == (FILE *) NULL) {
33332  printf("File I/O Error: Cannot create file %s.\n", gidfilename);
33333  return;
33334  }
33335 
33336  fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n");
33337  fprintf(outfile, "coordinates\n");
33338 
33339  points->traversalinit();
33340  ptloop = pointtraverse();
33341  pointnumber = 1; // Gid need start number form 1.
33342  while (ptloop != (point) NULL) {
33343  // Point coordinates.
33344  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
33345  ptloop[0], ptloop[1], ptloop[2]);
33346  if (in->numberofpointattributes > 0) {
33347  // Write an attribute, ignore others if more than one.
33348  fprintf(outfile, " %.17g", ptloop[3]);
33349  }
33350  fprintf(outfile, "\n");
33351  setpointmark(ptloop, pointnumber);
33352  ptloop = pointtraverse();
33353  pointnumber++;
33354  }
33355 
33356  fprintf(outfile, "end coordinates\n");
33357  fprintf(outfile, "elements\n");
33358 
33359  tetrahedrons->traversalinit();
33360  tetptr = tetrahedrontraverse();
33361  elementnumber = 1;
33362  while (tetptr != (tetrahedron *) NULL) {
33363  p1 = (point) tetptr[4];
33364  p2 = (point) tetptr[5];
33365  p3 = (point) tetptr[6];
33366  p4 = (point) tetptr[7];
33367  fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
33368  pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
33369  if (in->numberoftetrahedronattributes > 0) {
33370  fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
33371  }
33372  fprintf(outfile, "\n");
33373  tetptr = tetrahedrontraverse();
33374  elementnumber++;
33375  }
33376 
33377  fprintf(outfile, "end elements\n");
33378  fclose(outfile);
33379 
33380  if (gfilename != (char *) NULL && gfilename[0] != '\0') {
33381  strcpy(gidfilename, gfilename);
33382  } else if (b->outfilename[0] != '\0') {
33383  strcpy(gidfilename, b->outfilename);
33384  } else {
33385  strcpy(gidfilename, "unnamed");
33386  }
33387  strcat(gidfilename, ".face.msh");
33388 
33389  if (!b->quiet) {
33390  printf("Writing %s.\n", gidfilename);
33391  }
33392  outfile = fopen(gidfilename, "w");
33393  if (outfile == (FILE *) NULL) {
33394  printf("File I/O Error: Cannot create file %s.\n", gidfilename);
33395  return;
33396  }
33397 
33398  fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n");
33399  fprintf(outfile, "coordinates\n");
33400 
33401  points->traversalinit();
33402  ptloop = pointtraverse();
33403  pointnumber = 1; // Gid need start number form 1.
33404  while (ptloop != (point) NULL) {
33405  // Point coordinates.
33406  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
33407  ptloop[0], ptloop[1], ptloop[2]);
33408  if (in->numberofpointattributes > 0) {
33409  // Write an attribute, ignore others if more than one.
33410  fprintf(outfile, " %.17g", ptloop[3]);
33411  }
33412  fprintf(outfile, "\n");
33413  setpointmark(ptloop, pointnumber);
33414  ptloop = pointtraverse();
33415  pointnumber++;
33416  }
33417 
33418  fprintf(outfile, "end coordinates\n");
33419  fprintf(outfile, "elements\n");
33420 
33421  tetrahedrons->traversalinit();
33422  tface.tet = tetrahedrontraverse();
33423  elementnumber = 1;
33424  while (tface.tet != (tetrahedron *) NULL) {
33425  for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33426  sym(tface, tsymface);
33427  if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
33428  p1 = org(tface);
33429  p2 = dest(tface);
33430  p3 = apex(tface);
33431  if (tsymface.tet == dummytet) {
33432  // It's a hull face, output it.
33433  fprintf(outfile, "%5d %d %d %d\n", elementnumber,
33434  pointmark(p1), pointmark(p2), pointmark(p3));
33435  elementnumber++;
33436  } else if (b->useshelles) {
33437  // Only output it if it's a subface.
33438  tspivot(tface, sface);
33439  if (sface.sh != dummysh) {
33440  fprintf(outfile, "%5d %d %d %d\n", elementnumber,
33441  pointmark(p1), pointmark(p2), pointmark(p3));
33442  elementnumber++;
33443  }
33444  }
33445  }
33446  }
33447  tface.tet = tetrahedrontraverse();
33448  }
33449 
33450  fprintf(outfile, "end elements\n");
33451  fclose(outfile);
33452 }
33453 
33455 // //
33456 // outmesh2off() Write the mesh to an .off file. //
33457 // //
33458 // .off, the Object File Format, is one of the popular file formats from the //
33459 // Geometry Center's Geomview package (http://www.geomview.org). //
33460 // //
33462 
33463 void tetgenmesh::outmesh2off(char* ofilename)
33464 {
33465  FILE *outfile;
33466  char offfilename[FILENAMESIZE];
33467  triface tface, tsymface;
33468  point ptloop, p1, p2, p3;
33469  long faces;
33470  int shift;
33471 
33472  if (ofilename != (char *) NULL && ofilename[0] != '\0') {
33473  strcpy(offfilename, ofilename);
33474  } else if (b->outfilename[0] != '\0') {
33475  strcpy(offfilename, b->outfilename);
33476  } else {
33477  strcpy(offfilename, "unnamed");
33478  }
33479  strcat(offfilename, ".off");
33480 
33481  if (!b->quiet) {
33482  printf("Writing %s.\n", offfilename);
33483  }
33484  outfile = fopen(offfilename, "w");
33485  if (outfile == (FILE *) NULL) {
33486  printf("File I/O Error: Cannot create file %s.\n", offfilename);
33487  return;
33488  }
33489 
33490  // Calculate the number of triangular faces in the tetrahedral mesh.
33491  faces = (4l * tetrahedrons->items + hullsize) / 2l;
33492 
33493  // Number of points, faces, and edges(not used, here show hullsize).
33494  fprintf(outfile, "OFF\n%ld %ld %ld\n", points->items, faces, hullsize);
33495 
33496  // Write the points.
33497  points->traversalinit();
33498  ptloop = pointtraverse();
33499  while (ptloop != (point) NULL) {
33500  fprintf(outfile, " %.17g %.17g %.17g\n",ptloop[0], ptloop[1], ptloop[2]);
33501  ptloop = pointtraverse();
33502  }
33503 
33504  // OFF always use zero as the first index.
33505  shift = in->firstnumber == 1 ? 1 : 0;
33506 
33507  tetrahedrons->traversalinit();
33508  tface.tet = tetrahedrontraverse();
33509  // To loop over the set of faces, loop over all tetrahedra, and look at
33510  // the four faces of each tetrahedron. If there isn't another tetrahedron
33511  // adjacent to the face, operate on the face. If there is another adj-
33512  // acent tetrahedron, operate on the face only if the current tetrahedron
33513  // has a smaller pointer than its neighbor. This way, each face is
33514  // considered only once.
33515  while (tface.tet != (tetrahedron *) NULL) {
33516  for (tface.loc = 0; tface.loc < 4; tface.loc ++) {
33517  sym(tface, tsymface);
33518  if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) {
33519  p1 = org(tface);
33520  p2 = dest(tface);
33521  p3 = apex(tface);
33522  // Face number, indices of three vertexs.
33523  fprintf(outfile, "3 %4d %4d %4d\n", pointmark(p1) - shift,
33524  pointmark(p2) - shift, pointmark(p3) - shift);
33525  }
33526  }
33527  tface.tet = tetrahedrontraverse();
33528  }
33529 
33530  fprintf(outfile, "# Generated by %s\n", b->commandline);
33531  fclose(outfile);
33532 }
33533 
33534 //
33535 // End of I/O rouitnes
33536 //
33537 
33538 //
33539 // Begin of user interaction routines
33540 //
33541 
33543 // //
33544 // internalerror() Ask the user to send me the defective product. Exit. //
33545 // //
33547 
33548 void tetgenmesh::internalerror()
33549 {
33550  printf(" Please report this bug to sihang@mail.berlios.de. Include the\n");
33551  printf(" message above, your input data set, and the exact command\n");
33552  printf(" line you used to run this program, thank you.\n");
33553  terminatetetgen(2);
33554 }
33555 
33557 // //
33558 // checkmesh() Test the mesh for topological consistency. //
33559 // //
33561 
33562 void tetgenmesh::checkmesh()
33563 {
33564  triface tetraloop;
33565  triface oppotet, oppooppotet;
33566  point tetorg, tetdest, tetapex, tetoppo;
33567  REAL oritest;
33568  int horrors;
33569 
33570  if (!b->quiet) {
33571  printf(" Checking consistency of mesh...\n");
33572  }
33573 
33574  horrors = 0;
33575  // Run through the list of tetrahedra, checking each one.
33576  tetrahedrons->traversalinit();
33577  tetraloop.tet = tetrahedrontraverse();
33578  while (tetraloop.tet != (tetrahedron *) NULL) {
33579  // Check all four faces of the tetrahedron.
33580  for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
33581  tetorg = org(tetraloop);
33582  tetdest = dest(tetraloop);
33583  tetapex = apex(tetraloop);
33584  tetoppo = oppo(tetraloop);
33585  if (tetraloop.loc == 0) { // Only test for inversion once.
33586  oritest = orient3d(tetorg, tetdest, tetapex, tetoppo);
33587  if (oritest >= 0.0) {
33588  printf(" !! !! %s ", oritest > 0.0 ? "Inverted" : "Degenerated");
33589  printtet(&tetraloop);
33590  printf(" orient3d = %.17g.\n", oritest);
33591  horrors++;
33592  }
33593  }
33594  // Find the neighboring tetrahedron on this face.
33595  sym(tetraloop, oppotet);
33596  if (oppotet.tet != dummytet) {
33597  // Check that the tetrahedron's neighbor knows it's a neighbor.
33598  sym(oppotet, oppooppotet);
33599  if ((tetraloop.tet != oppooppotet.tet)
33600  || (tetraloop.loc != oppooppotet.loc)) {
33601  printf(" !! !! Asymmetric tetra-tetra bond:\n");
33602  if (tetraloop.tet == oppooppotet.tet) {
33603  printf(" (Right tetrahedron, wrong orientation)\n");
33604  }
33605  printf(" First ");
33606  printtet(&tetraloop);
33607  printf(" Second (nonreciprocating) ");
33608  printtet(&oppotet);
33609  horrors++;
33610  }
33611  }
33612  }
33613  tetraloop.tet = tetrahedrontraverse();
33614  }
33615  if (horrors == 0) {
33616  if (!b->quiet) {
33617  printf(" In my studied opinion, the mesh appears to be consistent.\n");
33618  }
33619  } else if (horrors == 1) {
33620  printf(" !! !! !! !! Precisely one festering wound discovered.\n");
33621  } else {
33622  printf(" !! !! !! !! %d abominations witnessed.\n", horrors);
33623  }
33624 }
33625 
33627 // //
33628 // checkshells() Test the boundary mesh for topological consistency. //
33629 // //
33631 
33632 void tetgenmesh::checkshells()
33633 {
33634  triface oppotet, oppooppotet, testtet;
33635  face shloop, segloop, spin;
33636  face testsh, testseg, testshsh;
33637  point shorg, shdest, segorg, segdest;
33638  REAL checksign;
33639  bool same;
33640  int horrors;
33641  int i;
33642 
33643  if (!b->quiet) {
33644  printf(" Checking consistency of the mesh boundary...\n");
33645  }
33646  horrors = 0;
33647 
33648  // Run through the list of subfaces, checking each one.
33649  subfaces->traversalinit();
33650  shloop.sh = shellfacetraverse(subfaces);
33651  while (shloop.sh != (shellface *) NULL) {
33652  // Check two connected tetrahedra if they exist.
33653  shloop.shver = 0;
33654  stpivot(shloop, oppotet);
33655  if (oppotet.tet != dummytet) {
33656  tspivot(oppotet, testsh);
33657  if (testsh.sh != shloop.sh) {
33658  printf(" !! !! Wrong tetra-subface connection.\n");
33659  printf(" Tetra: ");
33660  printtet(&oppotet);
33661  printf(" Subface: ");
33662  printsh(&shloop);
33663  horrors++;
33664  }
33665  if (oppo(oppotet) != (point) NULL) {
33666  adjustedgering(oppotet, CCW);
33667  checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop),
33668  oppo(oppotet));
33669  if (checksign >= 0.0) {
33670  printf(" !! !! Wrong subface orientation.\n");
33671  printf(" Subface: ");
33672  printsh(&shloop);
33673  horrors++;
33674  }
33675  }
33676  }
33677  sesymself(shloop);
33678  stpivot(shloop, oppooppotet);
33679  if (oppooppotet.tet != dummytet) {
33680  tspivot(oppooppotet, testsh);
33681  if (testsh.sh != shloop.sh) {
33682  printf(" !! !! Wrong tetra-subface connection.\n");
33683  printf(" Tetra: ");
33684  printtet(&oppooppotet);
33685  printf(" Subface: ");
33686  printsh(&shloop);
33687  horrors++;
33688  }
33689  if (oppotet.tet != dummytet) {
33690  sym(oppotet, testtet);
33691  if (testtet.tet != oppooppotet.tet) {
33692  printf(" !! !! Wrong tetra-subface-tetra connection.\n");
33693  printf(" Tetra 1: ");
33694  printtet(&oppotet);
33695  printf(" Subface: ");
33696  printsh(&shloop);
33697  printf(" Tetra 2: ");
33698  printtet(&oppooppotet);
33699  horrors++;
33700  }
33701  }
33702  if (oppo(oppooppotet) != (point) NULL) {
33703  adjustedgering(oppooppotet, CCW);
33704  checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop),
33705  oppo(oppooppotet));
33706  if (checksign >= 0.0) {
33707  printf(" !! !! Wrong subface orientation.\n");
33708  printf(" Subface: ");
33709  printsh(&shloop);
33710  horrors++;
33711  }
33712  }
33713  }
33714  // Check connection between subfaces.
33715  shloop.shver = 0;
33716  for (i = 0; i < 3; i++) {
33717  shorg = sorg(shloop);
33718  shdest = sdest(shloop);
33719  sspivot(shloop, testseg);
33720  if (testseg.sh != dummysh) {
33721  segorg = sorg(testseg);
33722  segdest = sdest(testseg);
33723  same = ((shorg == segorg) && (shdest == segdest))
33724  || ((shorg == segdest) && (shdest == segorg));
33725  if (!same) {
33726  printf(" !! !! Wrong subface-subsegment connection.\n");
33727  printf(" Subface: ");
33728  printsh(&shloop);
33729  printf(" Subsegment: ");
33730  printsh(&testseg);
33731  horrors++;
33732  }
33733  }
33734  spivot(shloop, testsh);
33735  if (testsh.sh != dummysh) {
33736  segorg = sorg(testsh);
33737  segdest = sdest(testsh);
33738  same = ((shorg == segorg) && (shdest == segdest))
33739  || ((shorg == segdest) && (shdest == segorg));
33740  if (!same) {
33741  printf(" !! !! Wrong subface-subface connection.\n");
33742  printf(" Subface 1: ");
33743  printsh(&shloop);
33744  printf(" Subface 2: ");
33745  printsh(&testsh);
33746  horrors++;
33747  }
33748  spivot(testsh, testshsh);
33749  shorg = sorg(testshsh);
33750  shdest = sdest(testshsh);
33751  same = ((shorg == segorg) && (shdest == segdest))
33752  || ((shorg == segdest) && (shdest == segorg));
33753  if (!same) {
33754  printf(" !! !! Wrong subface-subface connection.\n");
33755  printf(" Subface 1: ");
33756  printsh(&testsh);
33757  printf(" Subface 2: ");
33758  printsh(&testshsh);
33759  horrors++;
33760  }
33761  if (testseg.sh == dummysh) {
33762  if (testshsh.sh != shloop.sh) {
33763  printf(" !! !! Wrong subface-subface connection.\n");
33764  printf(" Subface 1: ");
33765  printsh(&shloop);
33766  printf(" Subface 2: ");
33767  printsh(&testsh);
33768  horrors++;
33769  }
33770  }
33771  }
33772  senextself(shloop);
33773  }
33774  shloop.sh = shellfacetraverse(subfaces);
33775  }
33776 
33777  // Run through the list of subsegs, checking each one.
33778  subsegs->traversalinit();
33779  segloop.sh = shellfacetraverse(subsegs);
33780  while (segloop.sh != (shellface *) NULL) {
33781  segorg = sorg(segloop);
33782  segdest = sdest(segloop);
33783  spivot(segloop, testsh);
33784  if (testsh.sh == dummysh) {
33785  printf(" !! !! Wrong subsegment-subface connection.\n");
33786  printf(" Subsegment: ");
33787  printsh(&segloop);
33788  horrors++;
33789  segloop.sh = shellfacetraverse(subsegs);
33790  continue;
33791  }
33792  shorg = sorg(testsh);
33793  shdest = sdest(testsh);
33794  same = ((shorg == segorg) && (shdest == segdest))
33795  || ((shorg == segdest) && (shdest == segorg));
33796  if (!same) {
33797  printf(" !! !! Wrong subsegment-subface connection.\n");
33798  printf(" Subsegment : ");
33799  printsh(&segloop);
33800  printf(" Subface : ");
33801  printsh(&testsh);
33802  horrors++;
33803  segloop.sh = shellfacetraverse(subsegs);
33804  continue;
33805  }
33806  // Check the connection of face loop around this subsegment.
33807  spin = testsh;
33808  i = 0;
33809  do {
33810  spivotself(spin);
33811  shorg = sorg(spin);
33812  shdest = sdest(spin);
33813  same = ((shorg == segorg) && (shdest == segdest))
33814  || ((shorg == segdest) && (shdest == segorg));
33815  if (!same) {
33816  printf(" !! !! Wrong subsegment-subface connection.\n");
33817  printf(" Subsegment : ");
33818  printsh(&segloop);
33819  printf(" Subface : ");
33820  printsh(&testsh);
33821  horrors++;
33822  break;
33823  }
33824  i++;
33825  } while (spin.sh != testsh.sh && i < 1000);
33826  if (i >= 1000) {
33827  printf(" !! !! Wrong subsegment-subface connection.\n");
33828  printf(" Subsegment : ");
33829  printsh(&segloop);
33830  horrors++;
33831  }
33832  segloop.sh = shellfacetraverse(subsegs);
33833  }
33834  if (horrors == 0) {
33835  if (!b->quiet) {
33836  printf(" Mesh boundaries connected correctly.\n");
33837  }
33838  } else {
33839  printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
33840  horrors);
33841  return;
33842  }
33843 }
33844 
33846 // //
33847 // checkdelaunay() Ensure that the mesh is constrained Delaunay. //
33848 // //
33849 // If 'flipqueue' is not NULL, non-locally Delaunay faces are saved in it. //
33850 // //
33852 
33853 void tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue)
33854 {
33855  triface tetraloop;
33856  triface oppotet;
33857  face opposhelle;
33858  point tetorg, tetdest, tetapex, tetoppo;
33859  point oppooppo;
33860  enum fliptype fc;
33861  REAL sign;
33862  int shouldbedelaunay;
33863  int horrors;
33864 
33865  if (!b->quiet) {
33866  printf(" Checking Delaunay property of the mesh...\n");
33867  }
33868  horrors = 0;
33869  // Run through the list of triangles, checking each one.
33870  tetrahedrons->traversalinit();
33871  tetraloop.tet = tetrahedrontraverse();
33872  while (tetraloop.tet != (tetrahedron *) NULL) {
33873  // Check all four faces of the tetrahedron.
33874  for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) {
33875  tetorg = org(tetraloop);
33876  tetdest = dest(tetraloop);
33877  tetapex = apex(tetraloop);
33878  tetoppo = oppo(tetraloop);
33879  sym(tetraloop, oppotet);
33880  oppooppo = oppo(oppotet);
33881  // Only do testif there is an adjoining tetrahedron whose pointer is
33882  // larger (to ensure that each pair isn't tested twice).
33883  shouldbedelaunay = (oppotet.tet != dummytet)
33884  && (tetoppo != (point) NULL)
33885  && (oppooppo != (point) NULL)
33886  && (tetraloop.tet < oppotet.tet);
33887  if (checksubfaces && shouldbedelaunay) {
33888  // If a shell face separates the tetrahedra, then the face is
33889  // constrained, so no local Delaunay test should be done.
33890  tspivot(tetraloop, opposhelle);
33891  if (opposhelle.sh != dummysh){
33892  shouldbedelaunay = 0;
33893  }
33894  }
33895  if (shouldbedelaunay) {
33896  sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo);
33897  if ((sign > 0.0) && (eps > 0.0)) {
33898  if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, sign,
33899  eps)) sign = 0.0;
33900  }
33901  if (sign > 0.0) {
33902  if (flipqueue) {
33903  enqueueflipface(tetraloop, flipqueue);
33904  } else {
33905  printf(" !! Non-locally Delaunay face (%d, %d, %d) ",
33906  pointmark(tetorg), pointmark(tetdest), pointmark(tetapex));
33907  fc = categorizeface(tetraloop);
33908  switch (fc) {
33909  case T23: printf("\"T23\""); break;
33910  case T32: printf("\"T32\""); break;
33911  case T22: printf("\"T22\""); break;
33912  case T44: printf("\"T44\""); break;
33913  case N32: printf("\"N32\""); break;
33914  case N40: printf("\"N40\""); break;
33915  case FORBIDDENFACE:printf("\"FORBIDDENFACE\""); break;
33916  case FORBIDDENEDGE:printf("\"FORBIDDENEDGE\""); break;
33917  }
33918  printf("\n");
33919  }
33920  horrors++;
33921  }
33922  }
33923  }
33924  tetraloop.tet = tetrahedrontraverse();
33925  }
33926  if (flipqueue == (queue *) NULL) {
33927  if (horrors == 0) {
33928  if (!b->quiet) {
33929  printf(" The mesh is %s.\n",
33930  checksubfaces ? "constrained Delaunay" : "Delaunay");
33931  }
33932  } else {
33933  printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors);
33934  }
33935  }
33936 }
33937 
33939 // //
33940 // checkconforming() Ensure that the mesh is conforming Delaunay. //
33941 // //
33943 
33944 void tetgenmesh::checkconforming()
33945 {
33946  face segloop, shloop;
33947  int encsubsegs, encsubfaces;
33948 
33949  if (!b->quiet) {
33950  printf(" Checking conforming Delaunay property of mesh...\n");
33951  }
33952  encsubsegs = encsubfaces = 0;
33953  // Run through the list of subsegments, check each one.
33954  subsegs->traversalinit();
33955  segloop.sh = shellfacetraverse(subsegs);
33956  while (segloop.sh != (shellface *) NULL) {
33957  if (checkseg4encroach(&segloop, NULL, NULL, false)) {
33958  printf(" !! !! Non-conforming subsegment: (%d, %d)\n",
33959  pointmark(sorg(segloop)), pointmark(sdest(segloop)));
33960  encsubsegs++;
33961  }
33962  segloop.sh = shellfacetraverse(subsegs);
33963  }
33964  // Run through the list of subfaces, check each one.
33965  subfaces->traversalinit();
33966  shloop.sh = shellfacetraverse(subfaces);
33967  while (shloop.sh != (shellface *) NULL) {
33968  if (checksub4encroach(&shloop, NULL, false)) {
33969  printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
33970  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
33971  pointmark(sapex(shloop)));
33972  encsubfaces++;
33973  }
33974  shloop.sh = shellfacetraverse(subfaces);
33975  }
33976  if (encsubsegs == 0 && encsubfaces == 0) {
33977  if (!b->quiet) {
33978  printf(" The mesh is conforming Delaunay.\n");
33979  }
33980  } else {
33981  if (encsubsegs > 0) {
33982  printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
33983  }
33984  if (encsubfaces > 0) {
33985  printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
33986  }
33987  }
33988 }
33989 
33991 // //
33992 // algorithmicstatistics() Print statistics about the mesh algorithms. //
33993 // //
33995 
33996 #ifdef SELF_CHECK
33997 
33998 void tetgenmesh::algorithmicstatistics()
33999 {
34000  /*
34001  printf("Algorithmic statistics:\n\n");
34002  printf(" Point location millisecond: %g\n", (REAL) tloctime * 1e+3);
34003  printf(" Flip millisecond: %g\n", (REAL) tfliptime * 1e+3);
34004  if (b->plc || b->refine) {
34005  printf(" Number of facet above points calculations: %ld\n", abovecount);
34006  }
34007  if (b->plc) {
34008  printf(" Segment split rules: R1 %ld, R2 %ld, R3 %ld\n", r1count, r2count,
34009  r3count);
34010  }
34011  if (b->quality) {
34012  printf(" Bowyer-Watson insertions: seg %ld, sub %ld, vol %ld.\n",
34013  bowatsegcount, bowatsubcount, bowatvolcount);
34014  printf(" Bowyer-Watson corrections: seg %ld, sub %ld, vol %ld\n",
34015  updsegcount, updsubcount, updvolcount);
34016  printf(" Bowyer-Watson failures: seg %ld, sub %ld, vol %ld\n",
34017  failsegcount, failsubcount, failvolcount);
34018  printf(" Number of repair flips: %ld.\n", repairflipcount);
34019  printf(" Number of circumcenters outside Bowat-cav.: %ld.\n",
34020  outbowatcircumcount);
34021  if (b->conformdel) {
34022  printf(" Segment split rules: R2 %ld, R3 %ld\n", r2count, r3count);
34023  printf(" Number of CDT enforcement points: %ld.\n", cdtenforcesegpts);
34024  }
34025  printf(" Number of Rejections: seg %ld, sub %ld, tet %ld.\n", rejsegpts,
34026  rejsubpts, rejtetpts);
34027  if (b->optlevel) {
34028  printf(
34029  " Optimization flips: f32 %ld, f44 %ld, f56 %ld, f68 %ld, fnm %ld.\n",
34030  optcount[3], optcount[4], optcount[5], optcount[6], optcount[9]);
34031  printf(" Optimization segment deletions: %ld.\n", optcount[1]);
34032  }
34033  }
34034  printf("\n");
34035  */
34036 }
34037 
34038 #endif // #ifdef SELF_CHECK
34039 
34041 // //
34042 // qualitystatistics() Print statistics about the quality of the mesh. //
34043 // //
34045 
34046 void tetgenmesh::qualitystatistics()
34047 {
34048  triface tetloop, neightet;
34049  point p[4];
34050  char sbuf[128];
34051  REAL radiusratiotable[12];
34052  REAL aspectratiotable[12];
34053  REAL A[4][4], rhs[4], D;
34054  REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
34055  REAL edgelength[6], alldihed[6], faceangle[3];
34056  REAL shortest, longest;
34057  REAL smallestvolume, biggestvolume;
34058  REAL smallestdiangle, biggestdiangle;
34059  REAL smallestfaangle, biggestfaangle;
34060  REAL tetvol, minaltitude;
34061  REAL cirradius, minheightinv; // insradius;
34062  REAL shortlen, longlen;
34063  REAL tetaspect, tetradius;
34064  REAL smalldiangle, bigdiangle;
34065  REAL smallfaangle, bigfaangle;
34066  int radiustable[12];
34067  int aspecttable[16];
34068  int dihedangletable[18];
34069  int faceangletable[18];
34070  int indx[4];
34071  int radiusindex;
34072  int aspectindex;
34073  int tendegree;
34074  int i, j;
34075 
34076  smallfaangle = 0.0;
34077  bigfaangle = 0.0;
34078 
34079  printf("Mesh quality statistics:\n\n");
34080 
34081  // Avoid compile warnings.
34082  shortlen = longlen = 0.0;
34083  smalldiangle = bigdiangle = 0.0;
34084 
34085  radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
34086  radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
34087  radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
34088  radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
34089  radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
34090  radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
34091 
34092  aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
34093  aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
34094  aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
34095  aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
34096  aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
34097  aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
34098 
34099  for (i = 0; i < 12; i++) radiustable[i] = 0;
34100  for (i = 0; i < 12; i++) aspecttable[i] = 0;
34101  for (i = 0; i < 18; i++) dihedangletable[i] = 0;
34102  for (i = 0; i < 18; i++) faceangletable[i] = 0;
34103 
34104  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
34105  minaltitude = minaltitude * minaltitude;
34106  shortest = minaltitude;
34107  longest = 0.0;
34108  smallestvolume = minaltitude;
34109  biggestvolume = 0.0;
34110  smallestdiangle = smallestfaangle = 180.0;
34111  biggestdiangle = biggestfaangle = 0.0;
34112 
34113  // Loop all elements, calculate quality parameters for each element.
34114  tetrahedrons->traversalinit();
34115  tetloop.tet = tetrahedrontraverse();
34116  while (tetloop.tet != (tetrahedron *) NULL) {
34117 
34118  // Get four vertices: p0, p1, p2, p3.
34119  for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
34120  // Set the edge vectors: V[0], ..., V[5]
34121  for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
34122  for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
34123  for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
34124  for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
34125  for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
34126  for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
34127  // Set the matrix A = [V[0], V[1], V[2]]^T.
34128  for (j = 0; j < 3; j++) {
34129  for (i = 0; i < 3; i++) A[j][i] = V[j][i];
34130  }
34131  // Decompose A just once.
34132  lu_decmp(A, 3, indx, &D, 0);
34133  // Get the tet volume.
34134  tetvol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
34135  // Get the three faces normals.
34136  for (j = 0; j < 3; j++) {
34137  for (i = 0; i < 3; i++) rhs[i] = 0.0;
34138  rhs[j] = 1.0; // Positive means the inside direction
34139  lu_solve(A, 3, indx, rhs, 0);
34140  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
34141  }
34142  // Get the fourth face normal by summing up the first three.
34143  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
34144  // Get the radius of the circumsphere.
34145  for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
34146  lu_solve(A, 3, indx, rhs, 0);
34147  cirradius = sqrt(dot(rhs, rhs));
34148  // Normalize the face normals.
34149  for (i = 0; i < 4; i++) {
34150  // H[i] is the inverse of height of its corresponding face.
34151  H[i] = sqrt(dot(N[i], N[i]));
34152  for (j = 0; j < 3; j++) N[i][j] /= H[i];
34153  }
34154  // Get the radius of the inscribed sphere.
34155  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
34156  // Get the biggest H[i] (corresponding to the smallest height).
34157  minheightinv = H[0];
34158  for (i = 1; i < 3; i++) {
34159  if (H[i] > minheightinv) minheightinv = H[i];
34160  }
34161  // Get the squares of the edge lengthes.
34162  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
34163  // Get the dihedrals (in degree) at each edges.
34164  j = 0;
34165  for (i = 1; i < 4; i++) {
34166  alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
34167  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34168  else if (alldihed[j] > 1.0) alldihed[j] = 1;
34169  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34170  j++;
34171  }
34172  for (i = 2; i < 4; i++) {
34173  alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
34174  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34175  else if (alldihed[j] > 1.0) alldihed[j] = 1;
34176  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34177  j++;
34178  }
34179  alldihed[j] = -dot(N[2], N[3]); // Edge ab.
34180  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
34181  else if (alldihed[j] > 1.0) alldihed[j] = 1;
34182  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
34183 
34184  // Calculate the longest and shortest edge length.
34185  for (i = 0; i < 6; i++) {
34186  if (i == 0) {
34187  shortlen = longlen = edgelength[i];
34188  } else {
34189  shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
34190  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
34191  }
34192  if (edgelength[i] > longest) {
34193  longest = edgelength[i];
34194  }
34195  if (edgelength[i] < shortest) {
34196  shortest = edgelength[i];
34197  }
34198  }
34199 
34200  // Calculate the largest and smallest volume.
34201  if (tetvol < smallestvolume) {
34202  smallestvolume = tetvol;
34203  }
34204  if (tetvol > biggestvolume) {
34205  biggestvolume = tetvol;
34206  }
34207 
34208  // Calculate the largest and smallest dihedral angles.
34209  for (i = 0; i < 6; i++) {
34210  if (i == 0) {
34211  smalldiangle = bigdiangle = alldihed[i];
34212  } else {
34213  smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
34214  bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
34215  }
34216  if (alldihed[i] < smallestdiangle) {
34217  smallestdiangle = alldihed[i];
34218  }
34219  if (alldihed[i] > biggestdiangle) {
34220  biggestdiangle = alldihed[i];
34221  }
34222  }
34223  // Accumulate the corresponding number in the dihedral angle histogram.
34224  if (smalldiangle < 5.0) {
34225  tendegree = 0;
34226  } else if (smalldiangle >= 5.0 && smalldiangle < 10.0) {
34227  tendegree = 1;
34228  } else if (smalldiangle >= 80.0 && smalldiangle < 110.0) {
34229  tendegree = 9; // Angles between 80 to 110 degree are in one entry.
34230  } else {
34231  tendegree = (int) (smalldiangle / 10.);
34232  if (smalldiangle < 80.0) {
34233  tendegree++; // In the left column.
34234  } else {
34235  tendegree--; // In the right column.
34236  }
34237  }
34238  dihedangletable[tendegree]++;
34239  if (bigdiangle >= 80.0 && bigdiangle < 110.0) {
34240  tendegree = 9; // Angles between 80 to 110 degree are in one entry.
34241  } else if (bigdiangle >= 170.0 && bigdiangle < 175.0) {
34242  tendegree = 16;
34243  } else if (bigdiangle >= 175.0) {
34244  tendegree = 17;
34245  } else {
34246  tendegree = (int) (bigdiangle / 10.);
34247  if (bigdiangle < 80.0) {
34248  tendegree++; // In the left column.
34249  } else {
34250  tendegree--; // In the right column.
34251  }
34252  }
34253  dihedangletable[tendegree]++;
34254 
34255  // Calulate the largest and smallest face angles.
34256  tetloop.ver = 0;
34257  for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) {
34258  sym(tetloop, neightet);
34259  // Only do the calulation once for a face.
34260  if ((neightet.tet == dummytet) || (tetloop.tet < neightet.tet)) {
34261  p[0] = org(tetloop);
34262  p[1] = dest(tetloop);
34263  p[2] = apex(tetloop);
34264  faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
34265  faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
34266  faceangle[2] = PI - (faceangle[0] + faceangle[1]);
34267  // Translate angles into degrees.
34268  for (i = 0; i < 3; i++) {
34269  faceangle[i] = (faceangle[i] * 180.0) / PI;
34270  }
34271  // Calculate the largest and smallest face angles.
34272  for (i = 0; i < 3; i++) {
34273  if (i == 0) {
34274  smallfaangle = bigfaangle = faceangle[i];
34275  } else {
34276  smallfaangle = faceangle[i] < smallfaangle ?
34277  faceangle[i] : smallfaangle;
34278  bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
34279  }
34280  if (faceangle[i] < smallestfaangle) {
34281  smallestfaangle = faceangle[i];
34282  }
34283  if (faceangle[i] > biggestfaangle) {
34284  biggestfaangle = faceangle[i];
34285  }
34286  }
34287  tendegree = (int) (smallfaangle / 10.);
34288  faceangletable[tendegree]++;
34289  tendegree = (int) (bigfaangle / 10.);
34290  faceangletable[tendegree]++;
34291  }
34292  }
34293 
34294  // Calculate aspect ratio and radius-edge ratio for this element.
34295  tetradius = cirradius / sqrt(shortlen);
34296  // tetaspect = sqrt(longlen) / (2.0 * insradius);
34297  tetaspect = sqrt(longlen) * minheightinv;
34298  aspectindex = 0;
34299  while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
34300  aspectindex++;
34301  }
34302  aspecttable[aspectindex]++;
34303  radiusindex = 0;
34304  while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
34305  radiusindex++;
34306  }
34307  radiustable[radiusindex]++;
34308 
34309  tetloop.tet = tetrahedrontraverse();
34310  }
34311 
34312  shortest = sqrt(shortest);
34313  longest = sqrt(longest);
34314  minaltitude = sqrt(minaltitude);
34315 
34316  printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
34317  smallestvolume, biggestvolume);
34318  printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
34319  shortest, longest);
34320  sprintf(sbuf, "%.17g", biggestfaangle);
34321  if (strlen(sbuf) > 8) {
34322  sbuf[8] = '\0';
34323  }
34324  printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
34325  smallestfaangle, sbuf);
34326  sprintf(sbuf, "%.17g", biggestdiangle);
34327  if (strlen(sbuf) > 8) {
34328  sbuf[8] = '\0';
34329  }
34330  printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
34331  smallestdiangle, sbuf);
34332 
34333  /*
34334  printf(" Radius-edge ratio histogram:\n");
34335  printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34336  radiusratiotable[0], radiustable[0], radiusratiotable[5],
34337  radiusratiotable[6], radiustable[6]);
34338  for (i = 1; i < 5; i++) {
34339  printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34340  radiusratiotable[i - 1], radiusratiotable[i], radiustable[i],
34341  radiusratiotable[i + 5], radiusratiotable[i + 6],
34342  radiustable[i + 6]);
34343  }
34344  printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n",
34345  radiusratiotable[4], radiusratiotable[5], radiustable[5],
34346  radiusratiotable[10], radiustable[11]);
34347  printf(" (A tetrahedron's radius-edge ratio is its radius of ");
34348  printf("circumsphere divided\n");
34349  printf(" by its shortest edge length)\n\n");
34350  */
34351 
34352  printf(" Aspect ratio histogram:\n");
34353  printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34354  aspectratiotable[0], aspecttable[0], aspectratiotable[5],
34355  aspectratiotable[6], aspecttable[6]);
34356  for (i = 1; i < 5; i++) {
34357  printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n",
34358  aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
34359  aspectratiotable[i + 5], aspectratiotable[i + 6],
34360  aspecttable[i + 6]);
34361  }
34362  printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n",
34363  aspectratiotable[4], aspectratiotable[5], aspecttable[5],
34364  aspectratiotable[10], aspecttable[11]);
34365  printf(" (A tetrahedron's aspect ratio is its longest edge length");
34366  printf(" divided by its\n");
34367  printf(" smallest side height)\n\n");
34368 
34369  printf(" Face angle histogram:\n");
34370  for (i = 0; i < 9; i++) {
34371  printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n",
34372  i * 10, i * 10 + 10, faceangletable[i],
34373  i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
34374  }
34375  if (minfaceang != PI) {
34376  printf(" Minimum input face angle is %g (degree).\n",
34377  minfaceang / PI * 180.0);
34378  }
34379  printf("\n");
34380 
34381  printf(" Dihedral angle histogram:\n");
34382  // Print the three two rows:
34383  printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34384  0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
34385  printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34386  5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
34387  // Print the third to seventh rows.
34388  for (i = 2; i < 7; i++) {
34389  printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34390  (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
34391  (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
34392  }
34393  // Print the last two rows.
34394  printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34395  60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
34396  printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n",
34397  70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
34398  if (minfacetdihed != PI) {
34399  printf(" Minimum input facet dihedral angle is %g (degree).\n",
34400  minfacetdihed / PI * 180.0);
34401  }
34402  printf("\n");
34403 }
34404 
34406 // //
34407 // statistics() Print all sorts of cool facts. //
34408 // //
34410 
34411 void tetgenmesh::statistics()
34412 {
34413  printf("\nStatistics:\n\n");
34414  printf(" Input points: %d\n", in->numberofpoints + jettisoninverts);
34415  if (b->refine) {
34416  printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
34417  }
34418  if (b->plc) {
34419  printf(" Input facets: %d\n", in->numberoffacets);
34420  printf(" Input segments: %ld\n", insegments);
34421  printf(" Input holes: %d\n", in->numberofholes);
34422  printf(" Input regions: %d\n", in->numberofregions);
34423  }
34424 
34425  printf("\n Mesh points: %ld\n", points->items);
34426  printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items);
34427  if (b->plc || b->refine) {
34428  printf(" Mesh triangles: %ld\n", (4l*tetrahedrons->items+hullsize)/2l);
34429  }
34430  if (b->plc || b->refine) {
34431  printf(" Mesh subfaces: %ld\n", subfaces->items);
34432  printf(" Mesh subsegments: %ld\n\n", subsegs->items);
34433  } else {
34434  printf(" Convex hull triangles: %ld\n\n", hullsize);
34435  }
34436  if (b->verbose > 0) {
34437  qualitystatistics();
34438  unsigned long totalmeshbytes;
34439  printf("Memory allocation statistics:\n\n");
34440  printf(" Maximum number of vertices: %ld\n", points->maxitems);
34441  totalmeshbytes = points->maxitems * points->itembytes;
34442  printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
34443  totalmeshbytes += tetrahedrons->maxitems * tetrahedrons->itembytes;
34444  if (subfaces != (memorypool *) NULL) {
34445  printf(" Maximum number of subfaces: %ld\n", subfaces->maxitems);
34446  totalmeshbytes += subfaces->maxitems * subfaces->itembytes;
34447  }
34448  if (subsegs != (memorypool *) NULL) {
34449  printf(" Maximum number of segments: %ld\n", subsegs->maxitems);
34450  totalmeshbytes += subsegs->maxitems * subsegs->itembytes;
34451  }
34452  printf(" Approximate heap memory used by the mesh (K bytes): %g\n\n",
34453  (double) totalmeshbytes / 1024.0);
34454 #ifdef SELF_CHECK
34455  algorithmicstatistics();
34456 #endif
34457  }
34458 }
34459 
34460 //
34461 // End of user interaction routines
34462 //
34463 
34464 //
34465 // Begin of constructor and destructor of tetgenmesh
34466 //
34467 
34469 // //
34470 // ~tetgenmesh() Deallocte memory occupied by a tetgenmesh object. //
34471 // //
34473 
34474 tetgenmesh::~tetgenmesh()
34475 {
34476  bgm = (tetgenmesh *) NULL;
34477  in = (tetgenio *) NULL;
34478  b = (tetgenbehavior *) NULL;
34479 
34480  if (tetrahedrons != (memorypool *) NULL) {
34481  delete tetrahedrons;
34482  }
34483  if (subfaces != (memorypool *) NULL) {
34484  delete subfaces;
34485  }
34486  if (subsegs != (memorypool *) NULL) {
34487  delete subsegs;
34488  }
34489  if (points != (memorypool *) NULL) {
34490  delete points;
34491  }
34492  if (dummytetbase != (tetrahedron *) NULL) {
34493  delete [] dummytetbase;
34494  }
34495  if (dummyshbase != (shellface *) NULL) {
34496  delete [] dummyshbase;
34497  }
34498  if (facetabovepointarray != (point *) NULL) {
34499  delete [] facetabovepointarray;
34500  }
34501  if (highordertable != (point *) NULL) {
34502  delete [] highordertable;
34503  }
34504  if (subpbcgrouptable != (pbcdata *) NULL) {
34505  delete [] subpbcgrouptable;
34506  }
34507  if (segpbcgrouptable != (list *) NULL) {
34508  delete segpbcgrouptable;
34509  delete [] idx2segpglist;
34510  delete [] segpglist;
34511  }
34512 }
34513 
34515 // //
34516 // tetgenmesh() Initialize a tetgenmesh object. //
34517 // //
34519 
34520 tetgenmesh::tetgenmesh()
34521 {
34522  bgm = (tetgenmesh *) NULL;
34523  in = (tetgenio *) NULL;
34524  b = (tetgenbehavior *) NULL;
34525 
34526  tetrahedrons = (memorypool *) NULL;
34527  subfaces = (memorypool *) NULL;
34528  subsegs = (memorypool *) NULL;
34529  points = (memorypool *) NULL;
34530  badsubsegs = (memorypool *) NULL;
34531  badsubfaces = (memorypool *) NULL;
34532  badtetrahedrons = (memorypool *) NULL;
34533  flipstackers = (memorypool *) NULL;
34534 
34535  dummytet = (tetrahedron *) NULL;
34536  dummytetbase = (tetrahedron *) NULL;
34537  dummysh = (shellface *) NULL;
34538  dummyshbase = (shellface *) NULL;
34539 
34540  facetabovepointarray = (point *) NULL;
34541  abovepoint = (point) NULL;
34542  highordertable = (point *) NULL;
34543  subpbcgrouptable = (pbcdata *) NULL;
34544  segpbcgrouptable = (list *) NULL;
34545  idx2segpglist = (int *) NULL;
34546  segpglist = (int *) NULL;
34547 
34548  xmax = xmin = ymax = ymin = zmax = zmin = 0.0;
34549  longest = 0.0;
34550  hullsize = 0l;
34551  insegments = 0l;
34552  pointmtrindex = 0;
34553  pointmarkindex = 0;
34554  point2simindex = 0;
34555  point2pbcptindex = 0;
34556  highorderindex = 0;
34557  elemattribindex = 0;
34558  volumeboundindex = 0;
34559  shmarkindex = 0;
34560  areaboundindex = 0;
34561  checksubfaces = 0;
34562  checksubsegs = 0;
34563  checkpbcs = 0;
34564  varconstraint = 0;
34565  nonconvex = 0;
34566  dupverts = 0;
34567  unuverts = 0;
34568  relverts = 0;
34569  suprelverts = 0;
34570  collapverts = 0;
34571  unsupverts = 0;
34572  jettisoninverts = 0;
34573  symbolic = 1;
34574  samples = 0l;
34575  randomseed = 1l;
34576  macheps = 0.0;
34577  minfaceang = minfacetdihed = PI;
34578  maxcavfaces = maxcavverts = 0;
34579  expcavcount = 0;
34580  abovecount = 0l;
34581  bowatvolcount = bowatsubcount = bowatsegcount = 0l;
34582  updvolcount = updsubcount = updsegcount = 0l;
34583  repairflipcount = 0l;
34584  outbowatcircumcount = 0l;
34585  failvolcount = failsubcount = failsegcount = 0l;
34586  r1count = r2count = r3count = 0l;
34587  cdtenforcesegpts = 0l;
34588  rejsegpts = rejsubpts = rejtetpts = 0l;
34589  flip23s = flip32s = flip22s = flip44s = 0l;
34590  tloctime = tfliptime = 0.0;
34591 }
34592 
34593 //
34594 // End of constructor and destructor of tetgenmesh
34595 //
34596 
34597 //
34598 // End of class 'tetgenmesh' implementation.
34599 //
34600 
34602 // //
34603 // tetrahedralize() The interface for users using TetGen library to //
34604 // generate tetrahedral meshes with all features. //
34605 // //
34606 // The sequence is roughly as follows. Many of these steps can be skipped, //
34607 // depending on the command line switches. //
34608 // //
34609 // - Initialize constants and parse the command line. //
34610 // - Read the vertices from a file and either //
34611 // - tetrahedralize them (no -r), or //
34612 // - read an old mesh from files and reconstruct it (-r). //
34613 // - Insert the PLC segments and facets (-p). //
34614 // - Read the holes (-p), regional attributes (-pA), and regional volume //
34615 // constraints (-pa). Carve the holes and concavities, and spread the //
34616 // regional attributes and volume constraints. //
34617 // - Enforce the constraints on minimum quality bound (-q) and maximum //
34618 // volume (-a). Also enforce the conforming Delaunay property (-q and -a). //
34619 // - Promote the mesh's linear tetrahedra to higher order elements (-o). //
34620 // - Write the output files and print the statistics. //
34621 // - Check the consistency and Delaunay property of the mesh (-C). //
34622 // //
34624 
34625 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
34626  tetgenio *addin, tetgenio *bgmin)
34627 {
34628  tetgenmesh m;
34629  // Variables for timing the performance of TetGen (defined in time.h).
34630  clock_t tv[14];
34631 
34632  tv[0] = clock();
34633 
34634  m.b = b;
34635  m.in = in;
34636  m.macheps = exactinit();
34637  m.steinerleft = b->steiner;
34638  if (b->metric) {
34639  m.bgm = new tetgenmesh();
34640  m.bgm->b = b;
34641  m.bgm->in = bgmin;
34642  m.bgm->macheps = exactinit();
34643  }
34644  m.initializepools();
34645  m.transfernodes();
34646 
34647  tv[1] = clock();
34648 
34649  if (b->refine) {
34650  m.reconstructmesh();
34651  } else {
34652  m.delaunizevertices();
34653  }
34654 
34655  tv[2] = clock();
34656 
34657  if (!b->quiet) {
34658  if (b->refine) {
34659  printf("Mesh reconstruction seconds:");
34660  } else {
34661  printf("Delaunay seconds:");
34662  }
34663  printf(" %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC);
34664  }
34665 
34666  if (b->metric) {
34667  if (bgmin != (tetgenio *) NULL) {
34668  m.bgm->initializepools();
34669  m.bgm->transfernodes();
34670  m.bgm->reconstructmesh();
34671  } else {
34672  m.bgm->in = in;
34673  m.bgm->initializepools();
34674  m.duplicatebgmesh();
34675  }
34676  }
34677 
34678  tv[3] = clock();
34679 
34680  if (!b->quiet) {
34681  if (b->metric) {
34682  printf("Background mesh reconstruct seconds: %g\n",
34683  (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC);
34684  }
34685  }
34686 
34687  if (b->useshelles && !b->refine) {
34688  m.meshsurface();
34689  if (b->diagnose != 1) {
34690  m.markacutevertices(89.0);
34691  m.incrperturbvertices(b->epsilon);
34692  m.delaunizesegments();
34693  if (m.checkpbcs) {
34694  long oldnum;
34695  do {
34696  oldnum = m.points->items;
34697  m.incrperturbvertices(b->epsilon);
34698  if (m.points->items > oldnum) {
34699  oldnum = m.points->items;
34700  m.delaunizesegments();
34701  }
34702  } while (oldnum < m.points->items);
34703  }
34704  m.constrainedfacets();
34705  } else {
34706  m.detectinterfaces();
34707  }
34708  }
34709 
34710  tv[4] = clock();
34711 
34712  if (!b->quiet) {
34713  if (b->useshelles && !b->refine) {
34714  if (b->diagnose != 1) {
34715  printf("Segment and facet ");
34716  } else {
34717  printf("Intersection ");
34718  }
34719  printf("seconds: %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC);
34720  }
34721  }
34722 
34723  if (b->plc && !(b->diagnose == 1)) {
34724  m.carveholes();
34725  }
34726 
34727  tv[5] = clock();
34728 
34729  if (!b->quiet) {
34730  if (b->plc && !(b->diagnose == 1)) {
34731  printf("Hole seconds: %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC);
34732  }
34733  }
34734 
34735  if ((b->plc || b->refine) && !(b->diagnose == 1)) {
34736  m.optimizemesh(false);
34737  }
34738 
34739  tv[6] = clock();
34740 
34741  if (!b->quiet) {
34742  if ((b->plc || b->refine) && !(b->diagnose == 1)) {
34743  printf("Repair seconds: %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC);
34744  }
34745  }
34746 
34747  if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
34748  m.removesteiners(false);
34749  }
34750 
34751  tv[7] = clock();
34752 
34753  if (!b->quiet) {
34754  if ((b->plc && b->nobisect) && !(b->diagnose == 1)) {
34755  printf("Steiner removal seconds: %g\n",
34756  (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC);
34757  }
34758  }
34759 
34760  if (b->insertaddpoints && (addin != (tetgenio *) NULL)) {
34761  if (addin->numberofpoints > 0) {
34762  m.insertconstrainedpoints(addin);
34763  }
34764  }
34765 
34766  tv[8] = clock();
34767 
34768  if (!b->quiet) {
34769  if ((b->plc || b->refine) && (b->insertaddpoints)) {
34770  printf("Constrained points seconds: %g\n",
34771  (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC);
34772  }
34773  }
34774 
34775  if (b->metric) {
34776  m.interpolatesizemap();
34777  }
34778 
34779  tv[9] = clock();
34780 
34781  if (!b->quiet) {
34782  if (b->metric) {
34783  printf("Size interpolating seconds: %g\n",
34784  (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC);
34785  }
34786  }
34787 
34788  if (b->coarse) {
34789  m.removesteiners(true);
34790  }
34791 
34792  tv[10] = clock();
34793 
34794  if (!b->quiet) {
34795  if (b->coarse) {
34796  printf("Mesh coarsening seconds: %g\n",
34797  (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC);
34798  }
34799  }
34800 
34801  if (b->quality) {
34802  m.enforcequality();
34803  }
34804 
34805  tv[11] = clock();
34806 
34807  if (!b->quiet) {
34808  if (b->quality) {
34809  printf("Quality seconds: %g\n",
34810  (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC);
34811  }
34812  }
34813 
34814  if (b->quality && (b->optlevel > 0)) {
34815  m.optimizemesh(true);
34816  }
34817 
34818  tv[12] = clock();
34819 
34820  if (!b->quiet) {
34821  if (b->quality && (b->optlevel > 0)) {
34822  printf("Optimize seconds: %g\n",
34823  (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC);
34824  }
34825  }
34826 
34827  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
34828  || (b->refine && (in->numberofcorners == 10)))) {
34829  m.jettisonnodes();
34830  }
34831 
34832  if (b->order > 1) {
34833  m.highorder();
34834  }
34835 
34836  if (!b->quiet) {
34837  printf("\n");
34838  }
34839 
34840  if (out != (tetgenio *) NULL) {
34841  out->firstnumber = in->firstnumber;
34842  out->mesh_dim = in->mesh_dim;
34843  }
34844 
34845  if (b->nonodewritten || b->noiterationnum) {
34846  if (!b->quiet) {
34847  printf("NOT writing a .node file.\n");
34848  }
34849  } else {
34850  if (b->diagnose == 1) {
34851  if (m.subfaces->items > 0l) {
34852  m.outnodes(out); // Only output when self-intersecting faces exist.
34853  }
34854  } else {
34855  m.outnodes(out);
34856  if (b->quality || b->metric) {
34857  // m.outmetrics(out);
34858  }
34859  }
34860  }
34861 
34862  if (b->noelewritten) {
34863  if (!b->quiet) {
34864  printf("NOT writing an .ele file.\n");
34865  }
34866  } else {
34867  if (!(b->diagnose == 1)) {
34868  if (m.tetrahedrons->items > 0l) {
34869  m.outelements(out);
34870  }
34871  }
34872  }
34873 
34874  if (b->nofacewritten) {
34875  if (!b->quiet) {
34876  printf("NOT writing an .face file.\n");
34877  }
34878  } else {
34879  if (b->facesout) {
34880  if (m.tetrahedrons->items > 0l) {
34881  m.outfaces(out); // Output all faces.
34882  }
34883  } else {
34884  if (b->diagnose == 1) {
34885  if (m.subfaces->items > 0l) {
34886  m.outsubfaces(out); // Only output self-intersecting faces.
34887  }
34888  } else if (b->plc || b->refine) {
34889  if (m.subfaces->items > 0l) {
34890  m.outsubfaces(out); // Output boundary faces.
34891  }
34892  } else {
34893  if (m.tetrahedrons->items > 0l) {
34894  m.outhullfaces(out); // Output convex hull faces.
34895  }
34896  }
34897  }
34898  }
34899 
34900  if (m.checkpbcs) {
34901  m.outpbcnodes(out);
34902  }
34903 
34904  if (b->edgesout) {
34905  if (b->edgesout > 1) {
34906  m.outedges(out); // -ee, output all mesh edges.
34907  } else {
34908  m.outsubsegments(out); // -e, only output subsegments.
34909  }
34910  }
34911 
34912  if (!out && b->plc &&
34913  ((b->object == tetgenbehavior::OFF) ||
34914  (b->object == tetgenbehavior::PLY) ||
34915  (b->object == tetgenbehavior::STL))) {
34916  m.outsmesh(b->outfilename);
34917  }
34918 
34919  if (!out && b->meditview) {
34920  m.outmesh2medit(b->outfilename);
34921  }
34922 
34923  if (!out && b->gidview) {
34924  m.outmesh2gid(b->outfilename);
34925  }
34926 
34927  if (!out && b->geomview) {
34928  m.outmesh2off(b->outfilename);
34929  }
34930 
34931  if (b->neighout) {
34932  m.outneighbors(out);
34933  }
34934 
34935  if (b->voroout) {
34936  m.outvoronoi(out);
34937  }
34938 
34939  tv[13] = clock();
34940 
34941  if (!b->quiet) {
34942  printf("\nOutput seconds: %g\n",
34943  (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC);
34944  printf("Total running seconds: %g\n",
34945  (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC);
34946  }
34947 
34948  if (b->docheck) {
34949  m.checkmesh();
34950  if (m.checksubfaces) {
34951  m.checkshells();
34952  }
34953  if (b->docheck > 1) {
34954  m.checkdelaunay(0.0, NULL);
34955  if (b->docheck > 2) {
34956  if (b->quality || b->refine) {
34957  m.checkconforming();
34958  }
34959  }
34960  }
34961  }
34962 
34963  if (!b->quiet) {
34964  m.statistics();
34965  }
34966 
34967  if (b->metric) {
34968  delete m.bgm;
34969  }
34970 }
34971 
34972 #ifndef TETLIBRARY
34973 
34975 // //
34976 // main() The entrance for running TetGen from command line. //
34977 // //
34979 
34980 int main(int argc, char *argv[])
34981 
34982 #else // with TETLIBRARY
34983 
34985 // //
34986 // tetrahedralize() The entrance for calling TetGen from another program. //
34987 // //
34989 
34990 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
34991  tetgenio *addin, tetgenio *bgmin)
34992 
34993 #endif // not TETLIBRARY
34994 
34995 {
34996  tetgenbehavior b;
34997 
34998 #ifndef TETLIBRARY
34999 
35000  tetgenio in, addin, bgmin;
35001 
35002  if (!b.parse_commandline(argc, argv)) {
35003  terminatetetgen(1);
35004  }
35005  if (b.refine) {
35006  if (!in.load_tetmesh(b.infilename)) {
35007  terminatetetgen(1);
35008  }
35009  } else {
35010  if (!in.load_plc(b.infilename, (int) b.object)) {
35011  terminatetetgen(1);
35012  }
35013  }
35014  if (b.insertaddpoints) {
35015  if (!addin.load_node(b.addinfilename)) {
35016  addin.numberofpoints = 0l;
35017  }
35018  }
35019  if (b.metric) {
35020  if (!bgmin.load_tetmesh(b.bgmeshfilename)) {
35021  bgmin.numberoftetrahedra = 0l;
35022  }
35023  }
35024 
35025  if (bgmin.numberoftetrahedra > 0l) {
35026  tetrahedralize(&b, &in, NULL, &addin, &bgmin);
35027  } else {
35028  tetrahedralize(&b, &in, NULL, &addin, NULL);
35029  }
35030 
35031  return 0;
35032 
35033 #else // with TETLIBRARY
35034 
35035  if (!b.parse_commandline(switches)) {
35036  terminatetetgen(1);
35037  }
35038  tetrahedralize(&b, in, out, addin, bgmin);
35039 
35040 #endif // not TETLIBRARY
35041 }
35042 
35043 } //Added namespace to avoid clash with triangle
35044 
35045 #ifndef TETLIBRARY
35046 // Shim for entry point to main inside the namespace. This is just in case we want to compile up a binary from this
35047 // source code.
35048 int main(int argc, char *argv[])
35049 {
35050  tetgen::main(argc, argv);
35051 }
35052 #endif // not TETLIBRARY
#define UNUSED_OPT(var)
Definition: Exception.hpp:216
for(i=STARTINDEX;i< argc;i++)
Definition: triangle.cpp:3406