EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tetgen.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file tetgen.cxx
1 
2 // //
3 // TetGen //
4 // //
5 // A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
6 // //
7 // Version 1.5 //
8 // November 4, 2013 //
9 // //
10 // TetGen is freely available through the website: http://www.tetgen.org. //
11 // It may be copied, modified, and redistributed for non-commercial use. //
12 // Please consult the file LICENSE for the detailed copyright notices. //
13 // //
15 
16 #include "tetgen.h"
17 
21 
23 // //
24 // load_node_call() Read a list of points from a file. //
25 // //
26 // 'infile' is the file handle contains the node list. It may point to a //
27 // .node, or .poly or .smesh file. 'markers' indicates each node contains an //
28 // additional marker (integer) or not. 'uvflag' indicates each node contains //
29 // u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
30 // of the file being read, it is only used in error messages. //
31 // //
32 // The 'firstnumber' (0 or 1) is automatically determined by the number of //
33 // the first index of the first point. //
34 // //
36 
37 bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
38  char* infilename)
39 {
40  char inputline[INPUTLINESIZE];
41  char *stringptr;
42  REAL x, y, z, attrib;
43  int firstnode, currentmarker;
44  int index, attribindex;
45  int i, j;
46 
47  // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
48  pointlist = new REAL[numberofpoints * 3];
49  if (pointlist == (REAL *) NULL) {
50  terminatetetgen(NULL, 1);
51  }
52  if (numberofpointattributes > 0) {
54  if (pointattributelist == (REAL *) NULL) {
55  terminatetetgen(NULL, 1);
56  }
57  }
58  if (markers) {
60  if (pointmarkerlist == (int *) NULL) {
61  terminatetetgen(NULL, 1);
62  }
63  }
64  if (uvflag) {
66  if (pointparamlist == NULL) {
67  terminatetetgen(NULL, 1);
68  }
69  }
70 
71  // Read the point section.
72  index = 0;
73  attribindex = 0;
74  for (i = 0; i < numberofpoints; i++) {
75  stringptr = readnumberline(inputline, infile, infilename);
76  if (useindex) {
77  if (i == 0) {
78  firstnode = (int) strtol (stringptr, &stringptr, 0);
79  if ((firstnode == 0) || (firstnode == 1)) {
80  firstnumber = firstnode;
81  }
82  }
83  stringptr = findnextnumber(stringptr);
84  } // if (useindex)
85  if (*stringptr == '\0') {
86  printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
87  break;
88  }
89  x = (REAL) strtod(stringptr, &stringptr);
90  stringptr = findnextnumber(stringptr);
91  if (*stringptr == '\0') {
92  printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
93  break;
94  }
95  y = (REAL) strtod(stringptr, &stringptr);
96  if (mesh_dim == 3) {
97  stringptr = findnextnumber(stringptr);
98  if (*stringptr == '\0') {
99  printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
100  break;
101  }
102  z = (REAL) strtod(stringptr, &stringptr);
103  } else {
104  z = 0.0; // mesh_dim == 2;
105  }
106  pointlist[index++] = x;
107  pointlist[index++] = y;
108  pointlist[index++] = z;
109  // Read the point attributes.
110  for (j = 0; j < numberofpointattributes; j++) {
111  stringptr = findnextnumber(stringptr);
112  if (*stringptr == '\0') {
113  attrib = 0.0;
114  } else {
115  attrib = (REAL) strtod(stringptr, &stringptr);
116  }
117  pointattributelist[attribindex++] = attrib;
118  }
119  if (markers) {
120  // Read a point marker.
121  stringptr = findnextnumber(stringptr);
122  if (*stringptr == '\0') {
123  currentmarker = 0;
124  } else {
125  currentmarker = (int) strtol (stringptr, &stringptr, 0);
126  }
127  pointmarkerlist[i] = currentmarker;
128  }
129  if (uvflag) {
130  // Read point paramteters.
131  stringptr = findnextnumber(stringptr);
132  if (*stringptr == '\0') {
133  printf("Error: Point %d has no uv[0].\n", firstnumber + i);
134  break;
135  }
136  pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
137  stringptr = findnextnumber(stringptr);
138  if (*stringptr == '\0') {
139  printf("Error: Point %d has no uv[1].\n", firstnumber + i);
140  break;
141  }
142  pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
143  stringptr = findnextnumber(stringptr);
144  if (*stringptr == '\0') {
145  printf("Error: Point %d has no tag.\n", firstnumber + i);
146  break;
147  }
148  pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
149  stringptr = findnextnumber(stringptr);
150  if (*stringptr == '\0') {
151  printf("Error: Point %d has no type.\n", firstnumber + i);
152  break;
153  }
154  pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
155  if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
156  printf("Error: Point %d has an invalid type.\n", firstnumber + i);
157  break;
158  }
159  }
160  }
161  if (i < numberofpoints) {
162  // Failed to read points due to some error.
163  delete [] pointlist;
164  pointlist = (REAL *) NULL;
165  if (markers) {
166  delete [] pointmarkerlist;
167  pointmarkerlist = (int *) NULL;
168  }
169  if (numberofpointattributes > 0) {
170  delete [] pointattributelist;
171  pointattributelist = (REAL *) NULL;
172  }
173  if (uvflag) {
174  delete [] pointparamlist;
175  pointparamlist = NULL;
176  }
177  numberofpoints = 0;
178  return false;
179  }
180  return true;
181 }
182 
184 // //
185 // load_node() Load a list of points from a .node file. //
186 // //
188 
189 bool tetgenio::load_node(char* filebasename)
190 {
191  FILE *infile;
192  char innodefilename[FILENAMESIZE];
193  char inputline[INPUTLINESIZE];
194  char *stringptr;
195  bool okflag;
196  int markers;
197  int uvflag; // for psc input.
198 
199  // Assembling the actual file names we want to open.
200  strcpy(innodefilename, filebasename);
201  strcat(innodefilename, ".node");
202 
203  // Try to open a .node file.
204  infile = fopen(innodefilename, "r");
205  if (infile == (FILE *) NULL) {
206  printf(" Cannot access file %s.\n", innodefilename);
207  return false;
208  }
209  printf("Opening %s.\n", innodefilename);
210 
211  // Set initial flags.
212  mesh_dim = 3;
213  numberofpointattributes = 0; // no point attribute.
214  markers = 0; // no boundary marker.
215  uvflag = 0; // no uv parameters (required by a PSC).
216 
217  // Read the first line of the file.
218  stringptr = readnumberline(inputline, infile, innodefilename);
219  // Does this file contain an index column?
220  stringptr = strstr(inputline, "rbox");
221  if (stringptr == NULL) {
222  // Read number of points, number of dimensions, number of point
223  // attributes, and number of boundary markers.
224  stringptr = inputline;
225  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
226  stringptr = findnextnumber(stringptr);
227  if (*stringptr != '\0') {
228  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
229  }
230  stringptr = findnextnumber(stringptr);
231  if (*stringptr != '\0') {
232  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
233  }
234  stringptr = findnextnumber(stringptr);
235  if (*stringptr != '\0') {
236  markers = (int) strtol (stringptr, &stringptr, 0);
237  }
238  stringptr = findnextnumber(stringptr);
239  if (*stringptr != '\0') {
240  uvflag = (int) strtol (stringptr, &stringptr, 0);
241  }
242  } else {
243  // It is a rbox (qhull) input file.
244  stringptr = inputline;
245  // Get the dimension.
246  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
247  // Get the number of points.
248  stringptr = readnumberline(inputline, infile, innodefilename);
249  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
250  // There is no index column.
251  useindex = 0;
252  }
253 
254  // Load the list of nodes.
255  okflag = load_node_call(infile, markers, uvflag, innodefilename);
256 
257  fclose(infile);
258  return okflag;
259 }
260 
262 // //
263 // load_edge() Load a list of edges from a .edge file. //
264 // //
266 
267 bool tetgenio::load_edge(char* filebasename)
268 {
269  FILE *infile;
270  char inedgefilename[FILENAMESIZE];
271  char inputline[INPUTLINESIZE];
272  char *stringptr;
273  int markers, corner;
274  int index;
275  int i, j;
276 
277  strcpy(inedgefilename, filebasename);
278  strcat(inedgefilename, ".edge");
279 
280  infile = fopen(inedgefilename, "r");
281  if (infile != (FILE *) NULL) {
282  printf("Opening %s.\n", inedgefilename);
283  } else {
284  //printf(" Cannot access file %s.\n", inedgefilename);
285  return false;
286  }
287 
288  // Read number of boundary edges.
289  stringptr = readnumberline(inputline, infile, inedgefilename);
290  numberofedges = (int) strtol (stringptr, &stringptr, 0);
291  if (numberofedges > 0) {
292  edgelist = new int[numberofedges * 2];
293  if (edgelist == (int *) NULL) {
294  terminatetetgen(NULL, 1);
295  }
296  stringptr = findnextnumber(stringptr);
297  if (*stringptr == '\0') {
298  markers = 0; // Default value.
299  } else {
300  markers = (int) strtol (stringptr, &stringptr, 0);
301  }
302  if (markers > 0) {
303  edgemarkerlist = new int[numberofedges];
304  }
305  }
306 
307  // Read the list of edges.
308  index = 0;
309  for (i = 0; i < numberofedges; i++) {
310  // Read edge index and the edge's two endpoints.
311  stringptr = readnumberline(inputline, infile, inedgefilename);
312  for (j = 0; j < 2; j++) {
313  stringptr = findnextnumber(stringptr);
314  if (*stringptr == '\0') {
315  printf("Error: Edge %d is missing vertex %d in %s.\n",
316  i + firstnumber, j + 1, inedgefilename);
317  terminatetetgen(NULL, 1);
318  }
319  corner = (int) strtol(stringptr, &stringptr, 0);
320  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
321  printf("Error: Edge %d has an invalid vertex index.\n",
322  i + firstnumber);
323  terminatetetgen(NULL, 1);
324  }
325  edgelist[index++] = corner;
326  }
327  if (numberofcorners == 10) {
328  // Skip an extra vertex (generated by a previous -o2 option).
329  stringptr = findnextnumber(stringptr);
330  }
331  // Read the edge marker if it has.
332  if (markers) {
333  stringptr = findnextnumber(stringptr);
334  edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
335  }
336  }
337 
338  fclose(infile);
339  return true;
340 }
341 
343 // //
344 // load_face() Load a list of faces (triangles) from a .face file. //
345 // //
347 
348 bool tetgenio::load_face(char* filebasename)
349 {
350  FILE *infile;
351  char infilename[FILENAMESIZE];
352  char inputline[INPUTLINESIZE];
353  char *stringptr;
354  REAL attrib;
355  int markers, corner;
356  int index;
357  int i, j;
358 
359  strcpy(infilename, filebasename);
360  strcat(infilename, ".face");
361 
362  infile = fopen(infilename, "r");
363  if (infile != (FILE *) NULL) {
364  printf("Opening %s.\n", infilename);
365  } else {
366  return false;
367  }
368 
369  // Read number of faces, boundary markers.
370  stringptr = readnumberline(inputline, infile, infilename);
371  numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
372  stringptr = findnextnumber(stringptr);
373  if (mesh_dim == 2) {
374  // Skip a number.
375  stringptr = findnextnumber(stringptr);
376  }
377  if (*stringptr == '\0') {
378  markers = 0; // Default there is no marker per face.
379  } else {
380  markers = (int) strtol (stringptr, &stringptr, 0);
381  }
382  if (numberoftrifaces > 0) {
383  trifacelist = new int[numberoftrifaces * 3];
384  if (trifacelist == (int *) NULL) {
385  terminatetetgen(NULL, 1);
386  }
387  if (markers) {
389  if (trifacemarkerlist == (int *) NULL) {
390  terminatetetgen(NULL, 1);
391  }
392  }
393  }
394 
395  // Read the list of faces.
396  index = 0;
397  for (i = 0; i < numberoftrifaces; i++) {
398  // Read face index and the face's three corners.
399  stringptr = readnumberline(inputline, infile, infilename);
400  for (j = 0; j < 3; j++) {
401  stringptr = findnextnumber(stringptr);
402  if (*stringptr == '\0') {
403  printf("Error: Face %d is missing vertex %d in %s.\n",
404  i + firstnumber, j + 1, infilename);
405  terminatetetgen(NULL, 1);
406  }
407  corner = (int) strtol(stringptr, &stringptr, 0);
408  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
409  printf("Error: Face %d has an invalid vertex index.\n",
410  i + firstnumber);
411  terminatetetgen(NULL, 1);
412  }
413  trifacelist[index++] = corner;
414  }
415  if (numberofcorners == 10) {
416  // Skip 3 extra vertices (generated by a previous -o2 option).
417  for (j = 0; j < 3; j++) {
418  stringptr = findnextnumber(stringptr);
419  }
420  }
421  // Read the boundary marker if it exists.
422  if (markers) {
423  stringptr = findnextnumber(stringptr);
424  if (*stringptr == '\0') {
425  attrib = 0.0;
426  } else {
427  attrib = (REAL) strtod(stringptr, &stringptr);
428  }
429  trifacemarkerlist[i] = (int) attrib;
430  }
431  }
432 
433  fclose(infile);
434 
435  return true;
436 }
437 
439 // //
440 // load_tet() Load a list of tetrahedra from a .ele file. //
441 // //
443 
444 bool tetgenio::load_tet(char* filebasename)
445 {
446  FILE *infile;
447  char infilename[FILENAMESIZE];
448  char inputline[INPUTLINESIZE];
449  char *stringptr;
450  REAL attrib;
451  int corner;
452  int index, attribindex;
453  int i, j;
454 
455  strcpy(infilename, filebasename);
456  strcat(infilename, ".ele");
457 
458  infile = fopen(infilename, "r");
459  if (infile != (FILE *) NULL) {
460  printf("Opening %s.\n", infilename);
461  } else {
462  return false;
463  }
464 
465  // Read number of elements, number of corners (4 or 10), number of
466  // element attributes.
467  stringptr = readnumberline(inputline, infile, infilename);
468  numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
469  if (numberoftetrahedra <= 0) {
470  printf("Error: Invalid number of tetrahedra.\n");
471  fclose(infile);
472  return false;
473  }
474  stringptr = findnextnumber(stringptr);
475  if (*stringptr == '\0') {
476  numberofcorners = 4; // Default read 4 nodes per element.
477  } else {
478  numberofcorners = (int) strtol(stringptr, &stringptr, 0);
479  }
480  stringptr = findnextnumber(stringptr);
481  if (*stringptr == '\0') {
482  numberoftetrahedronattributes = 0; // Default no attribute.
483  } else {
484  numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
485  }
486  if (numberofcorners != 4 && numberofcorners != 10) {
487  printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
489  fclose(infile);
490  return false;
491  }
492 
493  // Allocate memory for tetrahedra.
495  if (tetrahedronlist == (int *) NULL) {
496  terminatetetgen(NULL, 1);
497  }
498  // Allocate memory for output tetrahedron attributes if necessary.
502  if (tetrahedronattributelist == (REAL *) NULL) {
503  terminatetetgen(NULL, 1);
504  }
505  }
506 
507  // Read the list of tetrahedra.
508  index = 0;
509  attribindex = 0;
510  for (i = 0; i < numberoftetrahedra; i++) {
511  // Read tetrahedron index and the tetrahedron's corners.
512  stringptr = readnumberline(inputline, infile, infilename);
513  for (j = 0; j < numberofcorners; j++) {
514  stringptr = findnextnumber(stringptr);
515  if (*stringptr == '\0') {
516  printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
517  i + firstnumber, j + 1, infilename);
518  terminatetetgen(NULL, 1);
519  }
520  corner = (int) strtol(stringptr, &stringptr, 0);
521  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
522  printf("Error: Tetrahedron %d has an invalid vertex index.\n",
523  i + firstnumber);
524  terminatetetgen(NULL, 1);
525  }
526  tetrahedronlist[index++] = corner;
527  }
528  // Read the tetrahedron's attributes.
529  for (j = 0; j < numberoftetrahedronattributes; j++) {
530  stringptr = findnextnumber(stringptr);
531  if (*stringptr == '\0') {
532  attrib = 0.0;
533  } else {
534  attrib = (REAL) strtod(stringptr, &stringptr);
535  }
536  tetrahedronattributelist[attribindex++] = attrib;
537  }
538  }
539 
540  fclose(infile);
541 
542  return true;
543 }
544 
546 // //
547 // load_vol() Load a list of volume constraints from a .vol file. //
548 // //
550 
551 bool tetgenio::load_vol(char* filebasename)
552 {
553  FILE *infile;
554  char inelefilename[FILENAMESIZE];
555  char infilename[FILENAMESIZE];
556  char inputline[INPUTLINESIZE];
557  char *stringptr;
558  REAL volume;
559  int volelements;
560  int i;
561 
562  strcpy(infilename, filebasename);
563  strcat(infilename, ".vol");
564 
565  infile = fopen(infilename, "r");
566  if (infile != (FILE *) NULL) {
567  printf("Opening %s.\n", infilename);
568  } else {
569  return false;
570  }
571 
572  // Read number of tetrahedra.
573  stringptr = readnumberline(inputline, infile, infilename);
574  volelements = (int) strtol (stringptr, &stringptr, 0);
575  if (volelements != numberoftetrahedra) {
576  strcpy(inelefilename, filebasename);
577  strcat(infilename, ".ele");
578  printf("Warning: %s and %s disagree on number of tetrahedra.\n",
579  inelefilename, infilename);
580  fclose(infile);
581  return false;
582  }
583 
584  tetrahedronvolumelist = new REAL[volelements];
585  if (tetrahedronvolumelist == (REAL *) NULL) {
586  terminatetetgen(NULL, 1);
587  }
588 
589  // Read the list of volume constraints.
590  for (i = 0; i < volelements; i++) {
591  stringptr = readnumberline(inputline, infile, infilename);
592  stringptr = findnextnumber(stringptr);
593  if (*stringptr == '\0') {
594  volume = -1.0; // No constraint on this tetrahedron.
595  } else {
596  volume = (REAL) strtod(stringptr, &stringptr);
597  }
599  }
600 
601  fclose(infile);
602 
603  return true;
604 }
605 
607 // //
608 // load_var() Load constraints applied on facets, segments, and nodes //
609 // from a .var file. //
610 // //
612 
613 bool tetgenio::load_var(char* filebasename)
614 {
615  FILE *infile;
616  char varfilename[FILENAMESIZE];
617  char inputline[INPUTLINESIZE];
618  char *stringptr;
619  int index;
620  int i;
621 
622  // Variant constraints are saved in file "filename.var".
623  strcpy(varfilename, filebasename);
624  strcat(varfilename, ".var");
625  infile = fopen(varfilename, "r");
626  if (infile != (FILE *) NULL) {
627  printf("Opening %s.\n", varfilename);
628  } else {
629  return false;
630  }
631 
632  // Read the facet constraint section.
633  stringptr = readnumberline(inputline, infile, varfilename);
634  if (*stringptr != '\0') {
635  numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
636  } else {
638  }
639  if (numberoffacetconstraints > 0) {
640  // Initialize 'facetconstraintlist'.
642  index = 0;
643  for (i = 0; i < numberoffacetconstraints; i++) {
644  stringptr = readnumberline(inputline, infile, varfilename);
645  stringptr = findnextnumber(stringptr);
646  if (*stringptr == '\0') {
647  printf("Error: facet constraint %d has no facet marker.\n",
648  firstnumber + i);
649  break;
650  } else {
651  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
652  }
653  stringptr = findnextnumber(stringptr);
654  if (*stringptr == '\0') {
655  printf("Error: facet constraint %d has no maximum area bound.\n",
656  firstnumber + i);
657  break;
658  } else {
659  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
660  }
661  }
662  if (i < numberoffacetconstraints) {
663  // This must be caused by an error.
664  fclose(infile);
665  return false;
666  }
667  }
668 
669  // Read the segment constraint section.
670  stringptr = readnumberline(inputline, infile, varfilename);
671  if (*stringptr != '\0') {
672  numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
673  } else {
675  }
676  if (numberofsegmentconstraints > 0) {
677  // Initialize 'segmentconstraintlist'.
679  index = 0;
680  for (i = 0; i < numberofsegmentconstraints; i++) {
681  stringptr = readnumberline(inputline, infile, varfilename);
682  stringptr = findnextnumber(stringptr);
683  if (*stringptr == '\0') {
684  printf("Error: segment constraint %d has no frist endpoint.\n",
685  firstnumber + i);
686  break;
687  } else {
688  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
689  }
690  stringptr = findnextnumber(stringptr);
691  if (*stringptr == '\0') {
692  printf("Error: segment constraint %d has no second endpoint.\n",
693  firstnumber + i);
694  break;
695  } else {
696  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
697  }
698  stringptr = findnextnumber(stringptr);
699  if (*stringptr == '\0') {
700  printf("Error: segment constraint %d has no maximum length bound.\n",
701  firstnumber + i);
702  break;
703  } else {
704  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
705  }
706  }
707  if (i < numberofsegmentconstraints) {
708  // This must be caused by an error.
709  fclose(infile);
710  return false;
711  }
712  }
713 
714  fclose(infile);
715  return true;
716 }
717 
719 // //
720 // load_mtr() Load a size specification map from a .mtr file. //
721 // //
723 
724 bool tetgenio::load_mtr(char* filebasename)
725 {
726  FILE *infile;
727  char mtrfilename[FILENAMESIZE];
728  char inputline[INPUTLINESIZE];
729  char *stringptr;
730  REAL mtr;
731  int ptnum;
732  int mtrindex;
733  int i, j;
734 
735  strcpy(mtrfilename, filebasename);
736  strcat(mtrfilename, ".mtr");
737  infile = fopen(mtrfilename, "r");
738  if (infile != (FILE *) NULL) {
739  printf("Opening %s.\n", mtrfilename);
740  } else {
741  return false;
742  }
743 
744  // Read the number of points.
745  stringptr = readnumberline(inputline, infile, mtrfilename);
746  ptnum = (int) strtol (stringptr, &stringptr, 0);
747  if (ptnum != numberofpoints) {
748  printf(" !! Point numbers are not equal. Ignored.\n");
749  fclose(infile);
750  return false;
751  }
752  // Read the number of columns (1, 3, or 6).
753  stringptr = findnextnumber(stringptr); // Skip number of points.
754  if (*stringptr != '\0') {
755  numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
756  }
757  if (numberofpointmtrs == 0) {
758  // Column number doesn't match. Set a default number (1).
759  numberofpointmtrs = 1;
760  }
761 
762  // Allocate space for pointmtrlist.
764  if (pointmtrlist == (REAL *) NULL) {
765  terminatetetgen(NULL, 1);
766  }
767  mtrindex = 0;
768  for (i = 0; i < numberofpoints; i++) {
769  // Read metrics.
770  stringptr = readnumberline(inputline, infile, mtrfilename);
771  for (j = 0; j < numberofpointmtrs; j++) {
772  if (*stringptr == '\0') {
773  printf("Error: Metric %d is missing value #%d in %s.\n",
774  i + firstnumber, j + 1, mtrfilename);
775  terminatetetgen(NULL, 1);
776  }
777  mtr = (REAL) strtod(stringptr, &stringptr);
778  pointmtrlist[mtrindex++] = mtr;
779  stringptr = findnextnumber(stringptr);
780  }
781  }
782 
783  fclose(infile);
784  return true;
785 }
786 
788 // //
789 // load_poly() Load a PL complex from a .poly or a .smesh file. //
790 // //
792 
793 bool tetgenio::load_poly(char* filebasename)
794 {
795  FILE *infile;
796  char inpolyfilename[FILENAMESIZE];
797  char insmeshfilename[FILENAMESIZE];
798  char inputline[INPUTLINESIZE];
799  char *stringptr, *infilename;
800  int smesh, markers, uvflag, currentmarker;
801  int index;
802  int i, j, k;
803 
804  // Assembling the actual file names we want to open.
805  strcpy(inpolyfilename, filebasename);
806  strcpy(insmeshfilename, filebasename);
807  strcat(inpolyfilename, ".poly");
808  strcat(insmeshfilename, ".smesh");
809 
810  // First assume it is a .poly file.
811  smesh = 0;
812  // Try to open a .poly file.
813  infile = fopen(inpolyfilename, "r");
814  if (infile == (FILE *) NULL) {
815  // .poly doesn't exist! Try to open a .smesh file.
816  infile = fopen(insmeshfilename, "r");
817  if (infile == (FILE *) NULL) {
818  printf(" Cannot access file %s and %s.\n",
819  inpolyfilename, insmeshfilename);
820  return false;
821  } else {
822  printf("Opening %s.\n", insmeshfilename);
823  infilename = insmeshfilename;
824  }
825  smesh = 1;
826  } else {
827  printf("Opening %s.\n", inpolyfilename);
828  infilename = inpolyfilename;
829  }
830 
831  // Initialize the default values.
832  mesh_dim = 3; // Three-dimensional coordinates.
833  numberofpointattributes = 0; // no point attribute.
834  markers = 0; // no boundary marker.
835  uvflag = 0; // no uv parameters (required by a PSC).
836 
837  // Read number of points, number of dimensions, number of point
838  // attributes, and number of boundary markers.
839  stringptr = readnumberline(inputline, infile, infilename);
840  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
841  stringptr = findnextnumber(stringptr);
842  if (*stringptr != '\0') {
843  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
844  }
845  stringptr = findnextnumber(stringptr);
846  if (*stringptr != '\0') {
847  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
848  }
849  stringptr = findnextnumber(stringptr);
850  if (*stringptr != '\0') {
851  markers = (int) strtol (stringptr, &stringptr, 0);
852  }
853  if (*stringptr != '\0') {
854  uvflag = (int) strtol (stringptr, &stringptr, 0);
855  }
856 
857  if (numberofpoints > 0) {
858  // Load the list of nodes.
859  if (!load_node_call(infile, markers, uvflag, infilename)) {
860  fclose(infile);
861  return false;
862  }
863  } else {
864  // If the .poly or .smesh file claims there are zero points, that
865  // means the points should be read from a separate .node file.
866  if (!load_node(filebasename)) {
867  fclose(infile);
868  return false;
869  }
870  }
871 
872  if ((mesh_dim != 3) && (mesh_dim != 2)) {
873  printf("Input error: TetGen only works for 2D & 3D point sets.\n");
874  fclose(infile);
875  return false;
876  }
877  if (numberofpoints < (mesh_dim + 1)) {
878  printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
879  fclose(infile);
880  return false;
881  }
882 
883  facet *f;
884  polygon *p;
885 
886  if (mesh_dim == 3) {
887 
888  // Read number of facets and number of boundary markers.
889  stringptr = readnumberline(inputline, infile, infilename);
890  if (stringptr == NULL) {
891  // No facet list, return.
892  fclose(infile);
893  return true;
894  }
895  numberoffacets = (int) strtol (stringptr, &stringptr, 0);
896  if (numberoffacets <= 0) {
897  // No facet list, return.
898  fclose(infile);
899  return true;
900  }
901  stringptr = findnextnumber(stringptr);
902  if (*stringptr == '\0') {
903  markers = 0; // no boundary marker.
904  } else {
905  markers = (int) strtol (stringptr, &stringptr, 0);
906  }
907 
908  // Initialize the 'facetlist', 'facetmarkerlist'.
910  if (markers == 1) {
911  facetmarkerlist = new int[numberoffacets];
912  }
913 
914  // Read data into 'facetlist', 'facetmarkerlist'.
915  if (smesh == 0) {
916  // Facets are in .poly file format.
917  for (i = 1; i <= numberoffacets; i++) {
918  f = &(facetlist[i - 1]);
919  init(f);
920  f->numberofholes = 0;
921  currentmarker = 0;
922  // Read number of polygons, number of holes, and a boundary marker.
923  stringptr = readnumberline(inputline, infile, infilename);
924  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
925  stringptr = findnextnumber(stringptr);
926  if (*stringptr != '\0') {
927  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
928  if (markers == 1) {
929  stringptr = findnextnumber(stringptr);
930  if (*stringptr != '\0') {
931  currentmarker = (int) strtol(stringptr, &stringptr, 0);
932  }
933  }
934  }
935  // Initialize facetmarker if it needs.
936  if (markers == 1) {
937  facetmarkerlist[i - 1] = currentmarker;
938  }
939  // Each facet should has at least one polygon.
940  if (f->numberofpolygons <= 0) {
941  printf("Error: Wrong number of polygon in %d facet.\n", i);
942  break;
943  }
944  // Initialize the 'f->polygonlist'.
945  f->polygonlist = new polygon[f->numberofpolygons];
946  // Go through all polygons, read in their vertices.
947  for (j = 1; j <= f->numberofpolygons; j++) {
948  p = &(f->polygonlist[j - 1]);
949  init(p);
950  // Read number of vertices of this polygon.
951  stringptr = readnumberline(inputline, infile, infilename);
952  p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
953  if (p->numberofvertices < 1) {
954  printf("Error: Wrong polygon %d in facet %d\n", j, i);
955  break;
956  }
957  // Initialize 'p->vertexlist'.
958  p->vertexlist = new int[p->numberofvertices];
959  // Read all vertices of this polygon.
960  for (k = 1; k <= p->numberofvertices; k++) {
961  stringptr = findnextnumber(stringptr);
962  if (*stringptr == '\0') {
963  // Try to load another non-empty line and continue to read the
964  // rest of vertices.
965  stringptr = readnumberline(inputline, infile, infilename);
966  if (*stringptr == '\0') {
967  printf("Error: Missing %d endpoints of polygon %d in facet %d",
968  p->numberofvertices - k, j, i);
969  break;
970  }
971  }
972  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
973  }
974  }
975  if (j <= f->numberofpolygons) {
976  // This must be caused by an error. However, there're j - 1
977  // polygons have been read. Reset the 'f->numberofpolygon'.
978  if (j == 1) {
979  // This is the first polygon.
980  delete [] f->polygonlist;
981  }
982  f->numberofpolygons = j - 1;
983  // No hole will be read even it exists.
984  f->numberofholes = 0;
985  break;
986  }
987  // If this facet has hole pints defined, read them.
988  if (f->numberofholes > 0) {
989  // Initialize 'f->holelist'.
990  f->holelist = new REAL[f->numberofholes * 3];
991  // Read the holes' coordinates.
992  index = 0;
993  for (j = 1; j <= f->numberofholes; j++) {
994  stringptr = readnumberline(inputline, infile, infilename);
995  for (k = 1; k <= 3; k++) {
996  stringptr = findnextnumber(stringptr);
997  if (*stringptr == '\0') {
998  printf("Error: Hole %d in facet %d has no coordinates", j, i);
999  break;
1000  }
1001  f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1002  }
1003  if (k <= 3) {
1004  // This must be caused by an error.
1005  break;
1006  }
1007  }
1008  if (j <= f->numberofholes) {
1009  // This must be caused by an error.
1010  break;
1011  }
1012  }
1013  }
1014  if (i <= numberoffacets) {
1015  // This must be caused by an error.
1016  numberoffacets = i - 1;
1017  fclose(infile);
1018  return false;
1019  }
1020  } else { // poly == 0
1021  // Read the facets from a .smesh file.
1022  for (i = 1; i <= numberoffacets; i++) {
1023  f = &(facetlist[i - 1]);
1024  init(f);
1025  // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1026  // contains exactly one polygon, no hole.
1027  f->numberofpolygons = 1;
1028  f->polygonlist = new polygon[f->numberofpolygons];
1029  p = &(f->polygonlist[0]);
1030  init(p);
1031  // Read number of vertices of this polygon.
1032  stringptr = readnumberline(inputline, infile, insmeshfilename);
1033  p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1034  if (p->numberofvertices < 1) {
1035  printf("Error: Wrong number of vertex in facet %d\n", i);
1036  break;
1037  }
1038  // Initialize 'p->vertexlist'.
1039  p->vertexlist = new int[p->numberofvertices];
1040  for (k = 1; k <= p->numberofvertices; k++) {
1041  stringptr = findnextnumber(stringptr);
1042  if (*stringptr == '\0') {
1043  // Try to load another non-empty line and continue to read the
1044  // rest of vertices.
1045  stringptr = readnumberline(inputline, infile, infilename);
1046  if (*stringptr == '\0') {
1047  printf("Error: Missing %d endpoints in facet %d",
1048  p->numberofvertices - k, i);
1049  break;
1050  }
1051  }
1052  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1053  }
1054  if (k <= p->numberofvertices) {
1055  // This must be caused by an error.
1056  break;
1057  }
1058  // Read facet's boundary marker at last.
1059  if (markers == 1) {
1060  stringptr = findnextnumber(stringptr);
1061  if (*stringptr == '\0') {
1062  currentmarker = 0;
1063  } else {
1064  currentmarker = (int) strtol(stringptr, &stringptr, 0);
1065  }
1066  facetmarkerlist[i - 1] = currentmarker;
1067  }
1068  }
1069  if (i <= numberoffacets) {
1070  // This must be caused by an error.
1071  numberoffacets = i - 1;
1072  fclose(infile);
1073  return false;
1074  }
1075  }
1076 
1077  // Read the hole section.
1078  stringptr = readnumberline(inputline, infile, infilename);
1079  if (stringptr == NULL) {
1080  // No hole list, return.
1081  fclose(infile);
1082  return true;
1083  }
1084  if (*stringptr != '\0') {
1085  numberofholes = (int) strtol (stringptr, &stringptr, 0);
1086  } else {
1087  numberofholes = 0;
1088  }
1089  if (numberofholes > 0) {
1090  // Initialize 'holelist'.
1091  holelist = new REAL[numberofholes * 3];
1092  for (i = 0; i < 3 * numberofholes; i += 3) {
1093  stringptr = readnumberline(inputline, infile, infilename);
1094  stringptr = findnextnumber(stringptr);
1095  if (*stringptr == '\0') {
1096  printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1097  break;
1098  } else {
1099  holelist[i] = (REAL) strtod(stringptr, &stringptr);
1100  }
1101  stringptr = findnextnumber(stringptr);
1102  if (*stringptr == '\0') {
1103  printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1104  break;
1105  } else {
1106  holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1107  }
1108  stringptr = findnextnumber(stringptr);
1109  if (*stringptr == '\0') {
1110  printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1111  break;
1112  } else {
1113  holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1114  }
1115  }
1116  if (i < 3 * numberofholes) {
1117  // This must be caused by an error.
1118  fclose(infile);
1119  return false;
1120  }
1121  }
1122 
1123  // Read the region section. The 'region' section is optional, if we
1124  // don't reach the end-of-file, try read it in.
1125  stringptr = readnumberline(inputline, infile, NULL);
1126  if (stringptr != (char *) NULL && *stringptr != '\0') {
1127  numberofregions = (int) strtol (stringptr, &stringptr, 0);
1128  } else {
1129  numberofregions = 0;
1130  }
1131  if (numberofregions > 0) {
1132  // Initialize 'regionlist'.
1133  regionlist = new REAL[numberofregions * 5];
1134  index = 0;
1135  for (i = 0; i < numberofregions; i++) {
1136  stringptr = readnumberline(inputline, infile, infilename);
1137  stringptr = findnextnumber(stringptr);
1138  if (*stringptr == '\0') {
1139  printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1140  break;
1141  } else {
1142  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1143  }
1144  stringptr = findnextnumber(stringptr);
1145  if (*stringptr == '\0') {
1146  printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1147  break;
1148  } else {
1149  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1150  }
1151  stringptr = findnextnumber(stringptr);
1152  if (*stringptr == '\0') {
1153  printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1154  break;
1155  } else {
1156  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1157  }
1158  stringptr = findnextnumber(stringptr);
1159  if (*stringptr == '\0') {
1160  printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1161  break;
1162  } else {
1163  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1164  }
1165  stringptr = findnextnumber(stringptr);
1166  if (*stringptr == '\0') {
1167  regionlist[index] = regionlist[index - 1];
1168  } else {
1169  regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1170  }
1171  index++;
1172  }
1173  if (i < numberofregions) {
1174  // This must be caused by an error.
1175  fclose(infile);
1176  return false;
1177  }
1178  }
1179 
1180  } else {
1181 
1182  // Read a PSLG from Triangle's poly file.
1183  assert(mesh_dim == 2);
1184  // A PSLG is a facet of a PLC.
1185  numberoffacets = 1;
1186  // Initialize the 'facetlist'.
1188  facetmarkerlist = (int *) NULL; // No facet markers.
1189  f = &(facetlist[0]);
1190  init(f);
1191  // Read number of segments.
1192  stringptr = readnumberline(inputline, infile, infilename);
1193  // Segments are degenerate polygons.
1194  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
1195  if (f->numberofpolygons > 0) {
1196  f->polygonlist = new polygon[f->numberofpolygons];
1197  }
1198  // Go through all segments, read in their vertices.
1199  for (j = 0; j < f->numberofpolygons; j++) {
1200  p = &(f->polygonlist[j]);
1201  init(p);
1202  // Read in a segment.
1203  stringptr = readnumberline(inputline, infile, infilename);
1204  stringptr = findnextnumber(stringptr); // Skip its index.
1205  p->numberofvertices = 2; // A segment always has two vertices.
1206  p->vertexlist = new int[p->numberofvertices];
1207  p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
1208  stringptr = findnextnumber(stringptr);
1209  p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
1210  }
1211  // Read number of holes.
1212  stringptr = readnumberline(inputline, infile, infilename);
1213  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
1214  if (f->numberofholes > 0) {
1215  // Initialize 'f->holelist'.
1216  f->holelist = new REAL[f->numberofholes * 3];
1217  // Read the holes' coordinates.
1218  for (j = 0; j < f->numberofholes; j++) {
1219  // Read a 2D hole point.
1220  stringptr = readnumberline(inputline, infile, infilename);
1221  stringptr = findnextnumber(stringptr); // Skip its index.
1222  f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
1223  stringptr = findnextnumber(stringptr);
1224  f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
1225  f->holelist[j * 3 + 2] = 0.0; // The z-coord.
1226  }
1227  }
1228  // The regions are skipped.
1229 
1230  }
1231 
1232  // End of reading poly/smesh file.
1233  fclose(infile);
1234  return true;
1235 }
1236 
1238 // //
1239 // load_off() Load a polyhedron from a .off file. //
1240 // //
1241 // The .off format is one of file formats of the Geomview, an interactive //
1242 // program for viewing and manipulating geometric objects. More information //
1243 // is available form: http://www.geomview.org. //
1244 // //
1246 
1247 bool tetgenio::load_off(char* filebasename)
1248 {
1249  FILE *fp;
1250  tetgenio::facet *f;
1252  char infilename[FILENAMESIZE];
1253  char buffer[INPUTLINESIZE];
1254  char *bufferp;
1255  double *coord;
1256  int nverts = 0, iverts = 0;
1257  int nfaces = 0, ifaces = 0;
1258  int nedges = 0;
1259  int line_count = 0, i;
1260 
1261  // Default, the off file's index is from '0'. We check it by remembering the
1262  // smallest index we found in the file. It should be either 0 or 1.
1263  int smallestidx = 0;
1264 
1265  strncpy(infilename, filebasename, 1024 - 1);
1266  infilename[FILENAMESIZE - 1] = '\0';
1267  if (infilename[0] == '\0') {
1268  printf("Error: No filename.\n");
1269  return false;
1270  }
1271  if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1272  strcat(infilename, ".off");
1273  }
1274 
1275  if (!(fp = fopen(infilename, "r"))) {
1276  printf(" Unable to open file %s\n", infilename);
1277  return false;
1278  }
1279  printf("Opening %s.\n", infilename);
1280 
1281  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1282  // Check section
1283  if (nverts == 0) {
1284  // Read header
1285  bufferp = strstr(bufferp, "OFF");
1286  if (bufferp != NULL) {
1287  // Read mesh counts
1288  bufferp = findnextnumber(bufferp); // Skip field "OFF".
1289  if (*bufferp == '\0') {
1290  // Read a non-empty line.
1291  bufferp = readline(buffer, fp, &line_count);
1292  }
1293  if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1294  || (nverts == 0)) {
1295  printf("Syntax error reading header on line %d in file %s\n",
1296  line_count, infilename);
1297  fclose(fp);
1298  return false;
1299  }
1300  // Allocate memory for 'tetgenio'
1301  if (nverts > 0) {
1302  numberofpoints = nverts;
1303  pointlist = new REAL[nverts * 3];
1304  smallestidx = nverts + 1; // A bigger enough number.
1305  }
1306  if (nfaces > 0) {
1307  numberoffacets = nfaces;
1308  facetlist = new tetgenio::facet[nfaces];
1309  }
1310  }
1311  } else if (iverts < nverts) {
1312  // Read vertex coordinates
1313  coord = &pointlist[iverts * 3];
1314  for (i = 0; i < 3; i++) {
1315  if (*bufferp == '\0') {
1316  printf("Syntax error reading vertex coords on line %d in file %s\n",
1317  line_count, infilename);
1318  fclose(fp);
1319  return false;
1320  }
1321  coord[i] = (REAL) strtod(bufferp, &bufferp);
1322  bufferp = findnextnumber(bufferp);
1323  }
1324  iverts++;
1325  } else if (ifaces < nfaces) {
1326  // Get next face
1327  f = &facetlist[ifaces];
1328  init(f);
1329  // In .off format, each facet has one polygon, no hole.
1330  f->numberofpolygons = 1;
1331  f->polygonlist = new tetgenio::polygon[1];
1332  p = &f->polygonlist[0];
1333  init(p);
1334  // Read the number of vertices, it should be greater than 0.
1335  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1336  if (p->numberofvertices == 0) {
1337  printf("Syntax error reading polygon on line %d in file %s\n",
1338  line_count, infilename);
1339  fclose(fp);
1340  return false;
1341  }
1342  // Allocate memory for face vertices
1343  p->vertexlist = new int[p->numberofvertices];
1344  for (i = 0; i < p->numberofvertices; i++) {
1345  bufferp = findnextnumber(bufferp);
1346  if (*bufferp == '\0') {
1347  printf("Syntax error reading polygon on line %d in file %s\n",
1348  line_count, infilename);
1349  fclose(fp);
1350  return false;
1351  }
1352  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1353  // Detect the smallest index.
1354  if (p->vertexlist[i] < smallestidx) {
1355  smallestidx = p->vertexlist[i];
1356  }
1357  }
1358  ifaces++;
1359  } else {
1360  // Should never get here
1361  printf("Found extra text starting at line %d in file %s\n", line_count,
1362  infilename);
1363  break;
1364  }
1365  }
1366 
1367  // Close file
1368  fclose(fp);
1369 
1370  // Decide the firstnumber of the index.
1371  if (smallestidx == 0) {
1372  firstnumber = 0;
1373  } else if (smallestidx == 1) {
1374  firstnumber = 1;
1375  } else {
1376  printf("A wrong smallest index (%d) was detected in file %s\n",
1377  smallestidx, infilename);
1378  return false;
1379  }
1380 
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  if (ifaces != nfaces) {
1387  printf("Expected %d faces, but read only %d faces in file %s\n",
1388  nfaces, ifaces, infilename);
1389  return false;
1390  }
1391 
1392  return true;
1393 }
1394 
1396 // //
1397 // load_ply() Load a polyhedron from a .ply file. //
1398 // //
1399 // This is a simplified version of reading .ply files, which only reads the //
1400 // set of vertices and the set of faces. Other informations (such as color, //
1401 // material, texture, etc) in .ply file are ignored. Complete routines for //
1402 // reading and writing ,ply files are available from: http://www.cc.gatech. //
1403 // edu/projects/large_models/ply.html. Except the header section, ply file //
1404 // format has exactly the same format for listing vertices and polygons as //
1405 // off file format. //
1406 // //
1408 
1409 bool tetgenio::load_ply(char* filebasename)
1410 {
1411  FILE *fp;
1412  tetgenio::facet *f;
1414  char infilename[FILENAMESIZE];
1415  char buffer[INPUTLINESIZE];
1416  char *bufferp, *str;
1417  double *coord;
1418  int endheader = 0, format = 0;
1419  int nverts = 0, iverts = 0;
1420  int nfaces = 0, ifaces = 0;
1421  int line_count = 0, i;
1422 
1423  // Default, the ply file's index is from '0'. We check it by remembering the
1424  // smallest index we found in the file. It should be either 0 or 1.
1425  int smallestidx = 0;
1426 
1427  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1428  infilename[FILENAMESIZE - 1] = '\0';
1429  if (infilename[0] == '\0') {
1430  printf("Error: No filename.\n");
1431  return false;
1432  }
1433  if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1434  strcat(infilename, ".ply");
1435  }
1436 
1437  if (!(fp = fopen(infilename, "r"))) {
1438  printf("Error: Unable to open file %s\n", infilename);
1439  return false;
1440  }
1441  printf("Opening %s.\n", infilename);
1442 
1443  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1444  if (!endheader) {
1445  // Find if it is the keyword "end_header".
1446  str = strstr(bufferp, "end_header");
1447  // strstr() is case sensitive.
1448  if (!str) str = strstr(bufferp, "End_header");
1449  if (!str) str = strstr(bufferp, "End_Header");
1450  if (str) {
1451  // This is the end of the header section.
1452  endheader = 1;
1453  continue;
1454  }
1455  // Parse the number of vertices and the number of faces.
1456  if (nverts == 0 || nfaces == 0) {
1457  // Find if it si the keyword "element".
1458  str = strstr(bufferp, "element");
1459  if (!str) str = strstr(bufferp, "Element");
1460  if (str) {
1461  bufferp = findnextfield(str);
1462  if (*bufferp == '\0') {
1463  printf("Syntax error reading element type on line%d in file %s\n",
1464  line_count, infilename);
1465  fclose(fp);
1466  return false;
1467  }
1468  if (nverts == 0) {
1469  // Find if it is the keyword "vertex".
1470  str = strstr(bufferp, "vertex");
1471  if (!str) str = strstr(bufferp, "Vertex");
1472  if (str) {
1473  bufferp = findnextnumber(str);
1474  if (*bufferp == '\0') {
1475  printf("Syntax error reading vertex number on line");
1476  printf(" %d in file %s\n", line_count, infilename);
1477  fclose(fp);
1478  return false;
1479  }
1480  nverts = (int) strtol(bufferp, &bufferp, 0);
1481  // Allocate memory for 'tetgenio'
1482  if (nverts > 0) {
1483  numberofpoints = nverts;
1484  pointlist = new REAL[nverts * 3];
1485  smallestidx = nverts + 1; // A big enough index.
1486  }
1487  }
1488  }
1489  if (nfaces == 0) {
1490  // Find if it is the keyword "face".
1491  str = strstr(bufferp, "face");
1492  if (!str) str = strstr(bufferp, "Face");
1493  if (str) {
1494  bufferp = findnextnumber(str);
1495  if (*bufferp == '\0') {
1496  printf("Syntax error reading face number on line");
1497  printf(" %d in file %s\n", line_count, infilename);
1498  fclose(fp);
1499  return false;
1500  }
1501  nfaces = (int) strtol(bufferp, &bufferp, 0);
1502  // Allocate memory for 'tetgenio'
1503  if (nfaces > 0) {
1504  numberoffacets = nfaces;
1505  facetlist = new tetgenio::facet[nfaces];
1506  }
1507  }
1508  }
1509  } // It is not the string "element".
1510  }
1511  if (format == 0) {
1512  // Find the keyword "format".
1513  str = strstr(bufferp, "format");
1514  if (!str) str = strstr(bufferp, "Format");
1515  if (str) {
1516  format = 1;
1517  bufferp = findnextfield(str);
1518  // Find if it is the string "ascii".
1519  str = strstr(bufferp, "ascii");
1520  if (!str) str = strstr(bufferp, "ASCII");
1521  if (!str) {
1522  printf("This routine only reads ascii format of ply files.\n");
1523  printf("Hint: You can convert the binary to ascii format by\n");
1524  printf(" using the provided ply tools:\n");
1525  printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1526  fclose(fp);
1527  return false;
1528  }
1529  }
1530  }
1531  } else if (iverts < nverts) {
1532  // Read vertex coordinates
1533  coord = &pointlist[iverts * 3];
1534  for (i = 0; i < 3; i++) {
1535  if (*bufferp == '\0') {
1536  printf("Syntax error reading vertex coords on line %d in file %s\n",
1537  line_count, infilename);
1538  fclose(fp);
1539  return false;
1540  }
1541  coord[i] = (REAL) strtod(bufferp, &bufferp);
1542  bufferp = findnextnumber(bufferp);
1543  }
1544  iverts++;
1545  } else if (ifaces < nfaces) {
1546  // Get next face
1547  f = &facetlist[ifaces];
1548  init(f);
1549  // In .off format, each facet has one polygon, no hole.
1550  f->numberofpolygons = 1;
1551  f->polygonlist = new tetgenio::polygon[1];
1552  p = &f->polygonlist[0];
1553  init(p);
1554  // Read the number of vertices, it should be greater than 0.
1555  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1556  if (p->numberofvertices == 0) {
1557  printf("Syntax error reading polygon on line %d in file %s\n",
1558  line_count, infilename);
1559  fclose(fp);
1560  return false;
1561  }
1562  // Allocate memory for face vertices
1563  p->vertexlist = new int[p->numberofvertices];
1564  for (i = 0; i < p->numberofvertices; i++) {
1565  bufferp = findnextnumber(bufferp);
1566  if (*bufferp == '\0') {
1567  printf("Syntax error reading polygon on line %d in file %s\n",
1568  line_count, infilename);
1569  fclose(fp);
1570  return false;
1571  }
1572  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1573  if (p->vertexlist[i] < smallestidx) {
1574  smallestidx = p->vertexlist[i];
1575  }
1576  }
1577  ifaces++;
1578  } else {
1579  // Should never get here
1580  printf("Found extra text starting at line %d in file %s\n", line_count,
1581  infilename);
1582  break;
1583  }
1584  }
1585 
1586  // Close file
1587  fclose(fp);
1588 
1589  // Decide the firstnumber of the index.
1590  if (smallestidx == 0) {
1591  firstnumber = 0;
1592  } else if (smallestidx == 1) {
1593  firstnumber = 1;
1594  } else {
1595  printf("A wrong smallest index (%d) was detected in file %s\n",
1596  smallestidx, infilename);
1597  return false;
1598  }
1599 
1600  if (iverts != nverts) {
1601  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1602  nverts, iverts, infilename);
1603  return false;
1604  }
1605  if (ifaces != nfaces) {
1606  printf("Expected %d faces, but read only %d faces in file %s\n",
1607  nfaces, ifaces, infilename);
1608  return false;
1609  }
1610 
1611  return true;
1612 }
1613 
1615 // //
1616 // load_stl() Load a surface mesh from a .stl file. //
1617 // //
1618 // The .stl or stereolithography format is an ASCII or binary file used in //
1619 // manufacturing. It is a list of the triangular surfaces that describe a //
1620 // computer generated solid model. This is the standard input for most rapid //
1621 // prototyping machines. //
1622 // //
1623 // Comment: A .stl file many contain many duplicated points. They will be //
1624 // unified during the Delaunay tetrahedralization process. //
1625 // //
1627 
1628 bool tetgenio::load_stl(char* filebasename)
1629 {
1630  FILE *fp;
1631  tetgenmesh::arraypool *plist;
1632  tetgenio::facet *f;
1634  char infilename[FILENAMESIZE];
1635  char buffer[INPUTLINESIZE];
1636  char *bufferp, *str;
1637  double *coord;
1638  int solid = 0;
1639  int nverts = 0, iverts = 0;
1640  int nfaces = 0;
1641  int line_count = 0, i;
1642 
1643  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1644  infilename[FILENAMESIZE - 1] = '\0';
1645  if (infilename[0] == '\0') {
1646  printf("Error: No filename.\n");
1647  return false;
1648  }
1649  if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1650  strcat(infilename, ".stl");
1651  }
1652 
1653  if (!(fp = fopen(infilename, "r"))) {
1654  printf("Error: Unable to open file %s\n", infilename);
1655  return false;
1656  }
1657  printf("Opening %s.\n", infilename);
1658 
1659  // STL file has no number of points available. Use a list to read points.
1660  plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
1661 
1662  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1663  // The ASCII .stl file must start with the lower case keyword solid and
1664  // end with endsolid.
1665  if (solid == 0) {
1666  // Read header
1667  bufferp = strstr(bufferp, "solid");
1668  if (bufferp != NULL) {
1669  solid = 1;
1670  }
1671  } else {
1672  // We're inside the block of the solid.
1673  str = bufferp;
1674  // Is this the end of the solid.
1675  bufferp = strstr(bufferp, "endsolid");
1676  if (bufferp != NULL) {
1677  solid = 0;
1678  } else {
1679  // Read the XYZ coordinates if it is a vertex.
1680  bufferp = str;
1681  bufferp = strstr(bufferp, "vertex");
1682  if (bufferp != NULL) {
1683  plist->newindex((void **) &coord);
1684  for (i = 0; i < 3; i++) {
1685  bufferp = findnextnumber(bufferp);
1686  if (*bufferp == '\0') {
1687  printf("Syntax error reading vertex coords on line %d\n",
1688  line_count);
1689  delete plist;
1690  fclose(fp);
1691  return false;
1692  }
1693  coord[i] = (REAL) strtod(bufferp, &bufferp);
1694  }
1695 #if 0
1696  {
1697  static unsigned counter;
1698  counter++;
1699  printf("%5d\n", counter);
1700 
1701  //if (counter > 450) coord[0] += .001;
1702  }
1703 #endif
1704  }
1705  }
1706  }
1707  }
1708  fclose(fp);
1709 
1710  nverts = (int) plist->objects;
1711  // nverts should be an integer times 3 (every 3 vertices denote a face).
1712  if (nverts == 0 || (nverts % 3 != 0)) {
1713  printf("Error: Wrong number of vertices in file %s.\n", infilename);
1714  delete plist;
1715  return false;
1716  }
1717  numberofpoints = nverts;
1718  pointlist = new REAL[nverts * 3];
1719  for (i = 0; i < nverts; i++) {
1720  coord = (double *) fastlookup(plist, i);
1721  iverts = i * 3;
1722  pointlist[iverts] = (REAL) coord[0];
1723  pointlist[iverts + 1] = (REAL) coord[1];
1724  pointlist[iverts + 2] = (REAL) coord[2];
1725  }
1726 
1727  nfaces = (int) (nverts / 3);
1728  numberoffacets = nfaces;
1729  facetlist = new tetgenio::facet[nfaces];
1730 
1731  // Default use '1' as the array starting index.
1732  firstnumber = 1;
1733  iverts = firstnumber;
1734  for (i = 0; i < nfaces; i++) {
1735  f = &facetlist[i];
1736  init(f);
1737  // In .stl format, each facet has one polygon, no hole.
1738  f->numberofpolygons = 1;
1739  f->polygonlist = new tetgenio::polygon[1];
1740  p = &f->polygonlist[0];
1741  init(p);
1742  // Each polygon has three vertices.
1743  p->numberofvertices = 3;
1744  p->vertexlist = new int[p->numberofvertices];
1745  p->vertexlist[0] = iverts;
1746  p->vertexlist[1] = iverts + 1;
1747  p->vertexlist[2] = iverts + 2;
1748  iverts += 3;
1749  }
1750 
1751  delete plist;
1752  return true;
1753 }
1754 
1756 // //
1757 // load_medit() Load a surface mesh from a .mesh file. //
1758 // //
1759 // The .mesh format is the file format of Medit, a user-friendly interactive //
1760 // mesh viewer program. //
1761 // //
1763 
1764 bool tetgenio::load_medit(char* filebasename, int istetmesh)
1765 {
1766  FILE *fp;
1767  tetgenio::facet *tmpflist, *f;
1769  char infilename[FILENAMESIZE];
1770  char buffer[INPUTLINESIZE];
1771  char *bufferp, *str;
1772  double *coord;
1773  int *tmpfmlist;
1774  int dimension = 0;
1775  int nverts = 0;
1776  int nfaces = 0;
1777  int ntets = 0;
1778  int line_count = 0;
1779  int corners = 0; // 3 (triangle) or 4 (quad).
1780  int *plist;
1781  int i, j;
1782 
1783  int smallestidx = 0;
1784 
1785  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1786  infilename[FILENAMESIZE - 1] = '\0';
1787  if (infilename[0] == '\0') {
1788  printf("Error: No filename.\n");
1789  return false;
1790  }
1791  if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1792  strcat(infilename, ".mesh");
1793  }
1794 
1795  if (!(fp = fopen(infilename, "r"))) {
1796  printf("Error: Unable to open file %s\n", infilename);
1797  return false;
1798  }
1799  printf("Opening %s.\n", infilename);
1800 
1801  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1802  if (*bufferp == '#') continue; // A comment line is skipped.
1803  if (dimension == 0) {
1804  // Find if it is the keyword "Dimension".
1805  str = strstr(bufferp, "Dimension");
1806  if (!str) str = strstr(bufferp, "dimension");
1807  if (!str) str = strstr(bufferp, "DIMENSION");
1808  if (str) {
1809  // Read the dimensions
1810  bufferp = findnextnumber(str); // Skip field "Dimension".
1811  if (*bufferp == '\0') {
1812  // Read a non-empty line.
1813  bufferp = readline(buffer, fp, &line_count);
1814  }
1815  dimension = (int) strtol(bufferp, &bufferp, 0);
1816  if (dimension != 2 && dimension != 3) {
1817  printf("Unknown dimension in file on line %d in file %s\n",
1818  line_count, infilename);
1819  fclose(fp);
1820  return false;
1821  }
1822  mesh_dim = dimension;
1823  }
1824  }
1825  if (nverts == 0) {
1826  // Find if it is the keyword "Vertices".
1827  str = strstr(bufferp, "Vertices");
1828  if (!str) str = strstr(bufferp, "vertices");
1829  if (!str) str = strstr(bufferp, "VERTICES");
1830  if (str) {
1831  // Read the number of vertices.
1832  bufferp = findnextnumber(str); // Skip field "Vertices".
1833  if (*bufferp == '\0') {
1834  // Read a non-empty line.
1835  bufferp = readline(buffer, fp, &line_count);
1836  }
1837  nverts = (int) strtol(bufferp, &bufferp, 0);
1838  // Initialize the smallest index.
1839  smallestidx = nverts + 1;
1840  // Allocate memory for 'tetgenio'
1841  if (nverts > 0) {
1842  numberofpoints = nverts;
1843  pointlist = new REAL[nverts * 3];
1844  }
1845  // Read the follwoing node list.
1846  for (i = 0; i < nverts; i++) {
1847  bufferp = readline(buffer, fp, &line_count);
1848  if (bufferp == NULL) {
1849  printf("Unexpected end of file on line %d in file %s\n",
1850  line_count, infilename);
1851  fclose(fp);
1852  return false;
1853  }
1854  // Read vertex coordinates
1855  coord = &pointlist[i * 3];
1856  for (j = 0; j < 3; j++) {
1857  if (*bufferp == '\0') {
1858  printf("Syntax error reading vertex coords on line");
1859  printf(" %d in file %s\n", line_count, infilename);
1860  fclose(fp);
1861  return false;
1862  }
1863  if ((j < 2) || (dimension == 3)) {
1864  coord[j] = (REAL) strtod(bufferp, &bufferp);
1865  } else {
1866  assert((j == 2) && (dimension == 2));
1867  coord[j] = 0.0;
1868  }
1869  bufferp = findnextnumber(bufferp);
1870  }
1871  }
1872  continue;
1873  }
1874  }
1875  if (ntets == 0) {
1876  // Find if it is the keyword "Tetrahedra"
1877  corners = 0;
1878  str = strstr(bufferp, "Tetrahedra");
1879  if (!str) str = strstr(bufferp, "tetrahedra");
1880  if (!str) str = strstr(bufferp, "TETRAHEDRA");
1881  if (str) {
1882  corners = 4;
1883  }
1884  if (corners == 4) {
1885  // Read the number of tetrahedra
1886  bufferp = findnextnumber(str); // Skip field "Tetrahedra".
1887  if (*bufferp == '\0') {
1888  // Read a non-empty line.
1889  bufferp = readline(buffer, fp, &line_count);
1890  }
1891  ntets = strtol(bufferp, &bufferp, 0);
1892  if (ntets > 0) {
1893  // It is a tetrahedral mesh.
1894  numberoftetrahedra = ntets;
1895  numberofcorners = 4;
1897  tetrahedronlist = new int[ntets * 4];
1898  tetrahedronattributelist = new REAL[ntets];
1899  }
1900  } // if (corners == 4)
1901  // Read the list of tetrahedra.
1902  for (i = 0; i < numberoftetrahedra; i++) {
1903  plist = &(tetrahedronlist[i * 4]);
1904  bufferp = readline(buffer, fp, &line_count);
1905  if (bufferp == NULL) {
1906  printf("Unexpected end of file on line %d in file %s\n",
1907  line_count, infilename);
1908  fclose(fp);
1909  return false;
1910  }
1911  // Read the vertices of the tet.
1912  for (j = 0; j < corners; j++) {
1913  if (*bufferp == '\0') {
1914  printf("Syntax error reading face on line %d in file %s\n",
1915  line_count, infilename);
1916  fclose(fp);
1917  return false;
1918  }
1919  plist[j] = (int) strtol(bufferp, &bufferp, 0);
1920  // Remember the smallest index.
1921  if (plist[j] < smallestidx) smallestidx = plist[j];
1922  bufferp = findnextnumber(bufferp);
1923  }
1924  // Read the attribute of the tet if it exists.
1925  tetrahedronattributelist[i] = 0;
1926  if (*bufferp != '\0') {
1927  tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
1928  }
1929  } // i
1930  } // Tetrahedra
1931  if (nfaces == 0) {
1932  // Find if it is the keyword "Triangles" or "Quadrilaterals".
1933  corners = 0;
1934  str = strstr(bufferp, "Triangles");
1935  if (!str) str = strstr(bufferp, "triangles");
1936  if (!str) str = strstr(bufferp, "TRIANGLES");
1937  if (str) {
1938  corners = 3;
1939  } else {
1940  str = strstr(bufferp, "Quadrilaterals");
1941  if (!str) str = strstr(bufferp, "quadrilaterals");
1942  if (!str) str = strstr(bufferp, "QUADRILATERALS");
1943  if (str) {
1944  corners = 4;
1945  }
1946  }
1947  if (corners == 3 || corners == 4) {
1948  // Read the number of triangles (or quadrilaterals).
1949  bufferp = findnextnumber(str); // Skip field "Triangles".
1950  if (*bufferp == '\0') {
1951  // Read a non-empty line.
1952  bufferp = readline(buffer, fp, &line_count);
1953  }
1954  nfaces = strtol(bufferp, &bufferp, 0);
1955  // Allocate memory for 'tetgenio'
1956  if (nfaces > 0) {
1957  if (!istetmesh) {
1958  // It is a PLC surface mesh.
1959  if (numberoffacets > 0) {
1960  // facetlist has already been allocated. Enlarge arrays.
1961  // This happens when the surface mesh contains mixed cells.
1962  tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1963  tmpfmlist = new int[numberoffacets + nfaces];
1964  // Copy the data of old arrays into new arrays.
1965  for (i = 0; i < numberoffacets; i++) {
1966  f = &(tmpflist[i]);
1967  tetgenio::init(f);
1968  *f = facetlist[i];
1969  tmpfmlist[i] = facetmarkerlist[i];
1970  }
1971  // Release old arrays.
1972  delete [] facetlist;
1973  delete [] facetmarkerlist;
1974  // Remember the new arrays.
1975  facetlist = tmpflist;
1976  facetmarkerlist = tmpfmlist;
1977  } else {
1978  // This is the first time to allocate facetlist.
1979  facetlist = new tetgenio::facet[nfaces];
1980  facetmarkerlist = new int[nfaces];
1981  }
1982  } else {
1983  if (corners == 3) {
1984  // It is a surface mesh of a tetrahedral mesh.
1985  numberoftrifaces = nfaces;
1986  trifacelist = new int[nfaces * 3];
1987  trifacemarkerlist = new int[nfaces];
1988  }
1989  }
1990  } // if (nfaces > 0)
1991  // Read the following list of faces.
1992  if (!istetmesh) {
1993  for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
1994  bufferp = readline(buffer, fp, &line_count);
1995  if (bufferp == NULL) {
1996  printf("Unexpected end of file on line %d in file %s\n",
1997  line_count, infilename);
1998  fclose(fp);
1999  return false;
2000  }
2001  f = &facetlist[i];
2002  tetgenio::init(f);
2003  // In .mesh format, each facet has one polygon, no hole.
2004  f->numberofpolygons = 1;
2005  f->polygonlist = new tetgenio::polygon[1];
2006  p = &f->polygonlist[0];
2007  tetgenio::init(p);
2008  p->numberofvertices = corners;
2009  // Allocate memory for face vertices
2010  p->vertexlist = new int[p->numberofvertices];
2011  // Read the vertices of the face.
2012  for (j = 0; j < corners; j++) {
2013  if (*bufferp == '\0') {
2014  printf("Syntax error reading face on line %d in file %s\n",
2015  line_count, infilename);
2016  fclose(fp);
2017  return false;
2018  }
2019  p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
2020  // Remember the smallest index.
2021  if (p->vertexlist[j] < smallestidx) {
2022  smallestidx = p->vertexlist[j];
2023  }
2024  bufferp = findnextnumber(bufferp);
2025  }
2026  // Read the marker of the face if it exists.
2027  facetmarkerlist[i] = 0;
2028  if (*bufferp != '\0') {
2029  facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2030  }
2031  }
2032  // Have read in a list of triangles/quads.
2033  numberoffacets += nfaces;
2034  nfaces = 0;
2035  } else {
2036  // It is a surface mesh of a tetrahedral mesh.
2037  if (corners == 3) {
2038  for (i = 0; i < numberoftrifaces; i++) {
2039  plist = &(trifacelist[i * 3]);
2040  bufferp = readline(buffer, fp, &line_count);
2041  if (bufferp == NULL) {
2042  printf("Unexpected end of file on line %d in file %s\n",
2043  line_count, infilename);
2044  fclose(fp);
2045  return false;
2046  }
2047  // Read the vertices of the face.
2048  for (j = 0; j < corners; j++) {
2049  if (*bufferp == '\0') {
2050  printf("Syntax error reading face on line %d in file %s\n",
2051  line_count, infilename);
2052  fclose(fp);
2053  return false;
2054  }
2055  plist[j] = (int) strtol(bufferp, &bufferp, 0);
2056  // Remember the smallest index.
2057  if (plist[j] < smallestidx) {
2058  smallestidx = plist[j];
2059  }
2060  bufferp = findnextnumber(bufferp);
2061  }
2062  // Read the marker of the face if it exists.
2063  trifacemarkerlist[i] = 0;
2064  if (*bufferp != '\0') {
2065  trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2066  }
2067  } // i
2068  } // if (corners == 3)
2069  } // if (b->refine)
2070  } // if (corners == 3 || corners == 4)
2071  }
2072  }
2073 
2074  // Close file
2075  fclose(fp);
2076 
2077  // Decide the firstnumber of the index.
2078  if (smallestidx == 0) {
2079  firstnumber = 0;
2080  } else if (smallestidx == 1) {
2081  firstnumber = 1;
2082  } else {
2083  printf("A wrong smallest index (%d) was detected in file %s\n",
2084  smallestidx, infilename);
2085  return false;
2086  }
2087 
2088  return true;
2089 }
2090 
2092 // //
2093 // load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). //
2094 // //
2095 // This function is contributed by: Bryn Lloyd, Computer Vision Laboratory, //
2096 // ETH, Zuerich. May 7, 2007. //
2097 // //
2099 
2100 // Two inline functions used in read/write VTK files.
2101 
2102 void swapBytes(unsigned char* var, int size)
2103 {
2104  int i = 0;
2105  int j = size - 1;
2106  char c;
2107 
2108  while (i < j) {
2109  c = var[i]; var[i] = var[j]; var[j] = c;
2110  i++, j--;
2111  }
2112 }
2113 
2115 {
2116  short word = 0x4321;
2117  if((*(char *)& word) != 0x21)
2118  return true;
2119  else
2120  return false;
2121 }
2122 
2123 
2124 bool tetgenio::load_vtk(char* filebasename)
2125 {
2126  FILE *fp;
2127  tetgenio::facet *f;
2129  char infilename[FILENAMESIZE];
2130  char line[INPUTLINESIZE];
2131  char mode[128], id[256], fmt[64];
2132  char *bufferp;
2133  double *coord;
2134  float _x, _y, _z;
2135  int nverts = 0;
2136  int nfaces = 0;
2137  int line_count = 0;
2138  int dummy;
2139  int id1, id2, id3;
2140  int nn = -1;
2141  int nn_old = -1;
2142  int i, j;
2143  bool ImALittleEndian = !testIsBigEndian();
2144 
2145  int smallestidx = 0;
2146 
2147  strncpy(infilename, filebasename, FILENAMESIZE - 1);
2148  infilename[FILENAMESIZE - 1] = '\0';
2149  if (infilename[0] == '\0') {
2150  printf("Error: No filename.\n");
2151  return false;
2152  }
2153  if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
2154  strcat(infilename, ".vtk");
2155  }
2156  if (!(fp = fopen(infilename, "r"))) {
2157  printf("Error: Unable to open file %s\n", infilename);
2158  return false;
2159  }
2160  printf("Opening %s.\n", infilename);
2161 
2162  // Default uses the index starts from '0'.
2163  firstnumber = 0;
2164  strcpy(mode, "BINARY");
2165 
2166  while((bufferp = readline(line, fp, &line_count)) != NULL) {
2167  if(strlen(line) == 0) continue;
2168  //swallow lines beginning with a comment sign or white space
2169  if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
2170  line[0] == 32) continue;
2171 
2172  sscanf(line, "%s", id);
2173  if(!strcmp(id, "ASCII")) {
2174  strcpy(mode, "ASCII");
2175  }
2176 
2177  if(!strcmp(id, "POINTS")) {
2178  sscanf(line, "%s %d %s", id, &nverts, fmt);
2179  if (nverts > 0) {
2180  numberofpoints = nverts;
2181  pointlist = new REAL[nverts * 3];
2182  smallestidx = nverts + 1;
2183  }
2184 
2185  if(!strcmp(mode, "BINARY")) {
2186  for(i = 0; i < nverts; i++) {
2187  coord = &pointlist[i * 3];
2188  if(!strcmp(fmt, "double")) {
2189  fread((char*)(&(coord[0])), sizeof(double), 1, fp);
2190  fread((char*)(&(coord[1])), sizeof(double), 1, fp);
2191  fread((char*)(&(coord[2])), sizeof(double), 1, fp);
2192  if(ImALittleEndian){
2193  swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
2194  swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
2195  swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
2196  }
2197  } else if(!strcmp(fmt, "float")) {
2198  fread((char*)(&_x), sizeof(float), 1, fp);
2199  fread((char*)(&_y), sizeof(float), 1, fp);
2200  fread((char*)(&_z), sizeof(float), 1, fp);
2201  if(ImALittleEndian){
2202  swapBytes((unsigned char *) &_x, sizeof(_x));
2203  swapBytes((unsigned char *) &_y, sizeof(_y));
2204  swapBytes((unsigned char *) &_z, sizeof(_z));
2205  }
2206  coord[0] = double(_x);
2207  coord[1] = double(_y);
2208  coord[2] = double(_z);
2209  } else {
2210  printf("Error: Only float or double formats are supported!\n");
2211  return false;
2212  }
2213  }
2214  } else if(!strcmp(mode, "ASCII")) {
2215  for(i = 0; i < nverts; i++){
2216  bufferp = readline(line, fp, &line_count);
2217  if (bufferp == NULL) {
2218  printf("Unexpected end of file on line %d in file %s\n",
2219  line_count, infilename);
2220  fclose(fp);
2221  return false;
2222  }
2223  // Read vertex coordinates
2224  coord = &pointlist[i * 3];
2225  for (j = 0; j < 3; j++) {
2226  if (*bufferp == '\0') {
2227  printf("Syntax error reading vertex coords on line");
2228  printf(" %d in file %s\n", line_count, infilename);
2229  fclose(fp);
2230  return false;
2231  }
2232  coord[j] = (REAL) strtod(bufferp, &bufferp);
2233  bufferp = findnextnumber(bufferp);
2234  }
2235  }
2236  }
2237  continue;
2238  }
2239 
2240  if(!strcmp(id, "POLYGONS")) {
2241  sscanf(line, "%s %d %d", id, &nfaces, &dummy);
2242  if (nfaces > 0) {
2243  numberoffacets = nfaces;
2244  facetlist = new tetgenio::facet[nfaces];
2245  }
2246 
2247  if(!strcmp(mode, "BINARY")) {
2248  for(i = 0; i < nfaces; i++){
2249  fread((char*)(&nn), sizeof(int), 1, fp);
2250  if(ImALittleEndian){
2251  swapBytes((unsigned char *) &nn, sizeof(nn));
2252  }
2253  if (i == 0)
2254  nn_old = nn;
2255  if (nn != nn_old) {
2256  printf("Error: No mixed cells are allowed.\n");
2257  return false;
2258  }
2259 
2260  if(nn == 3){
2261  fread((char*)(&id1), sizeof(int), 1, fp);
2262  fread((char*)(&id2), sizeof(int), 1, fp);
2263  fread((char*)(&id3), sizeof(int), 1, fp);
2264  if(ImALittleEndian){
2265  swapBytes((unsigned char *) &id1, sizeof(id1));
2266  swapBytes((unsigned char *) &id2, sizeof(id2));
2267  swapBytes((unsigned char *) &id3, sizeof(id3));
2268  }
2269  f = &facetlist[i];
2270  init(f);
2271  // In .off format, each facet has one polygon, no hole.
2272  f->numberofpolygons = 1;
2273  f->polygonlist = new tetgenio::polygon[1];
2274  p = &f->polygonlist[0];
2275  init(p);
2276  // Set number of vertices
2277  p->numberofvertices = 3;
2278  // Allocate memory for face vertices
2279  p->vertexlist = new int[p->numberofvertices];
2280  p->vertexlist[0] = id1;
2281  p->vertexlist[1] = id2;
2282  p->vertexlist[2] = id3;
2283  // Detect the smallest index.
2284  for (j = 0; j < 3; j++) {
2285  if (p->vertexlist[j] < smallestidx) {
2286  smallestidx = p->vertexlist[j];
2287  }
2288  }
2289  } else {
2290  printf("Error: Only triangles are supported\n");
2291  return false;
2292  }
2293  }
2294  } else if(!strcmp(mode, "ASCII")) {
2295  for(i = 0; i < nfaces; i++) {
2296  bufferp = readline(line, fp, &line_count);
2297  nn = (int) strtol(bufferp, &bufferp, 0);
2298  if (i == 0)
2299  nn_old = nn;
2300  if (nn != nn_old) {
2301  printf("Error: No mixed cells are allowed.\n");
2302  return false;
2303  }
2304 
2305  if (nn == 3) {
2306  bufferp = findnextnumber(bufferp); // Skip the first field.
2307  id1 = (int) strtol(bufferp, &bufferp, 0);
2308  bufferp = findnextnumber(bufferp);
2309  id2 = (int) strtol(bufferp, &bufferp, 0);
2310  bufferp = findnextnumber(bufferp);
2311  id3 = (int) strtol(bufferp, &bufferp, 0);
2312  f = &facetlist[i];
2313  init(f);
2314  // In .off format, each facet has one polygon, no hole.
2315  f->numberofpolygons = 1;
2316  f->polygonlist = new tetgenio::polygon[1];
2317  p = &f->polygonlist[0];
2318  init(p);
2319  // Set number of vertices
2320  p->numberofvertices = 3;
2321  // Allocate memory for face vertices
2322  p->vertexlist = new int[p->numberofvertices];
2323  p->vertexlist[0] = id1;
2324  p->vertexlist[1] = id2;
2325  p->vertexlist[2] = id3;
2326  // Detect the smallest index.
2327  for (j = 0; j < 3; j++) {
2328  if (p->vertexlist[j] < smallestidx) {
2329  smallestidx = p->vertexlist[j];
2330  }
2331  }
2332  } else {
2333  printf("Error: Only triangles are supported.\n");
2334  return false;
2335  }
2336  }
2337  }
2338 
2339  fclose(fp);
2340 
2341  // Decide the firstnumber of the index.
2342  if (smallestidx == 0) {
2343  firstnumber = 0;
2344  } else if (smallestidx == 1) {
2345  firstnumber = 1;
2346  } else {
2347  printf("A wrong smallest index (%d) was detected in file %s\n",
2348  smallestidx, infilename);
2349  return false;
2350  }
2351 
2352  return true;
2353  }
2354 
2355  if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
2356  printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n");
2357  }
2358  } // while ()
2359 
2360  return true;
2361 }
2362 
2364 // //
2365 // load_plc() Load a piecewise linear complex from file(s). //
2366 // //
2368 
2369 bool tetgenio::load_plc(char* filebasename, int object)
2370 {
2371  bool success;
2372 
2373  if (object == (int) tetgenbehavior::NODES) {
2374  success = load_node(filebasename);
2375  } else if (object == (int) tetgenbehavior::POLY) {
2376  success = load_poly(filebasename);
2377  } else if (object == (int) tetgenbehavior::OFF) {
2378  success = load_off(filebasename);
2379  } else if (object == (int) tetgenbehavior::PLY) {
2380  success = load_ply(filebasename);
2381  } else if (object == (int) tetgenbehavior::STL) {
2382  success = load_stl(filebasename);
2383  } else if (object == (int) tetgenbehavior::MEDIT) {
2384  success = load_medit(filebasename, 0);
2385  } else if (object == (int) tetgenbehavior::VTK) {
2386  success = load_vtk(filebasename);
2387  } else {
2388  success = load_poly(filebasename);
2389  }
2390 
2391  if (success) {
2392  // Try to load the following files (.edge, .var, .mtr).
2393  load_edge(filebasename);
2394  load_var(filebasename);
2395  load_mtr(filebasename);
2396  }
2397 
2398  return success;
2399 }
2400 
2402 // //
2403 // load_mesh() Load a tetrahedral mesh from file(s). //
2404 // //
2406 
2407 bool tetgenio::load_tetmesh(char* filebasename, int object)
2408 {
2409  bool success;
2410 
2411  if (object == (int) tetgenbehavior::MEDIT) {
2412  success = load_medit(filebasename, 1);
2413  } else {
2414  success = load_node(filebasename);
2415  if (success) {
2416  success = load_tet(filebasename);
2417  }
2418  if (success) {
2419  // Try to load the following files (.face, .edge, .vol).
2420  load_face(filebasename);
2421  load_edge(filebasename);
2422  load_vol(filebasename);
2423  }
2424  }
2425 
2426  if (success) {
2427  // Try to load the following files (.var, .mtr).
2428  load_var(filebasename);
2429  load_mtr(filebasename);
2430  }
2431 
2432  return success;
2433 }
2434 
2436 // //
2437 // save_nodes() Save points to a .node file. //
2438 // //
2440 
2441 void tetgenio::save_nodes(char* filebasename)
2442 {
2443  FILE *fout;
2444  char outnodefilename[FILENAMESIZE];
2445  char outmtrfilename[FILENAMESIZE];
2446  int i, j;
2447 
2448  sprintf(outnodefilename, "%s.node", filebasename);
2449  printf("Saving nodes to %s\n", outnodefilename);
2450  fout = fopen(outnodefilename, "w");
2451  fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2452  numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2453  for (i = 0; i < numberofpoints; i++) {
2454  if (mesh_dim == 2) {
2455  fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3],
2456  pointlist[i * 3 + 1]);
2457  } else {
2458  fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2459  pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2460  }
2461  for (j = 0; j < numberofpointattributes; j++) {
2462  fprintf(fout, " %.16g",
2463  pointattributelist[i * numberofpointattributes + j]);
2464  }
2465  if (pointmarkerlist != NULL) {
2466  fprintf(fout, " %d", pointmarkerlist[i]);
2467  }
2468  fprintf(fout, "\n");
2469  }
2470  fclose(fout);
2471 
2472  // If the point metrics exist, output them to a .mtr file.
2473  if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2474  sprintf(outmtrfilename, "%s.mtr", filebasename);
2475  printf("Saving metrics to %s\n", outmtrfilename);
2476  fout = fopen(outmtrfilename, "w");
2477  fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2478  for (i = 0; i < numberofpoints; i++) {
2479  for (j = 0; j < numberofpointmtrs; j++) {
2480  fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2481  }
2482  fprintf(fout, "\n");
2483  }
2484  fclose(fout);
2485  }
2486 }
2487 
2489 // //
2490 // save_elements() Save elements to a .ele file. //
2491 // //
2493 
2494 void tetgenio::save_elements(char* filebasename)
2495 {
2496  FILE *fout;
2497  char outelefilename[FILENAMESIZE];
2498  int i, j;
2499 
2500  sprintf(outelefilename, "%s.ele", filebasename);
2501  printf("Saving elements to %s\n", outelefilename);
2502  fout = fopen(outelefilename, "w");
2503  if (mesh_dim == 3) {
2504  fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2506  for (i = 0; i < numberoftetrahedra; i++) {
2507  fprintf(fout, "%d", i + firstnumber);
2508  for (j = 0; j < numberofcorners; j++) {
2509  fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2510  }
2511  for (j = 0; j < numberoftetrahedronattributes; j++) {
2512  fprintf(fout, " %g",
2513  tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2514  }
2515  fprintf(fout, "\n");
2516  }
2517  } else {
2518  // Save a two-dimensional mesh.
2519  fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
2520  for (i = 0; i < numberoftrifaces; i++) {
2521  fprintf(fout, "%d", i + firstnumber);
2522  for (j = 0; j < 3; j++) {
2523  fprintf(fout, " %5d", trifacelist[i * 3 + j]);
2524  }
2525  if (trifacemarkerlist != NULL) {
2526  fprintf(fout, " %d", trifacemarkerlist[i]);
2527  }
2528  fprintf(fout, "\n");
2529  }
2530  }
2531 
2532  fclose(fout);
2533 }
2534 
2536 // //
2537 // save_faces() Save faces to a .face file. //
2538 // //
2540 
2541 void tetgenio::save_faces(char* filebasename)
2542 {
2543  FILE *fout;
2544  char outfacefilename[FILENAMESIZE];
2545  int i;
2546 
2547  sprintf(outfacefilename, "%s.face", filebasename);
2548  printf("Saving faces to %s\n", outfacefilename);
2549  fout = fopen(outfacefilename, "w");
2550  fprintf(fout, "%d %d\n", numberoftrifaces,
2551  trifacemarkerlist != NULL ? 1 : 0);
2552  for (i = 0; i < numberoftrifaces; i++) {
2553  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2554  trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2555  if (trifacemarkerlist != NULL) {
2556  fprintf(fout, " %d", trifacemarkerlist[i]);
2557  }
2558  fprintf(fout, "\n");
2559  }
2560 
2561  fclose(fout);
2562 }
2563 
2565 // //
2566 // save_edges() Save egdes to a .edge file. //
2567 // //
2569 
2570 void tetgenio::save_edges(char* filebasename)
2571 {
2572  FILE *fout;
2573  char outedgefilename[FILENAMESIZE];
2574  int i;
2575 
2576  sprintf(outedgefilename, "%s.edge", filebasename);
2577  printf("Saving edges to %s\n", outedgefilename);
2578  fout = fopen(outedgefilename, "w");
2579  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2580  for (i = 0; i < numberofedges; i++) {
2581  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2582  edgelist[i * 2 + 1]);
2583  if (edgemarkerlist != NULL) {
2584  fprintf(fout, " %d", edgemarkerlist[i]);
2585  }
2586  fprintf(fout, "\n");
2587  }
2588 
2589  fclose(fout);
2590 }
2591 
2593 // //
2594 // save_neighbors() Save egdes to a .neigh file. //
2595 // //
2597 
2598 void tetgenio::save_neighbors(char* filebasename)
2599 {
2600  FILE *fout;
2601  char outneighborfilename[FILENAMESIZE];
2602  int i;
2603 
2604  sprintf(outneighborfilename, "%s.neigh", filebasename);
2605  printf("Saving neighbors to %s\n", outneighborfilename);
2606  fout = fopen(outneighborfilename, "w");
2607  fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2608  for (i = 0; i < numberoftetrahedra; i++) {
2609  if (mesh_dim == 2) {
2610  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2611  neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2612  } else {
2613  fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2614  neighborlist[i * 4], neighborlist[i * 4 + 1],
2615  neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2616  }
2617  fprintf(fout, "\n");
2618  }
2619 
2620  fclose(fout);
2621 }
2622 
2624 // //
2625 // save_poly() Save segments or facets to a .poly file. //
2626 // //
2627 // It only save the facets, holes and regions. No .node file is saved. //
2628 // //
2630 
2631 void tetgenio::save_poly(char* filebasename)
2632 {
2633  FILE *fout;
2634  facet *f;
2635  polygon *p;
2636  char outpolyfilename[FILENAMESIZE];
2637  int i, j, k;
2638 
2639  sprintf(outpolyfilename, "%s.poly", filebasename);
2640  printf("Saving poly to %s\n", outpolyfilename);
2641  fout = fopen(outpolyfilename, "w");
2642 
2643  // The zero indicates that the vertices are in a separate .node file.
2644  // Followed by number of dimensions, number of vertex attributes,
2645  // and number of boundary markers (zero or one).
2646  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2647  pointmarkerlist != NULL ? 1 : 0);
2648 
2649  // Save segments or facets.
2650  if (mesh_dim == 2) {
2651  // Number of segments, number of boundary markers (zero or one).
2652  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2653  for (i = 0; i < numberofedges; i++) {
2654  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2655  edgelist[i * 2 + 1]);
2656  if (edgemarkerlist != NULL) {
2657  fprintf(fout, " %d", edgemarkerlist[i]);
2658  }
2659  fprintf(fout, "\n");
2660  }
2661  } else {
2662  // Number of facets, number of boundary markers (zero or one).
2663  fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2664  for (i = 0; i < numberoffacets; i++) {
2665  f = &(facetlist[i]);
2666  fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2667  facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2668  // Output polygons of this facet.
2669  for (j = 0; j < f->numberofpolygons; j++) {
2670  p = &(f->polygonlist[j]);
2671  fprintf(fout, "%d ", p->numberofvertices);
2672  for (k = 0; k < p->numberofvertices; k++) {
2673  if (((k + 1) % 10) == 0) {
2674  fprintf(fout, "\n ");
2675  }
2676  fprintf(fout, " %d", p->vertexlist[k]);
2677  }
2678  fprintf(fout, "\n");
2679  }
2680  // Output holes of this facet.
2681  for (j = 0; j < f->numberofholes; j++) {
2682  fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2683  f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2684  }
2685  }
2686  }
2687 
2688  // Save holes.
2689  fprintf(fout, "%d\n", numberofholes);
2690  for (i = 0; i < numberofholes; i++) {
2691  // Output x, y coordinates.
2692  fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2693  holelist[i * mesh_dim + 1]);
2694  if (mesh_dim == 3) {
2695  // Output z coordinate.
2696  fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2697  }
2698  fprintf(fout, "\n");
2699  }
2700 
2701  // Save regions.
2702  fprintf(fout, "%d\n", numberofregions);
2703  for (i = 0; i < numberofregions; i++) {
2704  if (mesh_dim == 2) {
2705  // Output the index, x, y coordinates, attribute (region number)
2706  // and maximum area constraint (maybe -1).
2707  fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2708  regionlist[i * 4], regionlist[i * 4 + 1],
2709  regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2710  } else {
2711  // Output the index, x, y, z coordinates, attribute (region number)
2712  // and maximum volume constraint (maybe -1).
2713  fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2714  regionlist[i * 5], regionlist[i * 5 + 1],
2715  regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2716  regionlist[i * 5 + 4]);
2717  }
2718  }
2719 
2720  fclose(fout);
2721 }
2722 
2724 // //
2725 // save_faces2smesh() Save triangular faces to a .smesh file. //
2726 // //
2727 // It only save the facets. No holes and regions. No .node file. //
2728 // //
2730 
2731 void tetgenio::save_faces2smesh(char* filebasename)
2732 {
2733  FILE *fout;
2734  char outsmeshfilename[FILENAMESIZE];
2735  int i, j;
2736 
2737  sprintf(outsmeshfilename, "%s.smesh", filebasename);
2738  printf("Saving faces to %s\n", outsmeshfilename);
2739  fout = fopen(outsmeshfilename, "w");
2740 
2741  // The zero indicates that the vertices are in a separate .node file.
2742  // Followed by number of dimensions, number of vertex attributes,
2743  // and number of boundary markers (zero or one).
2744  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2745  pointmarkerlist != NULL ? 1 : 0);
2746 
2747  // Number of facets, number of boundary markers (zero or one).
2748  fprintf(fout, "%d %d\n", numberoftrifaces,
2749  trifacemarkerlist != NULL ? 1 : 0);
2750 
2751  // Output triangular facets.
2752  for (i = 0; i < numberoftrifaces; i++) {
2753  j = i * 3;
2754  fprintf(fout, "3 %d %d %d", trifacelist[j], trifacelist[j + 1],
2755  trifacelist[j + 2]);
2756  if (trifacemarkerlist != NULL) {
2757  fprintf(fout, " %d", trifacemarkerlist[i]);
2758  }
2759  fprintf(fout, "\n");
2760  }
2761 
2762  // No holes and regions.
2763  fprintf(fout, "0\n");
2764  fprintf(fout, "0\n");
2765 
2766  fclose(fout);
2767 }
2768 
2770 // //
2771 // readline() Read a nonempty line from a file. //
2772 // //
2773 // A line is considered "nonempty" if it contains something more than white //
2774 // spaces. If a line is considered empty, it will be dropped and the next //
2775 // line will be read, this process ends until reaching the end-of-file or a //
2776 // non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2777 // a pointer to the first non-whitespace character of the line. //
2778 // //
2780 
2781 char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2782 {
2783  char *result;
2784 
2785  // Search for a non-empty line.
2786  do {
2787  result = fgets(string, INPUTLINESIZE - 1, infile);
2788  if (linenumber) (*linenumber)++;
2789  if (result == (char *) NULL) {
2790  return (char *) NULL;
2791  }
2792  // Skip white spaces.
2793  while ((*result == ' ') || (*result == '\t')) result++;
2794  // If it's end of line, read another line and try again.
2795  } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
2796  return result;
2797 }
2798 
2800 // //
2801 // findnextfield() Find the next field of a string. //
2802 // //
2803 // Jumps past the current field by searching for whitespace or a comma, then //
2804 // jumps past the whitespace or the comma to find the next field. //
2805 // //
2807 
2808 char* tetgenio::findnextfield(char *string)
2809 {
2810  char *result;
2811 
2812  result = string;
2813  // Skip the current field. Stop upon reaching whitespace or a comma.
2814  while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2815  (*result != ',') && (*result != ';')) {
2816  result++;
2817  }
2818  // Now skip the whitespace or the comma, stop at anything else that looks
2819  // like a character, or the end of a line.
2820  while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2821  (*result == ';')) {
2822  result++;
2823  }
2824  return result;
2825 }
2826 
2828 // //
2829 // readnumberline() Read a nonempty number line from a file. //
2830 // //
2831 // A line is considered "nonempty" if it contains something that looks like //
2832 // a number. Comments (prefaced by `#') are ignored. //
2833 // //
2835 
2836 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2837 {
2838  char *result;
2839 
2840  // Search for something that looks like a number.
2841  do {
2842  result = fgets(string, INPUTLINESIZE, infile);
2843  if (result == (char *) NULL) {
2844  return result;
2845  }
2846  // Skip anything that doesn't look like a number, a comment,
2847  // or the end of a line.
2848  while ((*result != '\0') && (*result != '#')
2849  && (*result != '.') && (*result != '+') && (*result != '-')
2850  && ((*result < '0') || (*result > '9'))) {
2851  result++;
2852  }
2853  // If it's a comment or end of line, read another line and try again.
2854  } while ((*result == '#') || (*result == '\0'));
2855  return result;
2856 }
2857 
2859 // //
2860 // findnextnumber() Find the next field of a number string. //
2861 // //
2862 // Jumps past the current field by searching for whitespace or a comma, then //
2863 // jumps past the whitespace or the comma to find the next field that looks //
2864 // like a number. //
2865 // //
2867 
2868 char* tetgenio::findnextnumber(char *string)
2869 {
2870  char *result;
2871 
2872  result = string;
2873  // Skip the current field. Stop upon reaching whitespace or a comma.
2874  while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2875  (*result != '\t') && (*result != ',')) {
2876  result++;
2877  }
2878  // Now skip the whitespace and anything else that doesn't look like a
2879  // number, a comment, or the end of a line.
2880  while ((*result != '\0') && (*result != '#')
2881  && (*result != '.') && (*result != '+') && (*result != '-')
2882  && ((*result < '0') || (*result > '9'))) {
2883  result++;
2884  }
2885  // Check for a comment (prefixed with `#').
2886  if (*result == '#') {
2887  *result = '\0';
2888  }
2889  return result;
2890 }
2891 
2895 
2899 
2901 // //
2902 // syntax() Print list of command line switches. //
2903 // //
2905 
2907 {
2908  printf(" tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
2909  printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
2910  printf(" -Y Preserves the input surface mesh (does not modify it).\n");
2911  printf(" -r Reconstructs a previously generated mesh.\n");
2912  printf(" -q Refines mesh (to improve mesh quality).\n");
2913  printf(" -R Mesh coarsening (to reduce the mesh elements).\n");
2914  printf(" -A Assigns attributes to tetrahedra in different regions.\n");
2915  printf(" -a Applies a maximum tetrahedron volume constraint.\n");
2916  printf(" -m Applies a mesh sizing function.\n");
2917  printf(" -i Inserts a list of additional points.\n");
2918  printf(" -O Specifies the level of mesh optimization.\n");
2919  printf(" -S Specifies maximum number of added points.\n");
2920  printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
2921  printf(" -X Suppresses use of exact arithmetic.\n");
2922  printf(" -M No merge of coplanar facets or very close vertices.\n");
2923  printf(" -w Generates weighted Delaunay (regular) triangulation.\n");
2924  printf(" -c Retains the convex hull of the PLC.\n");
2925  printf(" -d Detects self-intersections of facets of the PLC.\n");
2926  printf(" -z Numbers all output items starting from zero.\n");
2927  printf(" -f Outputs all faces to .face file.\n");
2928  printf(" -e Outputs all edges to .edge file.\n");
2929  printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
2930  printf(" -v Outputs Voronoi diagram to files.\n");
2931  printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
2932  printf(" -k Outputs mesh to .vtk file for viewing by Paraview.\n");
2933  printf(" -J No jettison of unused vertices from output .node file.\n");
2934  printf(" -B Suppresses output of boundary information.\n");
2935  printf(" -N Suppresses output of .node file.\n");
2936  printf(" -E Suppresses output of .ele file.\n");
2937  printf(" -F Suppresses output of .face and .edge file.\n");
2938  printf(" -I Suppresses mesh iteration numbers.\n");
2939  printf(" -C Checks the consistency of the final mesh.\n");
2940  printf(" -Q Quiet: No terminal output except errors.\n");
2941  printf(" -V Verbose: Detailed information, more terminal output.\n");
2942  printf(" -h Help: A brief instruction for using TetGen.\n");
2943 }
2944 
2946 // //
2947 // usage() Print a brief instruction for using TetGen. //
2948 // //
2950 
2952 {
2953  printf("TetGen\n");
2954  printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
2955  printf("Triangulator\n");
2956  printf("Version 1.5\n");
2957  printf("November 4, 2013\n");
2958  printf("\n");
2959  printf("What Can TetGen Do?\n");
2960  printf("\n");
2961  printf(" TetGen generates Delaunay tetrahedralizations, constrained\n");
2962  printf(" Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
2963  printf("\n");
2964  printf("Command Line Syntax:\n");
2965  printf("\n");
2966  printf(" Below is the basic command line syntax of TetGen with a list of ");
2967  printf("short\n");
2968  printf(" descriptions. Underscores indicate that numbers may optionally\n");
2969  printf(" follow certain switches. Do not leave any space between a ");
2970  printf("switch\n");
2971  printf(" and its numeric parameter. \'input_file\' contains input data\n");
2972  printf(" depending on the switches you supplied which may be a ");
2973  printf(" piecewise\n");
2974  printf(" linear complex or a list of nodes. File formats and detailed\n");
2975  printf(" description of command line switches are found in user's ");
2976  printf("manual.\n");
2977  printf("\n");
2978  syntax();
2979  printf("\n");
2980  printf("Examples of How to Use TetGen:\n");
2981  printf("\n");
2982  printf(" \'tetgen object\' reads vertices from object.node, and writes ");
2983  printf("their\n Delaunay tetrahedralization to object.1.node, ");
2984  printf("object.1.ele\n (tetrahedra), and object.1.face");
2985  printf(" (convex hull faces).\n");
2986  printf("\n");
2987  printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
2988  printf("smesh (and\n possibly object.node) and writes its constrained ");
2989  printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele, ");
2990  printf("object.1.face,\n");
2991  printf(" (boundary faces) and object.1.edge (boundary edges).\n");
2992  printf("\n");
2993  printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
2994  printf(" object.smesh (and possibly object.node), generates a mesh ");
2995  printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
2996  printf("have volume\n of 0.1 or less, and writes the mesh to ");
2997  printf("object.1.node, object.1.ele,\n object.1.face, and object.1.edge\n");
2998  printf("\n");
2999  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3000  terminatetetgen(NULL, 0);
3001 }
3002 
3004 // //
3005 // parse_commandline() Read the command line, identify switches, and set //
3006 // up options and file names. //
3007 // //
3008 // 'argc' and 'argv' are the same parameters passed to the function main() //
3009 // of a C/C++ program. They together represent the command line user invoked //
3010 // from an environment in which TetGen is running. //
3011 // //
3013 
3014 bool tetgenbehavior::parse_commandline(int argc, char **argv)
3015 {
3016  int startindex;
3017  int increment;
3018  int meshnumber;
3019  int i, j, k;
3020  char workstring[1024];
3021 
3022  // First determine the input style of the switches.
3023  if (argc == 0) {
3024  startindex = 0; // Switches are given without a dash.
3025  argc = 1; // For running the following for-loop once.
3026  commandline[0] = '\0';
3027  } else {
3028  startindex = 1;
3029  strcpy(commandline, argv[0]);
3030  strcat(commandline, " ");
3031  }
3032 
3033  for (i = startindex; i < argc; i++) {
3034  // Remember the command line for output.
3035  strcat(commandline, argv[i]);
3036  strcat(commandline, " ");
3037  if (startindex == 1) {
3038  // Is this string a filename?
3039  if (argv[i][0] != '-') {
3040  strncpy(infilename, argv[i], 1024 - 1);
3041  infilename[1024 - 1] = '\0';
3042  continue;
3043  }
3044  }
3045  // Parse the individual switch from the string.
3046  for (j = startindex; argv[i][j] != '\0'; j++) {
3047  if (argv[i][j] == 'p') {
3048  plc = 1;
3049  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3050  (argv[i][j + 1] == '.')) {
3051  k = 0;
3052  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3053  (argv[i][j + 1] == '.')) {
3054  j++;
3055  workstring[k] = argv[i][j];
3056  k++;
3057  }
3058  workstring[k] = '\0';
3059  facet_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3060  }
3061  } else if (argv[i][j] == 's') {
3062  psc = 1;
3063  } else if (argv[i][j] == 'Y') {
3064  nobisect = 1;
3065  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3066  nobisect_param = (argv[i][j + 1] - '0');
3067  j++;
3068  }
3069  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3070  j++;
3071  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3072  addsteiner_algo = (argv[i][j + 1] - '0');
3073  j++;
3074  }
3075  }
3076  } else if (argv[i][j] == 'r') {
3077  refine = 1;
3078  } else if (argv[i][j] == 'q') {
3079  quality = 1;
3080  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3081  (argv[i][j + 1] == '.')) {
3082  k = 0;
3083  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3084  (argv[i][j + 1] == '.')) {
3085  j++;
3086  workstring[k] = argv[i][j];
3087  k++;
3088  }
3089  workstring[k] = '\0';
3090  minratio = (REAL) strtod(workstring, (char **) NULL);
3091  }
3092  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3093  j++;
3094  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3095  (argv[i][j + 1] == '.')) {
3096  k = 0;
3097  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3098  (argv[i][j + 1] == '.')) {
3099  j++;
3100  workstring[k] = argv[i][j];
3101  k++;
3102  }
3103  workstring[k] = '\0';
3104  mindihedral = (REAL) strtod(workstring, (char **) NULL);
3105  }
3106  }
3107  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3108  j++;
3109  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3110  (argv[i][j + 1] == '.')) {
3111  k = 0;
3112  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3113  (argv[i][j + 1] == '.')) {
3114  j++;
3115  workstring[k] = argv[i][j];
3116  k++;
3117  }
3118  workstring[k] = '\0';
3119  optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3120  }
3121  }
3122  } else if (argv[i][j] == 'R') {
3123  coarsen = 1;
3124  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3125  coarsen_param = (argv[i][j + 1] - '0');
3126  j++;
3127  }
3128  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3129  j++;
3130  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3131  (argv[i][j + 1] == '.')) {
3132  k = 0;
3133  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3134  (argv[i][j + 1] == '.')) {
3135  j++;
3136  workstring[k] = argv[i][j];
3137  k++;
3138  }
3139  workstring[k] = '\0';
3140  coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
3141  }
3142  }
3143  } else if (argv[i][j] == 'w') {
3144  weighted = 1;
3145  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3146  weighted_param = (argv[i][j + 1] - '0');
3147  j++;
3148  }
3149  } else if (argv[i][j] == 'b') {
3150  // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
3151  brio_hilbert = 1;
3152  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3153  (argv[i][j + 1] == '.')) {
3154  k = 0;
3155  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3156  (argv[i][j + 1] == '.')) {
3157  j++;
3158  workstring[k] = argv[i][j];
3159  k++;
3160  }
3161  workstring[k] = '\0';
3162  brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
3163  }
3164  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3165  j++;
3166  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3167  (argv[i][j + 1] == '.')) {
3168  k = 0;
3169  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3170  (argv[i][j + 1] == '.')) {
3171  j++;
3172  workstring[k] = argv[i][j];
3173  k++;
3174  }
3175  workstring[k] = '\0';
3176  brio_ratio = (REAL) strtod(workstring, (char **) NULL);
3177  }
3178  }
3179  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3180  j++;
3181  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3182  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3183  k = 0;
3184  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3185  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3186  j++;
3187  workstring[k] = argv[i][j];
3188  k++;
3189  }
3190  workstring[k] = '\0';
3191  hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
3192  }
3193  }
3194  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3195  j++;
3196  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3197  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3198  k = 0;
3199  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3200  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3201  j++;
3202  workstring[k] = argv[i][j];
3203  k++;
3204  }
3205  workstring[k] = '\0';
3206  hilbert_order = (REAL) strtod(workstring, (char **) NULL);
3207  }
3208  }
3209  if (brio_threshold == 0) { // -b0
3210  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3211  }
3212  if (brio_ratio >= 1.0) { // -b/1
3213  no_sort = 1;
3214  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3215  }
3216  } else if (argv[i][j] == 'l') {
3217  incrflip = 1;
3218  } else if (argv[i][j] == 'L') {
3219  flipinsert = 1;
3220  } else if (argv[i][j] == 'm') {
3221  metric = 1;
3222  } else if (argv[i][j] == 'a') {
3223  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3224  (argv[i][j + 1] == '.')) {
3225  fixedvolume = 1;
3226  k = 0;
3227  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3228  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3229  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3230  j++;
3231  workstring[k] = argv[i][j];
3232  k++;
3233  }
3234  workstring[k] = '\0';
3235  maxvolume = (REAL) strtod(workstring, (char **) NULL);
3236  } else {
3237  varvolume = 1;
3238  }
3239  } else if (argv[i][j] == 'A') {
3240  regionattrib = 1;
3241  } else if (argv[i][j] == 'D') {
3242  conforming = 1;
3243  if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
3244  reflevel = (argv[i][j + 1] - '1') + 1;
3245  j++;
3246  }
3247  } else if (argv[i][j] == 'i') {
3248  insertaddpoints = 1;
3249  } else if (argv[i][j] == 'd') {
3250  diagnose = 1;
3251  } else if (argv[i][j] == 'c') {
3252  convex = 1;
3253  } else if (argv[i][j] == 'M') {
3254  nomergefacet = 1;
3255  nomergevertex = 1;
3256  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3257  nomergefacet = (argv[i][j + 1] - '0');
3258  j++;
3259  }
3260  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3261  j++;
3262  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3263  nomergevertex = (argv[i][j + 1] - '0');
3264  j++;
3265  }
3266  }
3267  } else if (argv[i][j] == 'X') {
3268  if (argv[i][j + 1] == '1') {
3269  nostaticfilter = 1;
3270  j++;
3271  } else {
3272  noexact = 1;
3273  }
3274  } else if (argv[i][j] == 'z') {
3275  zeroindex = 1;
3276  } else if (argv[i][j] == 'f') {
3277  facesout++;
3278  } else if (argv[i][j] == 'e') {
3279  edgesout++;
3280  } else if (argv[i][j] == 'n') {
3281  neighout++;
3282  } else if (argv[i][j] == 'v') {
3283  voroout = 1;
3284  } else if (argv[i][j] == 'g') {
3285  meditview = 1;
3286  } else if (argv[i][j] == 'k') {
3287  vtkview = 1;
3288  } else if (argv[i][j] == 'J') {
3289  nojettison = 1;
3290  } else if (argv[i][j] == 'B') {
3291  nobound = 1;
3292  } else if (argv[i][j] == 'N') {
3293  nonodewritten = 1;
3294  } else if (argv[i][j] == 'E') {
3295  noelewritten = 1;
3296  } else if (argv[i][j] == 'F') {
3297  nofacewritten = 1;
3298  } else if (argv[i][j] == 'I') {
3299  noiterationnum = 1;
3300  } else if (argv[i][j] == 'S') {
3301  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3302  (argv[i][j + 1] == '.')) {
3303  k = 0;
3304  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3305  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3306  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3307  j++;
3308  workstring[k] = argv[i][j];
3309  k++;
3310  }
3311  workstring[k] = '\0';
3312  steinerleft = (int) strtol(workstring, (char **) NULL, 0);
3313  }
3314  } else if (argv[i][j] == 'o') {
3315  if (argv[i][j + 1] == '2') {
3316  order = 2;
3317  j++;
3318  }
3319  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3320  j++;
3321  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3322  (argv[i][j + 1] == '.')) {
3323  k = 0;
3324  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3325  (argv[i][j + 1] == '.')) {
3326  j++;
3327  workstring[k] = argv[i][j];
3328  k++;
3329  }
3330  workstring[k] = '\0';
3331  optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3332  }
3333  }
3334  } else if (argv[i][j] == 'O') {
3335  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3336  optlevel = (argv[i][j + 1] - '0');
3337  j++;
3338  }
3339  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3340  j++;
3341  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
3342  optscheme = (argv[i][j + 1] - '0');
3343  j++;
3344  }
3345  }
3346  } else if (argv[i][j] == 'T') {
3347  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3348  (argv[i][j + 1] == '.')) {
3349  k = 0;
3350  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3351  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3352  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3353  j++;
3354  workstring[k] = argv[i][j];
3355  k++;
3356  }
3357  workstring[k] = '\0';
3358  epsilon = (REAL) strtod(workstring, (char **) NULL);
3359  }
3360  } else if (argv[i][j] == 'R') {
3361  reversetetori = 1;
3362  } else if (argv[i][j] == 'C') {
3363  docheck++;
3364  } else if (argv[i][j] == 'Q') {
3365  quiet = 1;
3366  } else if (argv[i][j] == 'V') {
3367  verbose++;
3368  } else if (argv[i][j] == 'x') {
3369  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3370  (argv[i][j + 1] == '.')) {
3371  k = 0;
3372  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3373  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3374  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3375  j++;
3376  workstring[k] = argv[i][j];
3377  k++;
3378  }
3379  workstring[k] = '\0';
3380  tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
3381  if (tetrahedraperblock > 8188) {
3384  } else {
3385  tetrahedraperblock = 8188;
3386  }
3387  }
3388  } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
3389  (argv[i][j] == '?')) {
3390  usage();
3391  } else {
3392  printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3393  }
3394  }
3395  }
3396 
3397  if (startindex == 0) {
3398  // Set a temporary filename for debugging output.
3399  strcpy(infilename, "tetgen-tmpfile");
3400  } else {
3401  if (infilename[0] == '\0') {
3402  // No input file name. Print the syntax and exit.
3403  syntax();
3404  terminatetetgen(NULL, 0);
3405  }
3406  // Recognize the object from file extension if it is available.
3407  if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3408  infilename[strlen(infilename) - 5] = '\0';
3409  object = NODES;
3410  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3411  infilename[strlen(infilename) - 5] = '\0';
3412  object = POLY;
3413  plc = 1;
3414  } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3415  infilename[strlen(infilename) - 6] = '\0';
3416  object = POLY;
3417  plc = 1;
3418  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3419  infilename[strlen(infilename) - 4] = '\0';
3420  object = OFF;
3421  plc = 1;
3422  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3423  infilename[strlen(infilename) - 4] = '\0';
3424  object = PLY;
3425  plc = 1;
3426  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3427  infilename[strlen(infilename) - 4] = '\0';
3428  object = STL;
3429  plc = 1;
3430  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3431  infilename[strlen(infilename) - 5] = '\0';
3432  object = MEDIT;
3433  if (!refine) plc = 1;
3434  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
3435  infilename[strlen(infilename) - 4] = '\0';
3436  object = VTK;
3437  plc = 1;
3438  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3439  infilename[strlen(infilename) - 4] = '\0';
3440  object = MESH;
3441  refine = 1;
3442  }
3443  }
3444 
3445  if (nobisect && (!plc && !refine)) { // -Y
3446  plc = 1; // Default -p option.
3447  }
3448  if (quality && (!plc && !refine)) { // -q
3449  plc = 1; // Default -p option.
3450  }
3451  if (diagnose && !plc) { // -d
3452  plc = 1;
3453  }
3454  if (refine && !quality) { // -r only
3455  // Reconstruct a mesh, no mesh optimization.
3456  optlevel = 0;
3457  }
3458  if (insertaddpoints && (optlevel == 0)) { // with -i option
3459  optlevel = 2;
3460  }
3461  if (coarsen && (optlevel == 0)) { // with -R option
3462  optlevel = 2;
3463  }
3464 
3465  // Detect improper combinations of switches.
3466  if ((refine || plc) && weighted) {
3467  printf("Error: Switches -w cannot use together with -p or -r.\n");
3468  return false;
3469  }
3470 
3471  if (convex) { // -c
3472  if (plc && !regionattrib) {
3473  // -A (region attribute) is needed for marking exterior tets (-1).
3474  regionattrib = 1;
3475  }
3476  }
3477 
3478  // Note: -A must not used together with -r option.
3479  // Be careful not to add an extra attribute to each element unless the
3480  // input supports it (PLC in, but not refining a preexisting mesh).
3481  if (refine || !plc) {
3482  regionattrib = 0;
3483  }
3484  // Be careful not to allocate space for element area constraints that
3485  // will never be assigned any value (other than the default -1.0).
3486  if (!refine && !plc) {
3487  varvolume = 0;
3488  }
3489  // If '-a' or '-aa' is in use, enable '-q' option too.
3490  if (fixedvolume || varvolume) {
3491  if (quality == 0) {
3492  quality = 1;
3493  if (!plc && !refine) {
3494  plc = 1; // enable -p.
3495  }
3496  }
3497  }
3498  // No user-specified dihedral angle bound. Use default ones.
3499  if (!quality) {
3500  if (optmaxdihedral < 179.0) {
3501  if (nobisect) { // with -Y option
3502  optmaxdihedral = 179.0;
3503  } else { // -p only
3504  optmaxdihedral = 179.999;
3505  }
3506  }
3507  if (optminsmtdihed < 179.999) {
3508  optminsmtdihed = 179.999;
3509  }
3510  if (optminslidihed < 179.999) {
3511  optminslidihed = 179.999;
3512  }
3513  }
3514 
3515  increment = 0;
3516  strcpy(workstring, infilename);
3517  j = 1;
3518  while (workstring[j] != '\0') {
3519  if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3520  increment = j + 1;
3521  }
3522  j++;
3523  }
3524  meshnumber = 0;
3525  if (increment > 0) {
3526  j = increment;
3527  do {
3528  if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3529  meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3530  } else {
3531  increment = 0;
3532  }
3533  j++;
3534  } while (workstring[j] != '\0');
3535  }
3536  if (noiterationnum) {
3537  strcpy(outfilename, infilename);
3538  } else if (increment == 0) {
3539  strcpy(outfilename, infilename);
3540  strcat(outfilename, ".1");
3541  } else {
3542  workstring[increment] = '%';
3543  workstring[increment + 1] = 'd';
3544  workstring[increment + 2] = '\0';
3545  sprintf(outfilename, workstring, meshnumber + 1);
3546  }
3547  // Additional input file name has the end ".a".
3548  strcpy(addinfilename, infilename);
3549  strcat(addinfilename, ".a");
3550  // Background filename has the form "*.b.ele", "*.b.node", ...
3551  strcpy(bgmeshfilename, infilename);
3552  strcat(bgmeshfilename, ".b");
3553 
3554  return true;
3555 }
3556 
3560 
3564 
3565 // Initialize fast lookup tables for mesh maniplulation primitives.
3566 
3567 int tetgenmesh::bondtbl[12][12] = {{0,},};
3568 int tetgenmesh::enexttbl[12] = {0,};
3569 int tetgenmesh::eprevtbl[12] = {0,};
3570 int tetgenmesh::enextesymtbl[12] = {0,};
3571 int tetgenmesh::eprevesymtbl[12] = {0,};
3572 int tetgenmesh::eorgoppotbl[12] = {0,};
3573 int tetgenmesh::edestoppotbl[12] = {0,};
3574 int tetgenmesh::fsymtbl[12][12] = {{0,},};
3575 int tetgenmesh::facepivot1[12] = {0,};
3576 int tetgenmesh::facepivot2[12][12] = {{0,},};
3577 int tetgenmesh::tsbondtbl[12][6] = {{0,},};
3578 int tetgenmesh::stbondtbl[12][6] = {{0,},};
3579 int tetgenmesh::tspivottbl[12][6] = {{0,},};
3580 int tetgenmesh::stpivottbl[12][6] = {{0,},};
3581 
3582 // Table 'esymtbl' takes an directed edge (version) as input, returns the
3583 // inversed edge (version) of it.
3584 
3585 int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
3586 
3587 // The following four tables give the 12 permutations of the set {0,1,2,3}.
3588 // An offset 4 is added to each element for a direct access of the points
3589 // in the tetrahedron data structure.
3590 
3591 int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
3592 int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
3593 int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
3594 int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
3595 
3596 // The twelve versions correspond to six undirected edges. The following two
3597 // tables map a version to an undirected edge and vice versa.
3598 
3599 int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
3600 int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
3601 
3602 // Edge versions whose apex or opposite may be dummypoint.
3603 
3604 int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
3605 
3606 
3607 // Table 'snextpivot' takes an edge version as input, returns the next edge
3608 // version in the same edge ring.
3609 
3610 int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
3611 
3612 // The following three tables give the 6 permutations of the set {0,1,2}.
3613 // An offset 3 is added to each element for a direct access of the points
3614 // in the triangle data structure.
3615 
3616 int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
3617 int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
3618 int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
3619 
3621 // //
3622 // inittable() Initialize the look-up tables. //
3623 // //
3625 
3627 {
3628  int i, j;
3629 
3630 
3631  // i = t1.ver; j = t2.ver;
3632  for (i = 0; i < 12; i++) {
3633  for (j = 0; j < 12; j++) {
3634  bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
3635  }
3636  }
3637 
3638 
3639  // i = t1.ver; j = t2.ver
3640  for (i = 0; i < 12; i++) {
3641  for (j = 0; j < 12; j++) {
3642  fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
3643  }
3644  }
3645 
3646 
3647  for (i = 0; i < 12; i++) {
3648  facepivot1[i] = (esymtbl[i] & 3);
3649  }
3650 
3651  for (i = 0; i < 12; i++) {
3652  for (j = 0; j < 12; j++) {
3653  facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
3654  }
3655  }
3656 
3657  for (i = 0; i < 12; i++) {
3658  enexttbl[i] = (i + 4) % 12;
3659  eprevtbl[i] = (i + 8) % 12;
3660  }
3661 
3662  for (i = 0; i < 12; i++) {
3663  enextesymtbl[i] = esymtbl[enexttbl[i]];
3664  eprevesymtbl[i] = esymtbl[eprevtbl[i]];
3665  }
3666 
3667  for (i = 0; i < 12; i++) {
3668  eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
3669  edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
3670  }
3671 
3672  int soffset, toffset;
3673 
3674  // i = t.ver, j = s.shver
3675  for (i = 0; i < 12; i++) {
3676  for (j = 0; j < 6; j++) {
3677  if ((j & 1) == 0) {
3678  soffset = (6 - ((i & 12) >> 1)) % 6;
3679  toffset = (12 - ((j & 6) << 1)) % 12;
3680  } else {
3681  soffset = (i & 12) >> 1;
3682  toffset = (j & 6) << 1;
3683  }
3684  tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3685  stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3686  }
3687  }
3688 
3689 
3690  // i = t.ver, j = s.shver
3691  for (i = 0; i < 12; i++) {
3692  for (j = 0; j < 6; j++) {
3693  if ((j & 1) == 0) {
3694  soffset = (i & 12) >> 1;
3695  toffset = (j & 6) << 1;
3696  } else {
3697  soffset = (6 - ((i & 12) >> 1)) % 6;
3698  toffset = (12 - ((j & 6) << 1)) % 12;
3699  }
3700  tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3701  stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3702  }
3703  }
3704 }
3705 
3707 // //
3708 // restart() Deallocate all objects in this pool. //
3709 // //
3710 // The pool returns to a fresh state, like after it was initialized, except //
3711 // that no memory is freed to the operating system. Rather, the previously //
3712 // allocated blocks are ready to be used. //
3713 // //
3715 
3717 {
3718  objects = 0l;
3719 }
3720 
3722 // //
3723 // poolinit() Initialize an arraypool for allocation of objects. //
3724 // //
3725 // Before the pool may be used, it must be initialized by this procedure. //
3726 // After initialization, memory can be allocated and freed in this pool. //
3727 // //
3729 
3730 void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
3731 {
3732  // Each object must be at least one byte long.
3733  objectbytes = sizeofobject > 1 ? sizeofobject : 1;
3734 
3735  log2objectsperblock = log2objperblk;
3736  // Compute the number of objects in each block.
3737  objectsperblock = ((int) 1) << log2objectsperblock;
3738  objectsperblockmark = objectsperblock - 1;
3739 
3740  // No memory has been allocated.
3741  totalmemory = 0l;
3742  // The top array has not been allocated yet.
3743  toparray = (char **) NULL;
3744  toparraylen = 0;
3745 
3746  // Ready all indices to be allocated.
3747  restart();
3748 }
3749 
3751 // //
3752 // arraypool() The constructor and destructor. //
3753 // //
3755 
3756 tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
3757 {
3758  poolinit(sizeofobject, log2objperblk);
3759 }
3760 
3762 {
3763  int i;
3764 
3765  // Has anything been allocated at all?
3766  if (toparray != (char **) NULL) {
3767  // Walk through the top array.
3768  for (i = 0; i < toparraylen; i++) {
3769  // Check every pointer; NULLs may be scattered randomly.
3770  if (toparray[i] != (char *) NULL) {
3771  // Free an allocated block.
3772  free((void *) toparray[i]);
3773  }
3774  }
3775  // Free the top array.
3776  free((void *) toparray);
3777  }
3778 
3779  // The top array is no longer allocated.
3780  toparray = (char **) NULL;
3781  toparraylen = 0;
3782  objects = 0;
3783  totalmemory = 0;
3784 }
3785 
3787 // //
3788 // getblock() Return (and perhaps create) the block containing the object //
3789 // with a given index. //
3790 // //
3791 // This function takes care of allocating or resizing the top array if nece- //
3792 // ssary, and of allocating the block if it hasn't yet been allocated. //
3793 // //
3794 // Return a pointer to the beginning of the block (NOT the object). //
3795 // //
3797 
3798 char* tetgenmesh::arraypool::getblock(int objectindex)
3799 {
3800  char **newarray;
3801  char *block;
3802  int newsize;
3803  int topindex;
3804  int i;
3805 
3806  // Compute the index in the top array (upper bits).
3807  topindex = objectindex >> log2objectsperblock;
3808  // Does the top array need to be allocated or resized?
3809  if (toparray == (char **) NULL) {
3810  // Allocate the top array big enough to hold 'topindex', and NULL out
3811  // its contents.
3812  newsize = topindex + 128;
3813  toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3814  toparraylen = newsize;
3815  for (i = 0; i < newsize; i++) {
3816  toparray[i] = (char *) NULL;
3817  }
3818  // Account for the memory.
3819  totalmemory = newsize * (uintptr_t) sizeof(char *);
3820  } else if (topindex >= toparraylen) {
3821  // Resize the top array, making sure it holds 'topindex'.
3822  newsize = 3 * toparraylen;
3823  if (topindex >= newsize) {
3824  newsize = topindex + 128;
3825  }
3826  // Allocate the new array, copy the contents, NULL out the rest, and
3827  // free the old array.
3828  newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3829  for (i = 0; i < toparraylen; i++) {
3830  newarray[i] = toparray[i];
3831  }
3832  for (i = toparraylen; i < newsize; i++) {
3833  newarray[i] = (char *) NULL;
3834  }
3835  free(toparray);
3836  // Account for the memory.
3837  totalmemory += (newsize - toparraylen) * sizeof(char *);
3838  toparray = newarray;
3839  toparraylen = newsize;
3840  }
3841 
3842  // Find the block, or learn that it hasn't been allocated yet.
3843  block = toparray[topindex];
3844  if (block == (char *) NULL) {
3845  // Allocate a block at this index.
3846  block = (char *) malloc((size_t) (objectsperblock * objectbytes));
3847  toparray[topindex] = block;
3848  // Account for the memory.
3849  totalmemory += objectsperblock * objectbytes;
3850  }
3851 
3852  // Return a pointer to the block.
3853  return block;
3854 }
3855 
3857 // //
3858 // lookup() Return the pointer to the object with a given index, or NULL //
3859 // if the object's block doesn't exist yet. //
3860 // //
3862 
3863 void* tetgenmesh::arraypool::lookup(int objectindex)
3864 {
3865  char *block;
3866  int topindex;
3867 
3868  // Has the top array been allocated yet?
3869  if (toparray == (char **) NULL) {
3870  return (void *) NULL;
3871  }
3872 
3873  // Compute the index in the top array (upper bits).
3874  topindex = objectindex >> log2objectsperblock;
3875  // Does the top index fit in the top array?
3876  if (topindex >= toparraylen) {
3877  return (void *) NULL;
3878  }
3879 
3880  // Find the block, or learn that it hasn't been allocated yet.
3881  block = toparray[topindex];
3882  if (block == (char *) NULL) {
3883  return (void *) NULL;
3884  }
3885 
3886  // Compute a pointer to the object with the given index. Note that
3887  // 'objectsperblock' is a power of two, so the & operation is a bit mask
3888  // that preserves the lower bits.
3889  return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
3890 }
3891 
3893 // //
3894 // newindex() Allocate space for a fresh object from the pool. //
3895 // //
3896 // 'newptr' returns a pointer to the new object (it must not be a NULL). //
3897 // //
3899 
3901 {
3902  // Allocate an object at index 'firstvirgin'.
3903  int newindex = objects;
3904  *newptr = (void *) (getblock(objects) +
3905  (objects & (objectsperblock - 1)) * objectbytes);
3906  objects++;
3907 
3908  return newindex;
3909 }
3910 
3911 
3913 // //
3914 // memorypool() The constructors of memorypool. //
3915 // //
3917 
3919 {
3920  firstblock = nowblock = (void **) NULL;
3921  nextitem = (void *) NULL;
3922  deaditemstack = (void *) NULL;
3923  pathblock = (void **) NULL;
3924  pathitem = (void *) NULL;
3925  alignbytes = 0;
3926  itembytes = itemwords = 0;
3927  itemsperblock = 0;
3928  items = maxitems = 0l;
3929  unallocateditems = 0;
3930  pathitemsleft = 0;
3931 }
3932 
3933 tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
3934  int alignment)
3935 {
3936  poolinit(bytecount, itemcount, wsize, alignment);
3937 }
3938 
3940 // //
3941 // ~memorypool() Free to the operating system all memory taken by a pool. //
3942 // //
3944 
3946 {
3947  while (firstblock != (void **) NULL) {
3948  nowblock = (void **) *(firstblock);
3949  free(firstblock);
3950  firstblock = nowblock;
3951  }
3952 }
3953 
3955 // //
3956 // poolinit() Initialize a pool of memory for allocation of items. //
3957 // //
3958 // A `pool' is created whose records have size at least `bytecount'. Items //
3959 // will be allocated in `itemcount'-item blocks. Each item is assumed to be //
3960 // a collection of words, and either pointers or floating-point values are //
3961 // assumed to be the "primary" word type. (The "primary" word type is used //
3962 // to determine alignment of items.) If `alignment' isn't zero, all items //
3963 // will be `alignment'-byte aligned in memory. `alignment' must be either a //
3964 // multiple or a factor of the primary word size; powers of two are safe. //
3965 // `alignment' is normally used to create a few unused bits at the bottom of //
3966 // each item's pointer, in which information may be stored. //
3967 // //
3969 
3970 void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
3971  int alignment)
3972 {
3973  // Find the proper alignment, which must be at least as large as:
3974  // - The parameter `alignment'.
3975  // - The primary word type, to avoid unaligned accesses.
3976  // - sizeof(void *), so the stack of dead items can be maintained
3977  // without unaligned accesses.
3978  if (alignment > wordsize) {
3979  alignbytes = alignment;
3980  } else {
3981  alignbytes = wordsize;
3982  }
3983  if ((int) sizeof(void *) > alignbytes) {
3984  alignbytes = (int) sizeof(void *);
3985  }
3986  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
3987  * (alignbytes / wordsize);
3988  itembytes = itemwords * wordsize;
3989  itemsperblock = itemcount;
3990 
3991  // Allocate a block of items. Space for `itemsperblock' items and one
3992  // pointer (to point to the next block) are allocated, as well as space
3993  // to ensure alignment of the items.
3994  firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
3995  + alignbytes);
3996  if (firstblock == (void **) NULL) {
3997  terminatetetgen(NULL, 1);
3998  }
3999  // Set the next block pointer to NULL.
4000  *(firstblock) = (void *) NULL;
4001  restart();
4002 }
4003 
4005 // //
4006 // restart() Deallocate all items in this pool. //
4007 // //
4008 // The pool is returned to its starting state, except that no memory is //
4009 // freed to the operating system. Rather, the previously allocated blocks //
4010 // are ready to be reused. //
4011 // //
4013 
4015 {
4016  uintptr_t alignptr;
4017 
4018  items = 0;
4019  maxitems = 0;
4020 
4021  // Set the currently active block.
4022  nowblock = firstblock;
4023  // Find the first item in the pool. Increment by the size of (void *).
4024  alignptr = (uintptr_t) (nowblock + 1);
4025  // Align the item on an `alignbytes'-byte boundary.
4026  nextitem = (void *)
4027  (alignptr + (uintptr_t) alignbytes -
4028  (alignptr % (uintptr_t) alignbytes));
4029  // There are lots of unallocated items left in this block.
4030  unallocateditems = itemsperblock;
4031  // The stack of deallocated items is empty.
4032  deaditemstack = (void *) NULL;
4033 }
4034 
4036 // //
4037 // alloc() Allocate space for an item. //
4038 // //
4040 
4042 {
4043  void *newitem;
4044  void **newblock;
4045  uintptr_t alignptr;
4046 
4047  // First check the linked list of dead items. If the list is not
4048  // empty, allocate an item from the list rather than a fresh one.
4049  if (deaditemstack != (void *) NULL) {
4050  newitem = deaditemstack; // Take first item in list.
4051  deaditemstack = * (void **) deaditemstack;
4052  } else {
4053  // Check if there are any free items left in the current block.
4054  if (unallocateditems == 0) {
4055  // Check if another block must be allocated.
4056  if (*nowblock == (void *) NULL) {
4057  // Allocate a new block of items, pointed to by the previous block.
4058  newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4059  + alignbytes);
4060  if (newblock == (void **) NULL) {
4061  terminatetetgen(NULL, 1);
4062  }
4063  *nowblock = (void *) newblock;
4064  // The next block pointer is NULL.
4065  *newblock = (void *) NULL;
4066  }
4067  // Move to the new block.
4068  nowblock = (void **) *nowblock;
4069  // Find the first item in the block.
4070  // Increment by the size of (void *).
4071  alignptr = (uintptr_t) (nowblock + 1);
4072  // Align the item on an `alignbytes'-byte boundary.
4073  nextitem = (void *)
4074  (alignptr + (uintptr_t) alignbytes -
4075  (alignptr % (uintptr_t) alignbytes));
4076  // There are lots of unallocated items left in this block.
4077  unallocateditems = itemsperblock;
4078  }
4079  // Allocate a new item.
4080  newitem = nextitem;
4081  // Advance `nextitem' pointer to next free item in block.
4082  nextitem = (void *) ((uintptr_t) nextitem + itembytes);
4083  unallocateditems--;
4084  maxitems++;
4085  }
4086  items++;
4087  return newitem;
4088 }
4089 
4091 // //
4092 // dealloc() Deallocate space for an item. //
4093 // //
4094 // The deallocated space is stored in a queue for later reuse. //
4095 // //
4097 
4098 void tetgenmesh::memorypool::dealloc(void *dyingitem)
4099 {
4100  // Push freshly killed item onto stack.
4101  *((void **) dyingitem) = deaditemstack;
4102  deaditemstack = dyingitem;
4103  items--;
4104 }
4105 
4107 // //
4108 // traversalinit() Prepare to traverse the entire list of items. //
4109 // //
4110 // This routine is used in conjunction with traverse(). //
4111 // //
4113 
4115 {
4116  uintptr_t alignptr;
4117 
4118  // Begin the traversal in the first block.
4119  pathblock = firstblock;
4120  // Find the first item in the block. Increment by the size of (void *).
4121  alignptr = (uintptr_t) (pathblock + 1);
4122  // Align with item on an `alignbytes'-byte boundary.
4123  pathitem = (void *)
4124  (alignptr + (uintptr_t) alignbytes -
4125  (alignptr % (uintptr_t) alignbytes));
4126  // Set the number of items left in the current block.
4127  pathitemsleft = itemsperblock;
4128 }
4129 
4131 // //
4132 // traverse() Find the next item in the list. //
4133 // //
4134 // This routine is used in conjunction with traversalinit(). Be forewarned //
4135 // that this routine successively returns all items in the list, including //
4136 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
4137 // ones are actually dead. It can usually be done more space-efficiently by //
4138 // a routine that knows something about the structure of the item. //
4139 // //
4141 
4143 {
4144  void *newitem;
4145  uintptr_t alignptr;
4146 
4147  // Stop upon exhausting the list of items.
4148  if (pathitem == nextitem) {
4149  return (void *) NULL;
4150  }
4151  // Check whether any untraversed items remain in the current block.
4152  if (pathitemsleft == 0) {
4153  // Find the next block.
4154  pathblock = (void **) *pathblock;
4155  // Find the first item in the block. Increment by the size of (void *).
4156  alignptr = (uintptr_t) (pathblock + 1);
4157  // Align with item on an `alignbytes'-byte boundary.
4158  pathitem = (void *)
4159  (alignptr + (uintptr_t) alignbytes -
4160  (alignptr % (uintptr_t) alignbytes));
4161  // Set the number of items left in the current block.
4162  pathitemsleft = itemsperblock;
4163  }
4164  newitem = pathitem;
4165  // Find the next item in the block.
4166  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
4167  pathitemsleft--;
4168  return newitem;
4169 }
4170 
4172 // //
4173 // makeindex2pointmap() Create a map from index to vertices. //
4174 // //
4175 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
4176 // to each vertex is set into the array. The pointer to the first vertex is //
4177 // saved in 'idx2verlist[in->firstnumber]'. //
4178 // //
4180 
4182 {
4183  point pointloop;
4184  int idx;
4185 
4186  if (b->verbose > 1) {
4187  printf(" Constructing mapping from indices to points.\n");
4188  }
4189 
4190  idx2verlist = new point[points->items + 1];
4191 
4192  points->traversalinit();
4193  pointloop = pointtraverse();
4194  idx = in->firstnumber;
4195  while (pointloop != (point) NULL) {
4196  idx2verlist[idx++] = pointloop;
4197  pointloop = pointtraverse();
4198  }
4199 }
4200 
4202 // //
4203 // makesubfacemap() Create a map from vertex to subfaces incident at it. //
4204 // //
4205 // The map is returned in two arrays 'idx2faclist' and 'facperverlist'. All //
4206 // subfaces incident at i-th vertex (i is counted from 0) are found in the //
4207 // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1]. //
4208 // Each entry in facperverlist[j] is a subface whose origin is the vertex. //
4209 // //
4210 // NOTE: These two arrays will be created inside this routine, don't forget //
4211 // to free them after using. //
4212 // //
4214 
4215 void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
4216  face*& facperverlist)
4217 {
4218  face shloop;
4219  int i, j, k;
4220 
4221  if (b->verbose > 1) {
4222  printf(" Making a map from points to subfaces.\n");
4223  }
4224 
4225  // Initialize 'idx2faclist'.
4226  idx2faclist = new int[points->items + 1];
4227  for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
4228 
4229  // Loop all subfaces, counter the number of subfaces incident at a vertex.
4230  pool->traversalinit();
4231  shloop.sh = shellfacetraverse(pool);
4232  while (shloop.sh != (shellface *) NULL) {
4233  // Increment the number of incident subfaces for each vertex.
4234  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4235  idx2faclist[j]++;
4236  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4237  idx2faclist[j]++;
4238  // Skip the third corner if it is a segment.
4239  if (shloop.sh[5] != NULL) {
4240  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4241  idx2faclist[j]++;
4242  }
4243  shloop.sh = shellfacetraverse(pool);
4244  }
4245 
4246  // Calculate the total length of array 'facperverlist'.
4247  j = idx2faclist[0];
4248  idx2faclist[0] = 0; // Array starts from 0 element.
4249  for (i = 0; i < points->items; i++) {
4250  k = idx2faclist[i + 1];
4251  idx2faclist[i + 1] = idx2faclist[i] + j;
4252  j = k;
4253  }
4254 
4255  // The total length is in the last unit of idx2faclist.
4256  facperverlist = new face[idx2faclist[i]];
4257 
4258  // Loop all subfaces again, remember the subfaces at each vertex.
4259  pool->traversalinit();
4260  shloop.sh = shellfacetraverse(pool);
4261  while (shloop.sh != (shellface *) NULL) {
4262  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4263  shloop.shver = 0; // save the origin.
4264  facperverlist[idx2faclist[j]] = shloop;
4265  idx2faclist[j]++;
4266  // Is it a subface or a subsegment?
4267  if (shloop.sh[5] != NULL) {
4268  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4269  shloop.shver = 2; // save the origin.
4270  facperverlist[idx2faclist[j]] = shloop;
4271  idx2faclist[j]++;
4272  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4273  shloop.shver = 4; // save the origin.
4274  facperverlist[idx2faclist[j]] = shloop;
4275  idx2faclist[j]++;
4276  } else {
4277  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4278  shloop.shver = 1; // save the origin.
4279  facperverlist[idx2faclist[j]] = shloop;
4280  idx2faclist[j]++;
4281  }
4282  shloop.sh = shellfacetraverse(pool);
4283  }
4284 
4285  // Contents in 'idx2faclist' are shifted, now shift them back.
4286  for (i = points->items - 1; i >= 0; i--) {
4287  idx2faclist[i + 1] = idx2faclist[i];
4288  }
4289  idx2faclist[0] = 0;
4290 }
4291 
4293 // //
4294 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
4295 // //
4297 
4299 {
4300  // Set tetrahedron's vertices to NULL. This makes it possible to detect
4301  // dead tetrahedra when traversing the list of all tetrahedra.
4302  dyingtetrahedron[4] = (tetrahedron) NULL;
4303 
4304  // Dealloc the space to subfaces/subsegments.
4305  if (dyingtetrahedron[8] != NULL) {
4306  tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
4307  }
4308  if (dyingtetrahedron[9] != NULL) {
4309  tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
4310  }
4311 
4312  tetrahedrons->dealloc((void *) dyingtetrahedron);
4313 }
4314 
4316 // //
4317 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
4318 // //
4320 
4322 {
4323  tetrahedron *newtetrahedron;
4324 
4325  do {
4326  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4327  if (newtetrahedron == (tetrahedron *) NULL) {
4328  return (tetrahedron *) NULL;
4329  }
4330  } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
4331  ((point) newtetrahedron[7] == dummypoint));
4332  return newtetrahedron;
4333 }
4334 
4336 {
4337  tetrahedron *newtetrahedron;
4338 
4339  do {
4340  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4341  if (newtetrahedron == (tetrahedron *) NULL) {
4342  return (tetrahedron *) NULL;
4343  }
4344  } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
4345  return newtetrahedron;
4346 }
4347 
4349 // //
4350 // shellfacedealloc() Deallocate space for a shellface, marking it dead. //
4351 // Used both for dealloc a subface and subsegment. //
4352 // //
4354 
4356 {
4357  // Set shellface's vertices to NULL. This makes it possible to detect dead
4358  // shellfaces when traversing the list of all shellfaces.
4359  dyingsh[3] = (shellface) NULL;
4360  pool->dealloc((void *) dyingsh);
4361 }
4362 
4364 // //
4365 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
4366 // for both subfaces and subsegments pool traverse. //
4367 // //
4369 
4371 {
4372  shellface *newshellface;
4373 
4374  do {
4375  newshellface = (shellface *) pool->traverse();
4376  if (newshellface == (shellface *) NULL) {
4377  return (shellface *) NULL;
4378  }
4379  } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
4380  return newshellface;
4381 }
4382 
4383 
4385 // //
4386 // pointdealloc() Deallocate space for a point, marking it dead. //
4387 // //
4389 
4391 {
4392  // Mark the point as dead. This makes it possible to detect dead points
4393  // when traversing the list of all points.
4394  setpointtype(dyingpoint, DEADVERTEX);
4395  points->dealloc((void *) dyingpoint);
4396 }
4397 
4399 // //
4400 // pointtraverse() Traverse the points, skipping dead ones. //
4401 // //
4403 
4405 {
4406  point newpoint;
4407 
4408  do {
4409  newpoint = (point) points->traverse();
4410  if (newpoint == (point) NULL) {
4411  return (point) NULL;
4412  }
4413  } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
4414  return newpoint;
4415 }
4416 
4418 // //
4419 // maketetrahedron() Create a new tetrahedron. //
4420 // //
4422 
4424 {
4425  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
4426 
4427  // Initialize the four adjoining tetrahedra to be "outer space".
4428  newtet->tet[0] = NULL;
4429  newtet->tet[1] = NULL;
4430  newtet->tet[2] = NULL;
4431  newtet->tet[3] = NULL;
4432  // Four NULL vertices.
4433  newtet->tet[4] = NULL;
4434  newtet->tet[5] = NULL;
4435  newtet->tet[6] = NULL;
4436  newtet->tet[7] = NULL;
4437  // No attached segments and subfaces yet.
4438  newtet->tet[8] = NULL;
4439  newtet->tet[9] = NULL;
4440  // Initialize the marker (clear all flags).
4441  setelemmarker(newtet->tet, 0);
4442  for (int i = 0; i < numelemattrib; i++) {
4443  setelemattribute(newtet->tet, i, 0.0);
4444  }
4445  if (b->varvolume) {
4446  setvolumebound(newtet->tet, -1.0);
4447  }
4448 
4449  // Initialize the version to be Zero.
4450  newtet->ver = 11;
4451 }
4452 
4454 // //
4455 // makeshellface() Create a new shellface with version zero. Used for //
4456 // both subfaces and subsegments. //
4457 // //
4459 
4461 {
4462  newface->sh = (shellface *) pool->alloc();
4463 
4464  // No adjointing subfaces.
4465  newface->sh[0] = NULL;
4466  newface->sh[1] = NULL;
4467  newface->sh[2] = NULL;
4468  // Three NULL vertices.
4469  newface->sh[3] = NULL;
4470  newface->sh[4] = NULL;
4471  newface->sh[5] = NULL;
4472  // No adjoining subsegments.
4473  newface->sh[6] = NULL;
4474  newface->sh[7] = NULL;
4475  newface->sh[8] = NULL;
4476  // No adjoining tetrahedra.
4477  newface->sh[9] = NULL;
4478  newface->sh[10] = NULL;
4479  if (checkconstraints) {
4480  // Initialize the maximum area bound.
4481  setareabound(*newface, 0.0);
4482  }
4483  // Clear the infection and marktest bits.
4484  ((int *) (newface->sh))[shmarkindex + 1] = 0;
4485  if (useinsertradius) {
4486  setfacetindex(*newface, 0);
4487  }
4488  // Set the boundary marker to zero.
4489  setshellmark(*newface, 0);
4490 
4491  newface->shver = 0;
4492 }
4493 
4495 // //
4496 // makepoint() Create a new point. //
4497 // //
4499 
4500 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
4501 {
4502  int i;
4503 
4504  *pnewpoint = (point) points->alloc();
4505 
4506  // Initialize the point attributes.
4507  for (i = 0; i < numpointattrib; i++) {
4508  (*pnewpoint)[3 + i] = 0.0;
4509  }
4510  // Initialize the metric tensor.
4511  for (i = 0; i < sizeoftensor; i++) {
4512  (*pnewpoint)[pointmtrindex + i] = 0.0;
4513  }
4514  setpoint2tet(*pnewpoint, NULL);
4515  setpoint2ppt(*pnewpoint, NULL);
4516  if (b->plc || b->refine) {
4517  // Initialize the point-to-simplex field.
4518  setpoint2sh(*pnewpoint, NULL);
4519  if (b->metric && (bgm != NULL)) {
4520  setpoint2bgmtet(*pnewpoint, NULL);
4521  }
4522  }
4523  // Initialize the point marker (starting from in->firstnumber).
4524  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
4525  // Clear all flags.
4526  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
4527  // Initialize (set) the point type.
4528  setpointtype(*pnewpoint, vtype);
4529 }
4530 
4532 // //
4533 // initializepools() Calculate the sizes of the point, tetrahedron, and //
4534 // subface. Initialize their memory pools. //
4535 // //
4536 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
4537 // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'. They are //
4538 // used to find values within each point and tetrahedron, respectively. //
4539 // //
4541 
4543 {
4544  int pointsize = 0, elesize = 0, shsize = 0;
4545  int i;
4546 
4547  if (b->verbose) {
4548  printf(" Initializing memorypools.\n");
4549  printf(" tetrahedron per block: %d.\n", b->tetrahedraperblock);
4550  }
4551 
4552  inittables();
4553 
4554  // There are three input point lists available, which are in, addin,
4555  // and bgm->in. These point lists may have different number of
4556  // attributes. Decide the maximum number.
4558  if (bgm != NULL) {
4561  }
4562  }
4563  if (addin != NULL) {
4566  }
4567  }
4568  if (b->weighted || b->flipinsert) { // -w or -L.
4569  // The internal number of point attribute needs to be at least 1
4570  // (for storing point weights).
4571  if (numpointattrib == 0) {
4572  numpointattrib = 1;
4573  }
4574  }
4575 
4576  // Default varconstraint = 0;
4578  checkconstraints = 1;
4579  }
4580  if (b->plc || b->refine) {
4581  // Save the insertion radius for Steiner points if boundaries
4582  // are allowed be split.
4583  if (!b->nobisect || checkconstraints) {
4584  useinsertradius = 1;
4585  }
4586  }
4587 
4588  // The index within each point at which its metric tensor is found.
4589  // Each vertex has three coordinates.
4590  if (b->psc) {
4591  // '-s' option (PSC), the u,v coordinates are provided.
4593  // The index within each point at which its u, v coordinates are found.
4594  // Comment: They are saved after the list of point attributes.
4596  } else {
4598  }
4599  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
4600  if (b->metric) {
4601  // Decide the size (1, 3, or 6) of the metric tensor.
4602  if (bgm != (tetgenmesh *) NULL) {
4603  // A background mesh is allocated. It may not exist though.
4604  sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
4606  } else {
4607  // No given background mesh - Itself is a background mesh.
4609  }
4610  // Make sure sizeoftensor is at least 1.
4611  sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
4612  } else {
4613  // For '-q' option. Make sure to have space for saving a scalar value.
4614  sizeoftensor = b->quality ? 1 : 0;
4615  }
4616  if (useinsertradius) {
4617  // Increase a space (REAL) for saving point insertion radius, it is
4618  // saved directly after the metric.
4619  sizeoftensor++;
4620  }
4621  // The index within each point at which an element pointer is found, where
4622  // the index is measured in pointers. Ensure the index is aligned to a
4623  // sizeof(tetrahedron)-byte address.
4625  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
4626  if (b->plc || b->refine || b->voroout) {
4627  // Increase the point size by three pointers, which are:
4628  // - a pointer to a tet, read by point2tet();
4629  // - a pointer to a parent point, read by point2ppt()).
4630  // - a pointer to a subface or segment, read by point2sh();
4631  if (b->metric && (bgm != (tetgenmesh *) NULL)) {
4632  // Increase one pointer into the background mesh, point2bgmtet().
4633  pointsize = (point2simindex + 4) * sizeof(tetrahedron);
4634  } else {
4635  pointsize = (point2simindex + 3) * sizeof(tetrahedron);
4636  }
4637  } else {
4638  // Increase the point size by two pointer, which are:
4639  // - a pointer to a tet, read by point2tet();
4640  // - a pointer to a parent point, read by point2ppt()). -- Used by btree.
4641  pointsize = (point2simindex + 2) * sizeof(tetrahedron);
4642  }
4643  // The index within each point at which the boundary marker is found,
4644  // Ensure the point marker is aligned to a sizeof(int)-byte address.
4645  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
4646  // Now point size is the ints (indicated by pointmarkindex) plus:
4647  // - an integer for boundary marker;
4648  // - an integer for vertex type;
4649  // - an integer for geometry tag (optional, -s option).
4650  pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
4651 
4652  // Initialize the pool of vertices.
4653  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
4654 
4655  if (b->verbose) {
4656  printf(" Size of a point: %d bytes.\n", points->itembytes);
4657  }
4658 
4659  // Initialize the infinite vertex.
4660  dummypoint = (point) new char[pointsize];
4661  // Initialize all fields of this point.
4662  dummypoint[0] = 0.0;
4663  dummypoint[1] = 0.0;
4664  dummypoint[2] = 0.0;
4665  for (i = 0; i < numpointattrib; i++) {
4666  dummypoint[3 + i] = 0.0;
4667  }
4668  // Initialize the metric tensor.
4669  for (i = 0; i < sizeoftensor; i++) {
4670  dummypoint[pointmtrindex + i] = 0.0;
4671  }
4672  setpoint2tet(dummypoint, NULL);
4673  setpoint2ppt(dummypoint, NULL);
4674  if (b->plc || b->psc || b->refine) {
4675  // Initialize the point-to-simplex field.
4676  setpoint2sh(dummypoint, NULL);
4677  if (b->metric && (bgm != NULL)) {
4678  setpoint2bgmtet(dummypoint, NULL);
4679  }
4680  }
4681  // Initialize the point marker (starting from in->firstnumber).
4682  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
4683  // Clear all flags.
4684  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
4685  // Initialize (set) the point type.
4686  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
4687 
4688  // The number of bytes occupied by a tetrahedron is varying by the user-
4689  // specified options. The contents of the first 12 pointers are listed
4690  // in the following table:
4691  // [0] |__ neighbor at f0 __|
4692  // [1] |__ neighbor at f1 __|
4693  // [2] |__ neighbor at f2 __|
4694  // [3] |__ neighbor at f3 __|
4695  // [4] |_____ vertex p0 ____|
4696  // [5] |_____ vertex p1 ____|
4697  // [6] |_____ vertex p2 ____|
4698  // [7] |_____ vertex p3 ____|
4699  // [8] |__ segments array __| (used by -p)
4700  // [9] |__ subfaces array __| (used by -p)
4701  // [10] |_____ reserved _____|
4702  // [11] |___ elem marker ____| (used as an integer)
4703 
4704  elesize = 12 * sizeof(tetrahedron);
4705 
4706  // The index to find the element markers. An integer containing varies
4707  // flags and element counter.
4708  assert(sizeof(int) <= sizeof(tetrahedron));
4709  assert((sizeof(tetrahedron) % sizeof(int)) == 0);
4710  elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
4711 
4712  // The actual number of element attributes. Note that if the
4713  // `b->regionattrib' flag is set, an additional attribute will be added.
4715 
4716  // The index within each element at which its attributes are found, where
4717  // the index is measured in REALs.
4718  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
4719  // The index within each element at which the maximum volume bound is
4720  // found, where the index is measured in REALs.
4722  // If element attributes or an constraint are needed, increase the number
4723  // of bytes occupied by an element.
4724  if (b->varvolume) {
4725  elesize = (volumeboundindex + 1) * sizeof(REAL);
4726  } else if (numelemattrib > 0) {
4727  elesize = volumeboundindex * sizeof(REAL);
4728  }
4729 
4730 
4731  // Having determined the memory size of an element, initialize the pool.
4732  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
4733  16);
4734 
4735  if (b->verbose) {
4736  printf(" Size of a tetrahedron: %d (%d) bytes.\n", elesize,
4738  }
4739 
4740  if (b->plc || b->refine) { // if (b->useshelles) {
4741  // The number of bytes occupied by a subface. The list of pointers
4742  // stored in a subface are: three to other subfaces, three to corners,
4743  // three to subsegments, two to tetrahedra.
4744  shsize = 11 * sizeof(shellface);
4745  // The index within each subface at which the maximum area bound is
4746  // found, where the index is measured in REALs.
4747  areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
4748  // If -q switch is in use, increase the number of bytes occupied by
4749  // a subface for saving maximum area bound.
4750  if (checkconstraints) {
4751  shsize = (areaboundindex + 1) * sizeof(REAL);
4752  } else {
4753  shsize = areaboundindex * sizeof(REAL);
4754  }
4755  // The index within subface at which the facet marker is found. Ensure
4756  // the marker is aligned to a sizeof(int)-byte address.
4757  shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
4758  // Increase the number of bytes by two or three integers, one for facet
4759  // marker, one for shellface type, and optionally one for pbc group.
4760  shsize = (shmarkindex + 2) * sizeof(shellface);
4761  if (useinsertradius) {
4762  // Increase the number of byte by one integer for storing facet index.
4763  // set/read by setfacetindex() and getfacetindex.
4764  shsize = (shmarkindex + 3) * sizeof(shellface);
4765  }
4766 
4767  // Initialize the pool of subfaces. Each subface record is eight-byte
4768  // aligned so it has room to store an edge version (from 0 to 5) in
4769  // the least three bits.
4770  subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4771 
4772  if (b->verbose) {
4773  printf(" Size of a shellface: %d (%d) bytes.\n", shsize,
4774  subfaces->itembytes);
4775  }
4776 
4777  // Initialize the pool of subsegments. The subsegment's record is same
4778  // with subface.
4779  subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4780 
4781  // Initialize the pool for tet-subseg connections.
4782  tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
4783  sizeof(void *), 0);
4784  // Initialize the pool for tet-subface connections.
4785  tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
4786  sizeof(void *), 0);
4787 
4788  // Initialize arraypools for segment & facet recovery.
4789  subsegstack = new arraypool(sizeof(face), 10);
4790  subfacstack = new arraypool(sizeof(face), 10);
4791  subvertstack = new arraypool(sizeof(point), 8);
4792 
4793  // Initialize arraypools for surface point insertion/deletion.
4794  caveshlist = new arraypool(sizeof(face), 8);
4795  caveshbdlist = new arraypool(sizeof(face), 8);
4796  cavesegshlist = new arraypool(sizeof(face), 4);
4797 
4798  cavetetshlist = new arraypool(sizeof(face), 8);
4799  cavetetseglist = new arraypool(sizeof(face), 8);
4800  caveencshlist = new arraypool(sizeof(face), 8);
4801  caveencseglist = new arraypool(sizeof(face), 8);
4802  }
4803 
4804  // Initialize the pools for flips.
4805  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
4806  unflipqueue = new arraypool(sizeof(badface), 10);
4807 
4808  // Initialize the arraypools for point insertion.
4809  cavetetlist = new arraypool(sizeof(triface), 10);
4810  cavebdrylist = new arraypool(sizeof(triface), 10);
4811  caveoldtetlist = new arraypool(sizeof(triface), 10);
4812  cavetetvertlist = new arraypool(sizeof(point), 10);
4813 }
4814 
4818 
4822 
4823 // PI is the ratio of a circle's circumference to its diameter.
4824 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
4825 
4827 // //
4828 // insphere_s() Insphere test with symbolic perturbation. //
4829 // //
4830 // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
4831 // outside the circumscribed sphere of the four points. //
4832 // //
4833 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4834 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4835 // points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4836 // //
4837 // Return a positive value (> 0) if pe lies inside, a negative value (< 0) //
4838 // if pe lies outside the sphere, the returned value will not be zero. //
4839 // //
4841 
4843 {
4844  REAL sign;
4845 
4846  sign = insphere(pa, pb, pc, pd, pe);
4847  if (sign != 0.0) {
4848  return sign;
4849  }
4850 
4851  // Symbolic perturbation.
4852  point pt[5], swappt;
4853  REAL oriA, oriB;
4854  int swaps, count;
4855  int n, i;
4856 
4857  pt[0] = pa;
4858  pt[1] = pb;
4859  pt[2] = pc;
4860  pt[3] = pd;
4861  pt[4] = pe;
4862 
4863  // Sort the five points such that their indices are in the increasing
4864  // order. An optimized bubble sort algorithm is used, i.e., it has
4865  // the worst case O(n^2) runtime, but it is usually much faster.
4866  swaps = 0; // Record the total number of swaps.
4867  n = 5;
4868  do {
4869  count = 0;
4870  n = n - 1;
4871  for (i = 0; i < n; i++) {
4872  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4873  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4874  count++;
4875  }
4876  }
4877  swaps += count;
4878  } while (count > 0); // Continue if some points are swapped.
4879 
4880  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4881  if (oriA != 0.0) {
4882  // Flip the sign if there are odd number of swaps.
4883  if ((swaps % 2) != 0) oriA = -oriA;
4884  return oriA;
4885  }
4886 
4887  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4888  assert(oriB != 0.0); // SELF_CHECK
4889  // Flip the sign if there are odd number of swaps.
4890  if ((swaps % 2) != 0) oriB = -oriB;
4891  return oriB;
4892 }
4893 
4895 // //
4896 // orient4d_s() 4d orientation test with symbolic perturbation. //
4897 // //
4898 // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
4899 // point pe' in R^4 lies below or above the hyperplane passing through the //
4900 // four points pa', pb', pc', and pd'. //
4901 // //
4902 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4903 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4904 // the points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4905 // //
4906 // Return a positive value (> 0) if pe' lies below, a negative value (< 0) //
4907 // if pe' lies above the hyperplane, the returned value should not be zero. //
4908 // //
4910 
4912  REAL aheight, REAL bheight, REAL cheight,
4913  REAL dheight, REAL eheight)
4914 {
4915  REAL sign;
4916 
4917  sign = orient4d(pa, pb, pc, pd, pe,
4918  aheight, bheight, cheight, dheight, eheight);
4919  if (sign != 0.0) {
4920  return sign;
4921  }
4922 
4923  // Symbolic perturbation.
4924  point pt[5], swappt;
4925  REAL oriA, oriB;
4926  int swaps, count;
4927  int n, i;
4928 
4929  pt[0] = pa;
4930  pt[1] = pb;
4931  pt[2] = pc;
4932  pt[3] = pd;
4933  pt[4] = pe;
4934 
4935  // Sort the five points such that their indices are in the increasing
4936  // order. An optimized bubble sort algorithm is used, i.e., it has
4937  // the worst case O(n^2) runtime, but it is usually much faster.
4938  swaps = 0; // Record the total number of swaps.
4939  n = 5;
4940  do {
4941  count = 0;
4942  n = n - 1;
4943  for (i = 0; i < n; i++) {
4944  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4945  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4946  count++;
4947  }
4948  }
4949  swaps += count;
4950  } while (count > 0); // Continue if some points are swapped.
4951 
4952  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4953  if (oriA != 0.0) {
4954  // Flip the sign if there are odd number of swaps.
4955  if ((swaps % 2) != 0) oriA = -oriA;
4956  return oriA;
4957  }
4958 
4959  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4960  assert(oriB != 0.0); // SELF_CHECK
4961  // Flip the sign if there are odd number of swaps.
4962  if ((swaps % 2) != 0) oriB = -oriB;
4963  return oriB;
4964 }
4965 
4967 // //
4968 // tri_edge_test() Triangle-edge intersection test. //
4969 // //
4970 // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
4971 // Q) in 3D, and tests if they intersect each other. //
4972 // //
4973 // If the point 'R' is not NULL, it lies strictly above the plane defined by //
4974 // A, B, C. It is used in test when T and E are coplanar. //
4975 // //
4976 // If T and E intersect each other, they may intersect in different ways. If //
4977 // 'level' > 0, their intersection type will be reported 'types' and 'pos'. //
4978 // //
4979 // The return value indicates one of the following cases: //
4980 // - 0, T and E are disjoint. //
4981 // - 1, T and E intersect each other. //
4982 // - 2, T and E are not coplanar. They intersect at a single point. //
4983 // - 4, T and E are coplanar. They intersect at a single point or a line //
4984 // segment (if types[1] != DISJOINT). //
4985 // //
4987 
4988 #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
4989 
4990 #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
4991 
4993  point R, int level, int *types, int *pos)
4994 {
4995  point U[3], V[3]; // The permuted vectors of points.
4996  int pu[3], pv[3]; // The original positions of points.
4997  REAL abovept[3];
4998  REAL sA, sB, sC;
4999  REAL s1, s2, s3, s4;
5000  int z1;
5001 
5002  if (R == NULL) {
5003  // Calculate a lift point.
5004  if (1) {
5005  REAL n[3], len;
5006  // Calculate a lift point, saved in dummypoint.
5007  facenormal(A, B, C, n, 1, NULL);
5008  len = sqrt(dot(n, n));
5009  if (len != 0) {
5010  n[0] /= len;
5011  n[1] /= len;
5012  n[2] /= len;
5013  len = distance(A, B);
5014  len += distance(B, C);
5015  len += distance(C, A);
5016  len /= 3.0;
5017  R = abovept; //dummypoint;
5018  R[0] = A[0] + len * n[0];
5019  R[1] = A[1] + len * n[1];
5020  R[2] = A[2] + len * n[2];
5021  } else {
5022  // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
5023  // to a line. We need a line-line intersection test.
5024  //assert(0);
5025  // !!! A non-save return value.!!!
5026  return 0; // DISJOINT
5027  }
5028  }
5029  }
5030 
5031  // Test A's, B's, and C's orientations wrt plane PQR.
5032  sA = orient3d(P, Q, R, A);
5033  sB = orient3d(P, Q, R, B);
5034  sC = orient3d(P, Q, R, C);
5035 
5036 
5037  if (sA < 0) {
5038  if (sB < 0) {
5039  if (sC < 0) { // (---).
5040  return 0;
5041  } else {
5042  if (sC > 0) { // (--+).
5043  // All points are in the right positions.
5044  SETVECTOR3(U, A, B, C); // I3
5045  SETVECTOR3(V, P, Q, R); // I2
5046  SETVECTOR3(pu, 0, 1, 2);
5047  SETVECTOR3(pv, 0, 1, 2);
5048  z1 = 0;
5049  } else { // (--0).
5050  SETVECTOR3(U, A, B, C); // I3
5051  SETVECTOR3(V, P, Q, R); // I2
5052  SETVECTOR3(pu, 0, 1, 2);
5053  SETVECTOR3(pv, 0, 1, 2);
5054  z1 = 1;
5055  }
5056  }
5057  } else {
5058  if (sB > 0) {
5059  if (sC < 0) { // (-+-).
5060  SETVECTOR3(U, C, A, B); // PT = ST
5061  SETVECTOR3(V, P, Q, R); // I2
5062  SETVECTOR3(pu, 2, 0, 1);
5063  SETVECTOR3(pv, 0, 1, 2);
5064  z1 = 0;
5065  } else {
5066  if (sC > 0) { // (-++).
5067  SETVECTOR3(U, B, C, A); // PT = ST x ST
5068  SETVECTOR3(V, Q, P, R); // PL = SL
5069  SETVECTOR3(pu, 1, 2, 0);
5070  SETVECTOR3(pv, 1, 0, 2);
5071  z1 = 0;
5072  } else { // (-+0).
5073  SETVECTOR3(U, C, A, B); // PT = ST
5074  SETVECTOR3(V, P, Q, R); // I2
5075  SETVECTOR3(pu, 2, 0, 1);
5076  SETVECTOR3(pv, 0, 1, 2);
5077  z1 = 2;
5078  }
5079  }
5080  } else {
5081  if (sC < 0) { // (-0-).
5082  SETVECTOR3(U, C, A, B); // PT = ST
5083  SETVECTOR3(V, P, Q, R); // I2
5084  SETVECTOR3(pu, 2, 0, 1);
5085  SETVECTOR3(pv, 0, 1, 2);
5086  z1 = 1;
5087  } else {
5088  if (sC > 0) { // (-0+).
5089  SETVECTOR3(U, B, C, A); // PT = ST x ST
5090  SETVECTOR3(V, Q, P, R); // PL = SL
5091  SETVECTOR3(pu, 1, 2, 0);
5092  SETVECTOR3(pv, 1, 0, 2);
5093  z1 = 2;
5094  } else { // (-00).
5095  SETVECTOR3(U, B, C, A); // PT = ST x ST
5096  SETVECTOR3(V, Q, P, R); // PL = SL
5097  SETVECTOR3(pu, 1, 2, 0);
5098  SETVECTOR3(pv, 1, 0, 2);
5099  z1 = 3;
5100  }
5101  }
5102  }
5103  }
5104  } else {
5105  if (sA > 0) {
5106  if (sB < 0) {
5107  if (sC < 0) { // (+--).
5108  SETVECTOR3(U, B, C, A); // PT = ST x ST
5109  SETVECTOR3(V, P, Q, R); // I2
5110  SETVECTOR3(pu, 1, 2, 0);
5111  SETVECTOR3(pv, 0, 1, 2);
5112  z1 = 0;
5113  } else {
5114  if (sC > 0) { // (+-+).
5115  SETVECTOR3(U, C, A, B); // PT = ST
5116  SETVECTOR3(V, Q, P, R); // PL = SL
5117  SETVECTOR3(pu, 2, 0, 1);
5118  SETVECTOR3(pv, 1, 0, 2);
5119  z1 = 0;
5120  } else { // (+-0).
5121  SETVECTOR3(U, C, A, B); // PT = ST
5122  SETVECTOR3(V, Q, P, R); // PL = SL
5123  SETVECTOR3(pu, 2, 0, 1);
5124  SETVECTOR3(pv, 1, 0, 2);
5125  z1 = 2;
5126  }
5127  }
5128  } else {
5129  if (sB > 0) {
5130  if (sC < 0) { // (++-).
5131  SETVECTOR3(U, A, B, C); // I3
5132  SETVECTOR3(V, Q, P, R); // PL = SL
5133  SETVECTOR3(pu, 0, 1, 2);
5134  SETVECTOR3(pv, 1, 0, 2);
5135  z1 = 0;
5136  } else {
5137  if (sC > 0) { // (+++).
5138  return 0;
5139  } else { // (++0).
5140  SETVECTOR3(U, A, B, C); // I3
5141  SETVECTOR3(V, Q, P, R); // PL = SL
5142  SETVECTOR3(pu, 0, 1, 2);
5143  SETVECTOR3(pv, 1, 0, 2);
5144  z1 = 1;
5145  }
5146  }
5147  } else { // (+0#)
5148  if (sC < 0) { // (+0-).
5149  SETVECTOR3(U, B, C, A); // PT = ST x ST
5150  SETVECTOR3(V, P, Q, R); // I2
5151  SETVECTOR3(pu, 1, 2, 0);
5152  SETVECTOR3(pv, 0, 1, 2);
5153  z1 = 2;
5154  } else {
5155  if (sC > 0) { // (+0+).
5156  SETVECTOR3(U, C, A, B); // PT = ST
5157  SETVECTOR3(V, Q, P, R); // PL = SL
5158  SETVECTOR3(pu, 2, 0, 1);
5159  SETVECTOR3(pv, 1, 0, 2);
5160  z1 = 1;
5161  } else { // (+00).
5162  SETVECTOR3(U, B, C, A); // PT = ST x ST
5163  SETVECTOR3(V, P, Q, R); // I2
5164  SETVECTOR3(pu, 1, 2, 0);
5165  SETVECTOR3(pv, 0, 1, 2);
5166  z1 = 3;
5167  }
5168  }
5169  }
5170  }
5171  } else {
5172  if (sB < 0) {
5173  if (sC < 0) { // (0--).
5174  SETVECTOR3(U, B, C, A); // PT = ST x ST
5175  SETVECTOR3(V, P, Q, R); // I2
5176  SETVECTOR3(pu, 1, 2, 0);
5177  SETVECTOR3(pv, 0, 1, 2);
5178  z1 = 1;
5179  } else {
5180  if (sC > 0) { // (0-+).
5181  SETVECTOR3(U, A, B, C); // I3
5182  SETVECTOR3(V, P, Q, R); // I2
5183  SETVECTOR3(pu, 0, 1, 2);
5184  SETVECTOR3(pv, 0, 1, 2);
5185  z1 = 2;
5186  } else { // (0-0).
5187  SETVECTOR3(U, C, A, B); // PT = ST
5188  SETVECTOR3(V, Q, P, R); // PL = SL
5189  SETVECTOR3(pu, 2, 0, 1);
5190  SETVECTOR3(pv, 1, 0, 2);
5191  z1 = 3;
5192  }
5193  }
5194  } else {
5195  if (sB > 0) {
5196  if (sC < 0) { // (0+-).
5197  SETVECTOR3(U, A, B, C); // I3
5198  SETVECTOR3(V, Q, P, R); // PL = SL
5199  SETVECTOR3(pu, 0, 1, 2);
5200  SETVECTOR3(pv, 1, 0, 2);
5201  z1 = 2;
5202  } else {
5203  if (sC > 0) { // (0++).
5204  SETVECTOR3(U, B, C, A); // PT = ST x ST
5205  SETVECTOR3(V, Q, P, R); // PL = SL
5206  SETVECTOR3(pu, 1, 2, 0);
5207  SETVECTOR3(pv, 1, 0, 2);
5208  z1 = 1;
5209  } else { // (0+0).
5210  SETVECTOR3(U, C, A, B); // PT = ST
5211  SETVECTOR3(V, P, Q, R); // I2
5212  SETVECTOR3(pu, 2, 0, 1);
5213  SETVECTOR3(pv, 0, 1, 2);
5214  z1 = 3;
5215  }
5216  }
5217  } else { // (00#)
5218  if (sC < 0) { // (00-).
5219  SETVECTOR3(U, A, B, C); // I3
5220  SETVECTOR3(V, Q, P, R); // PL = SL
5221  SETVECTOR3(pu, 0, 1, 2);
5222  SETVECTOR3(pv, 1, 0, 2);
5223  z1 = 3;
5224  } else {
5225  if (sC > 0) { // (00+).
5226  SETVECTOR3(U, A, B, C); // I3
5227  SETVECTOR3(V, P, Q, R); // I2
5228  SETVECTOR3(pu, 0, 1, 2);
5229  SETVECTOR3(pv, 0, 1, 2);
5230  z1 = 3;
5231  } else { // (000)
5232  // Not possible unless ABC is degenerate.
5233  // Avoiding compiler warnings.
5234  SETVECTOR3(U, A, B, C); // I3
5235  SETVECTOR3(V, P, Q, R); // I2
5236  SETVECTOR3(pu, 0, 1, 2);
5237  SETVECTOR3(pv, 0, 1, 2);
5238  z1 = 4;
5239  }
5240  }
5241  }
5242  }
5243  }
5244  }
5245 
5246  s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q
5247  s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P
5248 
5249  if (s1 > 0) {
5250  return 0;
5251  }
5252  if (s2 < 0) {
5253  return 0;
5254  }
5255 
5256  if (level == 0) {
5257  return 1; // They are intersected.
5258  }
5259 
5260  assert(z1 != 4); // SELF_CHECK
5261 
5262  if (z1 == 1) {
5263  if (s1 == 0) { // (0###)
5264  // C = Q.
5265  types[0] = (int) SHAREVERT;
5266  pos[0] = pu[2]; // C
5267  pos[1] = pv[1]; // Q
5268  types[1] = (int) DISJOINT;
5269  } else {
5270  if (s2 == 0) { // (#0##)
5271  // C = P.
5272  types[0] = (int) SHAREVERT;
5273  pos[0] = pu[2]; // C
5274  pos[1] = pv[0]; // P
5275  types[1] = (int) DISJOINT;
5276  } else { // (-+##)
5277  // C in [P, Q].
5278  types[0] = (int) ACROSSVERT;
5279  pos[0] = pu[2]; // C
5280  pos[1] = pv[0]; // [P, Q]
5281  types[1] = (int) DISJOINT;
5282  }
5283  }
5284  return 4;
5285  }
5286 
5287  s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P
5288  s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q
5289 
5290  if (z1 == 0) { // (tritri-03)
5291  if (s1 < 0) {
5292  if (s3 > 0) {
5293  assert(s2 > 0); // SELF_CHECK
5294  if (s4 > 0) {
5295  // [P, Q] overlaps [k, l] (-+++).
5296  types[0] = (int) ACROSSEDGE;
5297  pos[0] = pu[2]; // [C, A]
5298  pos[1] = pv[0]; // [P, Q]
5299  types[1] = (int) TOUCHFACE;
5300  pos[2] = 3; // [A, B, C]
5301  pos[3] = pv[1]; // Q
5302  } else {
5303  if (s4 == 0) {
5304  // Q = l, [P, Q] contains [k, l] (-++0).
5305  types[0] = (int) ACROSSEDGE;
5306  pos[0] = pu[2]; // [C, A]
5307  pos[1] = pv[0]; // [P, Q]
5308  types[1] = (int) TOUCHEDGE;
5309  pos[2] = pu[1]; // [B, C]
5310  pos[3] = pv[1]; // Q
5311  } else { // s4 < 0
5312  // [P, Q] contains [k, l] (-++-).
5313  types[0] = (int) ACROSSEDGE;
5314  pos[0] = pu[2]; // [C, A]
5315  pos[1] = pv[0]; // [P, Q]
5316  types[1] = (int) ACROSSEDGE;
5317  pos[2] = pu[1]; // [B, C]
5318  pos[3] = pv[0]; // [P, Q]
5319  }
5320  }
5321  } else {
5322  if (s3 == 0) {
5323  assert(s2 > 0); // SELF_CHECK
5324  if (s4 > 0) {
5325  // P = k, [P, Q] in [k, l] (-+0+).
5326  types[0] = (int) TOUCHEDGE;
5327  pos[0] = pu[2]; // [C, A]
5328  pos[1] = pv[0]; // P
5329  types[1] = (int) TOUCHFACE;
5330  pos[2] = 3; // [A, B, C]
5331  pos[3] = pv[1]; // Q
5332  } else {
5333  if (s4 == 0) {
5334  // [P, Q] = [k, l] (-+00).
5335  types[0] = (int) TOUCHEDGE;
5336  pos[0] = pu[2]; // [C, A]
5337  pos[1] = pv[0]; // P
5338  types[1] = (int) TOUCHEDGE;
5339  pos[2] = pu[1]; // [B, C]
5340  pos[3] = pv[1]; // Q
5341  } else {
5342  // P = k, [P, Q] contains [k, l] (-+0-).
5343  types[0] = (int) TOUCHEDGE;
5344  pos[0] = pu[2]; // [C, A]
5345  pos[1] = pv[0]; // P
5346  types[1] = (int) ACROSSEDGE;
5347  pos[2] = pu[1]; // [B, C]
5348  pos[3] = pv[0]; // [P, Q]
5349  }
5350  }
5351  } else { // s3 < 0
5352  if (s2 > 0) {
5353  if (s4 > 0) {
5354  // [P, Q] in [k, l] (-+-+).
5355  types[0] = (int) TOUCHFACE;
5356  pos[0] = 3; // [A, B, C]
5357  pos[1] = pv[0]; // P
5358  types[1] = (int) TOUCHFACE;
5359  pos[2] = 3; // [A, B, C]
5360  pos[3] = pv[1]; // Q
5361  } else {
5362  if (s4 == 0) {
5363  // Q = l, [P, Q] in [k, l] (-+-0).
5364  types[0] = (int) TOUCHFACE;
5365  pos[0] = 3; // [A, B, C]
5366  pos[1] = pv[0]; // P
5367  types[1] = (int) TOUCHEDGE;
5368  pos[2] = pu[1]; // [B, C]
5369  pos[3] = pv[1]; // Q
5370  } else { // s4 < 0
5371  // [P, Q] overlaps [k, l] (-+--).
5372  types[0] = (int) TOUCHFACE;
5373  pos[0] = 3; // [A, B, C]
5374  pos[1] = pv[0]; // P
5375  types[1] = (int) ACROSSEDGE;
5376  pos[2] = pu[1]; // [B, C]
5377  pos[3] = pv[0]; // [P, Q]
5378  }
5379  }
5380  } else { // s2 == 0
5381  // P = l (#0##).
5382  types[0] = (int) TOUCHEDGE;
5383  pos[0] = pu[1]; // [B, C]
5384  pos[1] = pv[0]; // P
5385  types[1] = (int) DISJOINT;
5386  }
5387  }
5388  }
5389  } else { // s1 == 0
5390  // Q = k (0####)
5391  types[0] = (int) TOUCHEDGE;
5392  pos[0] = pu[2]; // [C, A]
5393  pos[1] = pv[1]; // Q
5394  types[1] = (int) DISJOINT;
5395  }
5396  } else if (z1 == 2) { // (tritri-23)
5397  if (s1 < 0) {
5398  if (s3 > 0) {
5399  assert(s2 > 0); // SELF_CHECK
5400  if (s4 > 0) {
5401  // [P, Q] overlaps [A, l] (-+++).
5402  types[0] = (int) ACROSSVERT;
5403  pos[0] = pu[0]; // A
5404  pos[1] = pv[0]; // [P, Q]
5405  types[1] = (int) TOUCHFACE;
5406  pos[2] = 3; // [A, B, C]
5407  pos[3] = pv[1]; // Q
5408  } else {
5409  if (s4 == 0) {
5410  // Q = l, [P, Q] contains [A, l] (-++0).
5411  types[0] = (int) ACROSSVERT;
5412  pos[0] = pu[0]; // A
5413  pos[1] = pv[0]; // [P, Q]
5414  types[1] = (int) TOUCHEDGE;
5415  pos[2] = pu[1]; // [B, C]
5416  pos[3] = pv[1]; // Q
5417  } else { // s4 < 0
5418  // [P, Q] contains [A, l] (-++-).
5419  types[0] = (int) ACROSSVERT;
5420  pos[0] = pu[0]; // A
5421  pos[1] = pv[0]; // [P, Q]
5422  types[1] = (int) ACROSSEDGE;
5423  pos[2] = pu[1]; // [B, C]
5424  pos[3] = pv[0]; // [P, Q]
5425  }
5426  }
5427  } else {
5428  if (s3 == 0) {
5429  assert(s2 > 0); // SELF_CHECK
5430  if (s4 > 0) {
5431  // P = A, [P, Q] in [A, l] (-+0+).
5432  types[0] = (int) SHAREVERT;
5433  pos[0] = pu[0]; // A
5434  pos[1] = pv[0]; // P
5435  types[1] = (int) TOUCHFACE;
5436  pos[2] = 3; // [A, B, C]
5437  pos[3] = pv[1]; // Q
5438  } else {
5439  if (s4 == 0) {
5440  // [P, Q] = [A, l] (-+00).
5441  types[0] = (int) SHAREVERT;
5442  pos[0] = pu[0]; // A
5443  pos[1] = pv[0]; // P
5444  types[1] = (int) TOUCHEDGE;
5445  pos[2] = pu[1]; // [B, C]
5446  pos[3] = pv[1]; // Q
5447  } else { // s4 < 0
5448  // Q = l, [P, Q] in [A, l] (-+0-).
5449  types[0] = (int) SHAREVERT;
5450  pos[0] = pu[0]; // A
5451  pos[1] = pv[0]; // P
5452  types[1] = (int) ACROSSEDGE;
5453  pos[2] = pu[1]; // [B, C]
5454  pos[3] = pv[0]; // [P, Q]
5455  }
5456  }
5457  } else { // s3 < 0
5458  if (s2 > 0) {
5459  if (s4 > 0) {
5460  // [P, Q] in [A, l] (-+-+).
5461  types[0] = (int) TOUCHFACE;
5462  pos[0] = 3; // [A, B, C]
5463  pos[1] = pv[0]; // P
5464  types[0] = (int) TOUCHFACE;
5465  pos[0] = 3; // [A, B, C]
5466  pos[1] = pv[1]; // Q
5467  } else {
5468  if (s4 == 0) {
5469  // Q = l, [P, Q] in [A, l] (-+-0).
5470  types[0] = (int) TOUCHFACE;
5471  pos[0] = 3; // [A, B, C]
5472  pos[1] = pv[0]; // P
5473  types[0] = (int) TOUCHEDGE;
5474  pos[0] = pu[1]; // [B, C]
5475  pos[1] = pv[1]; // Q
5476  } else { // s4 < 0
5477  // [P, Q] overlaps [A, l] (-+--).
5478  types[0] = (int) TOUCHFACE;
5479  pos[0] = 3; // [A, B, C]
5480  pos[1] = pv[0]; // P
5481  types[0] = (int) ACROSSEDGE;
5482  pos[0] = pu[1]; // [B, C]
5483  pos[1] = pv[0]; // [P, Q]
5484  }
5485  }
5486  } else { // s2 == 0
5487  // P = l (#0##).
5488  types[0] = (int) TOUCHEDGE;
5489  pos[0] = pu[1]; // [B, C]
5490  pos[1] = pv[0]; // P
5491  types[1] = (int) DISJOINT;
5492  }
5493  }
5494  }
5495  } else { // s1 == 0
5496  // Q = A (0###).
5497  types[0] = (int) SHAREVERT;
5498  pos[0] = pu[0]; // A
5499  pos[1] = pv[1]; // Q
5500  types[1] = (int) DISJOINT;
5501  }
5502  } else if (z1 == 3) { // (tritri-33)
5503  if (s1 < 0) {
5504  if (s3 > 0) {
5505  assert(s2 > 0); // SELF_CHECK
5506  if (s4 > 0) {
5507  // [P, Q] overlaps [A, B] (-+++).
5508  types[0] = (int) ACROSSVERT;
5509  pos[0] = pu[0]; // A
5510  pos[1] = pv[0]; // [P, Q]
5511  types[1] = (int) TOUCHEDGE;
5512  pos[2] = pu[0]; // [A, B]
5513  pos[3] = pv[1]; // Q
5514  } else {
5515  if (s4 == 0) {
5516  // Q = B, [P, Q] contains [A, B] (-++0).
5517  types[0] = (int) ACROSSVERT;
5518  pos[0] = pu[0]; // A
5519  pos[1] = pv[0]; // [P, Q]
5520  types[1] = (int) SHAREVERT;
5521  pos[2] = pu[1]; // B
5522  pos[3] = pv[1]; // Q
5523  } else { // s4 < 0
5524  // [P, Q] contains [A, B] (-++-).
5525  types[0] = (int) ACROSSVERT;
5526  pos[0] = pu[0]; // A
5527  pos[1] = pv[0]; // [P, Q]
5528  types[1] = (int) ACROSSVERT;
5529  pos[2] = pu[1]; // B
5530  pos[3] = pv[0]; // [P, Q]
5531  }
5532  }
5533  } else {
5534  if (s3 == 0) {
5535  assert(s2 > 0); // SELF_CHECK
5536  if (s4 > 0) {
5537  // P = A, [P, Q] in [A, B] (-+0+).
5538  types[0] = (int) SHAREVERT;
5539  pos[0] = pu[0]; // A
5540  pos[1] = pv[0]; // P
5541  types[1] = (int) TOUCHEDGE;
5542  pos[2] = pu[0]; // [A, B]
5543  pos[3] = pv[1]; // Q
5544  } else {
5545  if (s4 == 0) {
5546  // [P, Q] = [A, B] (-+00).
5547  types[0] = (int) SHAREEDGE;
5548  pos[0] = pu[0]; // [A, B]
5549  pos[1] = pv[0]; // [P, Q]
5550  types[1] = (int) DISJOINT;
5551  } else { // s4 < 0
5552  // P= A, [P, Q] in [A, B] (-+0-).
5553  types[0] = (int) SHAREVERT;
5554  pos[0] = pu[0]; // A
5555  pos[1] = pv[0]; // P
5556  types[1] = (int) ACROSSVERT;
5557  pos[2] = pu[1]; // B
5558  pos[3] = pv[0]; // [P, Q]
5559  }
5560  }
5561  } else { // s3 < 0
5562  if (s2 > 0) {
5563  if (s4 > 0) {
5564  // [P, Q] in [A, B] (-+-+).
5565  types[0] = (int) TOUCHEDGE;
5566  pos[0] = pu[0]; // [A, B]
5567  pos[1] = pv[0]; // P
5568  types[1] = (int) TOUCHEDGE;
5569  pos[2] = pu[0]; // [A, B]
5570  pos[3] = pv[1]; // Q
5571  } else {
5572  if (s4 == 0) {
5573  // Q = B, [P, Q] in [A, B] (-+-0).
5574  types[0] = (int) TOUCHEDGE;
5575  pos[0] = pu[0]; // [A, B]
5576  pos[1] = pv[0]; // P
5577  types[1] = (int) SHAREVERT;
5578  pos[2] = pu[1]; // B
5579  pos[3] = pv[1]; // Q
5580  } else { // s4 < 0
5581  // [P, Q] overlaps [A, B] (-+--).
5582  types[0] = (int) TOUCHEDGE;
5583  pos[0] = pu[0]; // [A, B]
5584  pos[1] = pv[0]; // P
5585  types[1] = (int) ACROSSVERT;
5586  pos[2] = pu[1]; // B
5587  pos[3] = pv[0]; // [P, Q]
5588  }
5589  }
5590  } else { // s2 == 0
5591  // P = B (#0##).
5592  types[0] = (int) SHAREVERT;
5593  pos[0] = pu[1]; // B
5594  pos[1] = pv[0]; // P
5595  types[1] = (int) DISJOINT;
5596  }
5597  }
5598  }
5599  } else { // s1 == 0
5600  // Q = A (0###).
5601  types[0] = (int) SHAREVERT;
5602  pos[0] = pu[0]; // A
5603  pos[1] = pv[1]; // Q
5604  types[1] = (int) DISJOINT;
5605  }
5606  }
5607 
5608  return 4;
5609 }
5610 
5612  REAL sP,REAL sQ,int level,int *types,int *pos)
5613 {
5614  point U[3], V[3]; //, Ptmp;
5615  int pu[3], pv[3]; //, itmp;
5616  REAL s1, s2, s3;
5617  int z1;
5618 
5619 
5620  if (sP < 0) {
5621  if (sQ < 0) { // (--) disjoint
5622  return 0;
5623  } else {
5624  if (sQ > 0) { // (-+)
5625  SETVECTOR3(U, A, B, C);
5626  SETVECTOR3(V, P, Q, R);
5627  SETVECTOR3(pu, 0, 1, 2);
5628  SETVECTOR3(pv, 0, 1, 2);
5629  z1 = 0;
5630  } else { // (-0)
5631  SETVECTOR3(U, A, B, C);
5632  SETVECTOR3(V, P, Q, R);
5633  SETVECTOR3(pu, 0, 1, 2);
5634  SETVECTOR3(pv, 0, 1, 2);
5635  z1 = 1;
5636  }
5637  }
5638  } else {
5639  if (sP > 0) { // (+-)
5640  if (sQ < 0) {
5641  SETVECTOR3(U, A, B, C);
5642  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5643  SETVECTOR3(pu, 0, 1, 2);
5644  SETVECTOR3(pv, 1, 0, 2);
5645  z1 = 0;
5646  } else {
5647  if (sQ > 0) { // (++) disjoint
5648  return 0;
5649  } else { // (+0)
5650  SETVECTOR3(U, B, A, C); // A and B are flipped.
5651  SETVECTOR3(V, P, Q, R);
5652  SETVECTOR3(pu, 1, 0, 2);
5653  SETVECTOR3(pv, 0, 1, 2);
5654  z1 = 1;
5655  }
5656  }
5657  } else { // sP == 0
5658  if (sQ < 0) { // (0-)
5659  SETVECTOR3(U, A, B, C);
5660  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5661  SETVECTOR3(pu, 0, 1, 2);
5662  SETVECTOR3(pv, 1, 0, 2);
5663  z1 = 1;
5664  } else {
5665  if (sQ > 0) { // (0+)
5666  SETVECTOR3(U, B, A, C); // A and B are flipped.
5667  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5668  SETVECTOR3(pu, 1, 0, 2);
5669  SETVECTOR3(pv, 1, 0, 2);
5670  z1 = 1;
5671  } else { // (00)
5672  // A, B, C, P, and Q are coplanar.
5673  z1 = 2;
5674  }
5675  }
5676  }
5677  }
5678 
5679  if (z1 == 2) {
5680  // The triangle and the edge are coplanar.
5681  return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
5682  }
5683 
5684  s1 = orient3d(U[0], U[1], V[0], V[1]);
5685  if (s1 < 0) {
5686  return 0;
5687  }
5688 
5689  s2 = orient3d(U[1], U[2], V[0], V[1]);
5690  if (s2 < 0) {
5691  return 0;
5692  }
5693 
5694  s3 = orient3d(U[2], U[0], V[0], V[1]);
5695  if (s3 < 0) {
5696  return 0;
5697  }
5698 
5699  if (level == 0) {
5700  return 1; // The are intersected.
5701  }
5702 
5703  types[1] = (int) DISJOINT; // No second intersection point.
5704 
5705  if (z1 == 0) {
5706  if (s1 > 0) {
5707  if (s2 > 0) {
5708  if (s3 > 0) { // (+++)
5709  // [P, Q] passes interior of [A, B, C].
5710  types[0] = (int) ACROSSFACE;
5711  pos[0] = 3; // interior of [A, B, C]
5712  pos[1] = 0; // [P, Q]
5713  } else { // s3 == 0 (++0)
5714  // [P, Q] intersects [C, A].
5715  types[0] = (int) ACROSSEDGE;
5716  pos[0] = pu[2]; // [C, A]
5717  pos[1] = 0; // [P, Q]
5718  }
5719  } else { // s2 == 0
5720  if (s3 > 0) { // (+0+)
5721  // [P, Q] intersects [B, C].
5722  types[0] = (int) ACROSSEDGE;
5723  pos[0] = pu[1]; // [B, C]
5724  pos[1] = 0; // [P, Q]
5725  } else { // s3 == 0 (+00)
5726  // [P, Q] passes C.
5727  types[0] = (int) ACROSSVERT;
5728  pos[0] = pu[2]; // C
5729  pos[1] = 0; // [P, Q]
5730  }
5731  }
5732  } else { // s1 == 0
5733  if (s2 > 0) {
5734  if (s3 > 0) { // (0++)
5735  // [P, Q] intersects [A, B].
5736  types[0] = (int) ACROSSEDGE;
5737  pos[0] = pu[0]; // [A, B]
5738  pos[1] = 0; // [P, Q]
5739  } else { // s3 == 0 (0+0)
5740  // [P, Q] passes A.
5741  types[0] = (int) ACROSSVERT;
5742  pos[0] = pu[0]; // A
5743  pos[1] = 0; // [P, Q]
5744  }
5745  } else { // s2 == 0
5746  if (s3 > 0) { // (00+)
5747  // [P, Q] passes B.
5748  types[0] = (int) ACROSSVERT;
5749  pos[0] = pu[1]; // B
5750  pos[1] = 0; // [P, Q]
5751  } else { // s3 == 0 (000)
5752  // Impossible.
5753  assert(0);
5754  }
5755  }
5756  }
5757  } else { // z1 == 1
5758  if (s1 > 0) {
5759  if (s2 > 0) {
5760  if (s3 > 0) { // (+++)
5761  // Q lies in [A, B, C].
5762  types[0] = (int) TOUCHFACE;
5763  pos[0] = 0; // [A, B, C]
5764  pos[1] = pv[1]; // Q
5765  } else { // s3 == 0 (++0)
5766  // Q lies on [C, A].
5767  types[0] = (int) TOUCHEDGE;
5768  pos[0] = pu[2]; // [C, A]
5769  pos[1] = pv[1]; // Q
5770  }
5771  } else { // s2 == 0
5772  if (s3 > 0) { // (+0+)
5773  // Q lies on [B, C].
5774  types[0] = (int) TOUCHEDGE;
5775  pos[0] = pu[1]; // [B, C]
5776  pos[1] = pv[1]; // Q
5777  } else { // s3 == 0 (+00)
5778  // Q = C.
5779  types[0] = (int) SHAREVERT;
5780  pos[0] = pu[2]; // C
5781  pos[1] = pv[1]; // Q
5782  }
5783  }
5784  } else { // s1 == 0
5785  if (s2 > 0) {
5786  if (s3 > 0) { // (0++)
5787  // Q lies on [A, B].
5788  types[0] = (int) TOUCHEDGE;
5789  pos[0] = pu[0]; // [A, B]
5790  pos[1] = pv[1]; // Q
5791  } else { // s3 == 0 (0+0)
5792  // Q = A.
5793  types[0] = (int) SHAREVERT;
5794  pos[0] = pu[0]; // A
5795  pos[1] = pv[1]; // Q
5796  }
5797  } else { // s2 == 0
5798  if (s3 > 0) { // (00+)
5799  // Q = B.
5800  types[0] = (int) SHAREVERT;
5801  pos[0] = pu[1]; // B
5802  pos[1] = pv[1]; // Q
5803  } else { // s3 == 0 (000)
5804  // Impossible.
5805  assert(0);
5806  }
5807  }
5808  }
5809  }
5810 
5811  // T and E intersect in a single point.
5812  return 2;
5813 }
5814 
5816  point R, int level, int *types, int *pos)
5817 {
5818  REAL sP, sQ;
5819 
5820  // Test the locations of P and Q with respect to ABC.
5821  sP = orient3d(A, B, C, P);
5822  sQ = orient3d(A, B, C, Q);
5823 
5824  return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
5825 }
5826 
5828 // //
5829 // tri_tri_inter() Test whether two triangle (abc) and (opq) are //
5830 // intersecting or not. //
5831 // //
5832 // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
5833 // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT. //
5834 // //
5836 
5838  REAL* Q, REAL s_p, REAL s_q)
5839 {
5840  int types[2], pos[4];
5841  int ni; // =0, 2, 4
5842 
5843  ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
5844 
5845  if (ni > 0) {
5846  if (ni == 2) {
5847  // Get the intersection type.
5848  if (types[0] == (int) SHAREVERT) {
5849  return (int) SHAREVERT;
5850  } else {
5851  return (int) INTERSECT;
5852  }
5853  } else if (ni == 4) {
5854  // There may be two intersections.
5855  if (types[0] == (int) SHAREVERT) {
5856  if (types[1] == (int) DISJOINT) {
5857  return (int) SHAREVERT;
5858  } else {
5859  assert(types[1] != (int) SHAREVERT);
5860  return (int) INTERSECT;
5861  }
5862  } else {
5863  if (types[0] == (int) SHAREEDGE) {
5864  return (int) SHAREEDGE;
5865  } else {
5866  return (int) INTERSECT;
5867  }
5868  }
5869  } else {
5870  assert(0);
5871  }
5872  }
5873 
5874  return (int) DISJOINT;
5875 }
5876 
5878 {
5879  REAL s_o, s_p, s_q;
5880  REAL s_a, s_b, s_c;
5881 
5882  s_o = orient3d(A, B, C, O);
5883  s_p = orient3d(A, B, C, P);
5884  s_q = orient3d(A, B, C, Q);
5885  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
5886  // o, p, q are all in the same halfspace of ABC.
5887  return 0; // DISJOINT;
5888  }
5889 
5890  s_a = orient3d(O, P, Q, A);
5891  s_b = orient3d(O, P, Q, B);
5892  s_c = orient3d(O, P, Q, C);
5893  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
5894  // a, b, c are all in the same halfspace of OPQ.
5895  return 0; // DISJOINT;
5896  }
5897 
5898  int abcop, abcpq, abcqo;
5899  int shareedge = 0;
5900 
5901  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
5902  if (abcop == (int) INTERSECT) {
5903  return (int) INTERSECT;
5904  } else if (abcop == (int) SHAREEDGE) {
5905  shareedge++;
5906  }
5907  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
5908  if (abcpq == (int) INTERSECT) {
5909  return (int) INTERSECT;
5910  } else if (abcpq == (int) SHAREEDGE) {
5911  shareedge++;
5912  }
5913  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
5914  if (abcqo == (int) INTERSECT) {
5915  return (int) INTERSECT;
5916  } else if (abcqo == (int) SHAREEDGE) {
5917  shareedge++;
5918  }
5919  if (shareedge == 3) {
5920  // opq are coincident with abc.
5921  return (int) SHAREFACE;
5922  }
5923 
5924  // It is only possible either no share edge or one.
5925  assert(shareedge == 0 || shareedge == 1);
5926 
5927  // Continue to detect whether opq and abc are intersecting or not.
5928  int opqab, opqbc, opqca;
5929 
5930  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
5931  if (opqab == (int) INTERSECT) {
5932  return (int) INTERSECT;
5933  }
5934  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
5935  if (opqbc == (int) INTERSECT) {
5936  return (int) INTERSECT;
5937  }
5938  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
5939  if (opqca == (int) INTERSECT) {
5940  return (int) INTERSECT;
5941  }
5942 
5943  // At this point, two triangles are not intersecting and not coincident.
5944  // They may be share an edge, or share a vertex, or disjoint.
5945  if (abcop == (int) SHAREEDGE) {
5946  assert((abcpq == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
5947  // op is coincident with an edge of abc.
5948  return (int) SHAREEDGE;
5949  }
5950  if (abcpq == (int) SHAREEDGE) {
5951  assert((abcop == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
5952  // pq is coincident with an edge of abc.
5953  return (int) SHAREEDGE;
5954  }
5955  if (abcqo == (int) SHAREEDGE) {
5956  assert((abcop == (int) SHAREVERT) && (abcpq == (int) SHAREVERT));
5957  // qo is coincident with an edge of abc.
5958  return (int) SHAREEDGE;
5959  }
5960 
5961  // They may share a vertex or disjoint.
5962  if (abcop == (int) SHAREVERT) {
5963  // o or p is coincident with a vertex of abc.
5964  if (abcpq == (int) SHAREVERT) {
5965  // p is the coincident vertex.
5966  assert(abcqo != (int) SHAREVERT);
5967  } else {
5968  // o is the coincident vertex.
5969  assert(abcqo == (int) SHAREVERT);
5970  }
5971  return (int) SHAREVERT;
5972  }
5973  if (abcpq == (int) SHAREVERT) {
5974  // q is the coincident vertex.
5975  assert(abcqo == (int) SHAREVERT);
5976  return (int) SHAREVERT;
5977  }
5978 
5979  // They are disjoint.
5980  return (int) DISJOINT;
5981 }
5982 
5984 // //
5985 // lu_decmp() Compute the LU decomposition of a matrix. //
5986 // //
5987 // Compute the LU decomposition of a (non-singular) square matrix A using //
5988 // partial pivoting and implicit row exchanges. The result is: //
5989 // A = P * L * U, //
5990 // where P is a permutation matrix, L is unit lower triangular, and U is //
5991 // upper triangular. The factored form of A is used in combination with //
5992 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
5993 // //
5994 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
5995 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
5996 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
5997 // permutation effected by the partial pivoting, effectively, 'ps' array //
5998 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
5999 // depending on whether the number of row interchanges was even or odd, //
6000 // respectively. //
6001 // //
6002 // Return true if the LU decomposition is successfully computed, otherwise, //
6003 // return false in case that A is a singular matrix. //
6004 // //
6006 
6007 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6008 {
6009  REAL scales[4];
6010  REAL pivot, biggest, mult, tempf;
6011  int pivotindex = 0;
6012  int i, j, k;
6013 
6014  *d = 1.0; // No row interchanges yet.
6015 
6016  for (i = N; i < n + N; i++) { // For each row.
6017  // Find the largest element in each row for row equilibration
6018  biggest = 0.0;
6019  for (j = N; j < n + N; j++)
6020  if (biggest < (tempf = fabs(lu[i][j])))
6021  biggest = tempf;
6022  if (biggest != 0.0)
6023  scales[i] = 1.0 / biggest;
6024  else {
6025  scales[i] = 0.0;
6026  return false; // Zero row: singular matrix.
6027  }
6028  ps[i] = i; // Initialize pivot sequence.
6029  }
6030 
6031  for (k = N; k < n + N - 1; k++) { // For each column.
6032  // Find the largest element in each column to pivot around.
6033  biggest = 0.0;
6034  for (i = k; i < n + N; i++) {
6035  if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6036  biggest = tempf;
6037  pivotindex = i;
6038  }
6039  }
6040  if (biggest == 0.0) {
6041  return false; // Zero column: singular matrix.
6042  }
6043  if (pivotindex != k) { // Update pivot sequence.
6044  j = ps[k];
6045  ps[k] = ps[pivotindex];
6046  ps[pivotindex] = j;
6047  *d = -(*d); // ...and change the parity of d.
6048  }
6049 
6050  // Pivot, eliminating an extra variable each time
6051  pivot = lu[ps[k]][k];
6052  for (i = k + 1; i < n + N; i++) {
6053  lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6054  if (mult != 0.0) {
6055  for (j = k + 1; j < n + N; j++)
6056  lu[ps[i]][j] -= mult * lu[ps[k]][j];
6057  }
6058  }
6059  }
6060 
6061  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6062  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6063 }
6064 
6066 // //
6067 // lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6068 // has been decomposed into the lower and upper triangular //
6069 // matrices L and U, where A = LU. //
6070 // //
6071 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6072 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6073 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6074 // is input as the right-hand side vector, and returns with the solution //
6075 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6076 // left in place for successive calls with different right-hand sides 'b'. //
6077 // //
6079 
6080 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6081 {
6082  int i, j;
6083  REAL X[4], dot;
6084 
6085  for (i = N; i < n + N; i++) X[i] = 0.0;
6086 
6087  // Vector reduction using U triangular matrix.
6088  for (i = N; i < n + N; i++) {
6089  dot = 0.0;
6090  for (j = N; j < i + N; j++)
6091  dot += lu[ps[i]][j] * X[j];
6092  X[i] = b[ps[i]] - dot;
6093  }
6094 
6095  // Back substitution, in L triangular matrix.
6096  for (i = n + N - 1; i >= N; i--) {
6097  dot = 0.0;
6098  for (j = i + 1; j < n + N; j++)
6099  dot += lu[ps[i]][j] * X[j];
6100  X[i] = (X[i] - dot) / lu[ps[i]][i];
6101  }
6102 
6103  for (i = N; i < n + N; i++) b[i] = X[i];
6104 }
6105 
6107 // //
6108 // incircle3d() 3D in-circle test. //
6109 // //
6110 // Return a negative value if pd is inside the circumcircle of the triangle //
6111 // pa, pb, and pc. //
6112 // //
6113 // IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input //
6114 // triangles are [a,b,c] and [b,a,d]. //
6115 // //
6117 
6119 {
6120  REAL area2[2], n1[3], n2[3], c[3];
6121  REAL sign, r, d;
6122 
6123  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
6124  facenormal(pa, pb, pc, n1, 1, NULL);
6125  area2[0] = dot(n1, n1);
6126  facenormal(pb, pa, pd, n2, 1, NULL);
6127  area2[1] = dot(n2, n2);
6128 
6129  if (area2[0] > area2[1]) {
6130  // Choose [a, b, c] as the base triangle.
6131  circumsphere(pa, pb, pc, NULL, c, &r);
6132  d = distance(c, pd);
6133  } else {
6134  // Choose [b, a, d] as the base triangle.
6135  if (area2[1] > 0) {
6136  circumsphere(pb, pa, pd, NULL, c, &r);
6137  d = distance(c, pc);
6138  } else {
6139  // The four points are collinear. This case only happens on the boundary.
6140  return 0; // Return "not inside".
6141  }
6142  }
6143 
6144  sign = d - r;
6145  if (fabs(sign) / r < b->epsilon) {
6146  sign = 0;
6147  }
6148 
6149  return sign;
6150 }
6151 
6153 // //
6154 // facenormal() Calculate the normal of the face. //
6155 // //
6156 // The normal of the face abc can be calculated by the cross product of 2 of //
6157 // its 3 edge vectors. A better choice of two edge vectors will reduce the //
6158 // numerical error during the calculation. Burdakov proved that the optimal //
6159 // basis problem is equivalent to the minimum spanning tree problem with the //
6160 // edge length be the functional, see Burdakov, "A greedy algorithm for the //
6161 // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
6162 // short edges in abc are chosen for the calculation. //
6163 // //
6164 // If 'lav' is not NULL and if 'pivot' is set, the average edge length of //
6165 // the edges of the face [a,b,c] is returned. //
6166 // //
6168 
6169 void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
6170  REAL* lav)
6171 {
6172  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
6173  REAL L1, L2, L3;
6174 
6175  v1[0] = pb[0] - pa[0]; // edge vector v1: a->b
6176  v1[1] = pb[1] - pa[1];
6177  v1[2] = pb[2] - pa[2];
6178  v2[0] = pa[0] - pc[0]; // edge vector v2: c->a
6179  v2[1] = pa[1] - pc[1];
6180  v2[2] = pa[2] - pc[2];
6181 
6182  // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
6183  if (pivot > 0) {
6184  // Choose edge vectors by Burdakov's algorithm.
6185  v3[0] = pc[0] - pb[0]; // edge vector v3: b->c
6186  v3[1] = pc[1] - pb[1];
6187  v3[2] = pc[2] - pb[2];
6188  L1 = dot(v1, v1);
6189  L2 = dot(v2, v2);
6190  L3 = dot(v3, v3);
6191  // Sort the three edge lengths.
6192  if (L1 < L2) {
6193  if (L2 < L3) {
6194  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6195  } else {
6196  pv1 = v3; pv2 = v1; // n = v3 x (-v1).
6197  }
6198  } else {
6199  if (L1 < L3) {
6200  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6201  } else {
6202  pv1 = v2; pv2 = v3; // n = v2 x (-v3).
6203  }
6204  }
6205  if (lav) {
6206  // return the average edge length.
6207  *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
6208  }
6209  } else {
6210  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6211  }
6212 
6213  // Calculate the face normal.
6214  cross(pv1, pv2, n);
6215  // Inverse the direction;
6216  n[0] = -n[0];
6217  n[1] = -n[1];
6218  n[2] = -n[2];
6219 }
6220 
6222 // //
6223 // shortdistance() Returns the shortest distance from point p to a line //
6224 // defined by two points e1 and e2. //
6225 // //
6226 // First compute the projection length l_p of the vector v1 = p - e1 along //
6227 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
6228 // shortest distance. //
6229 // //
6230 // This routine allows that p is collinear with the line. In this case, the //
6231 // return value is zero. The two points e1 and e2 should not be identical. //
6232 // //
6234 
6236 {
6237  REAL v1[3], v2[3];
6238  REAL len, l_p;
6239 
6240  v1[0] = e2[0] - e1[0];
6241  v1[1] = e2[1] - e1[1];
6242  v1[2] = e2[2] - e1[2];
6243  v2[0] = p[0] - e1[0];
6244  v2[1] = p[1] - e1[1];
6245  v2[2] = p[2] - e1[2];
6246 
6247  len = sqrt(dot(v1, v1));
6248  assert(len != 0.0);
6249 
6250  v1[0] /= len;
6251  v1[1] /= len;
6252  v1[2] /= len;
6253  l_p = dot(v1, v2);
6254 
6255  return sqrt(dot(v2, v2) - l_p * l_p);
6256 }
6257 
6259 // //
6260 // triarea() Return the area of a triangle. //
6261 // //
6263 
6265 {
6266  REAL A[4][4];
6267 
6268  // Compute the coefficient matrix A (3x3).
6269  A[0][0] = pb[0] - pa[0];
6270  A[0][1] = pb[1] - pa[1];
6271  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
6272  A[1][0] = pc[0] - pa[0];
6273  A[1][1] = pc[1] - pa[1];
6274  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
6275 
6276  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
6277 
6278  return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
6279 }
6280 
6282 {
6283  REAL adx, bdx, cdx;
6284  REAL ady, bdy, cdy;
6285  REAL adz, bdz, cdz;
6286 
6287  adx = pa[0] - pd[0];
6288  bdx = pb[0] - pd[0];
6289  cdx = pc[0] - pd[0];
6290  ady = pa[1] - pd[1];
6291  bdy = pb[1] - pd[1];
6292  cdy = pc[1] - pd[1];
6293  adz = pa[2] - pd[2];
6294  bdz = pb[2] - pd[2];
6295  cdz = pc[2] - pd[2];
6296 
6297  return adx * (bdy * cdz - bdz * cdy)
6298  + bdx * (cdy * adz - cdz * ady)
6299  + cdx * (ady * bdz - adz * bdy);
6300 }
6301 
6303 // //
6304 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
6305 // o->p1 and o->p2. //
6306 // //
6307 // 'n' is the normal of the plane containing face (o, p1, p2). The interior //
6308 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
6309 // the position of p1 and p2 will get the complement angle of the other one. //
6310 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
6311 // 'n' be NULL if you only want the interior angle between 0 - PI. //
6312 // //
6314 
6316 {
6317  REAL v1[3], v2[3], np[3];
6318  REAL theta, costheta, lenlen;
6319  REAL ori, len1, len2;
6320 
6321  // Get the interior angle (0 - PI) between o->p1, and o->p2.
6322  v1[0] = p1[0] - o[0];
6323  v1[1] = p1[1] - o[1];
6324  v1[2] = p1[2] - o[2];
6325  v2[0] = p2[0] - o[0];
6326  v2[1] = p2[1] - o[1];
6327  v2[2] = p2[2] - o[2];
6328  len1 = sqrt(dot(v1, v1));
6329  len2 = sqrt(dot(v2, v2));
6330  lenlen = len1 * len2;
6331  assert(lenlen != 0.0);
6332 
6333  costheta = dot(v1, v2) / lenlen;
6334  if (costheta > 1.0) {
6335  costheta = 1.0; // Roundoff.
6336  } else if (costheta < -1.0) {
6337  costheta = -1.0; // Roundoff.
6338  }
6339  theta = acos(costheta);
6340  if (n != NULL) {
6341  // Get a point above the face (o, p1, p2);
6342  np[0] = o[0] + n[0];
6343  np[1] = o[1] + n[1];
6344  np[2] = o[2] + n[2];
6345  // Adjust theta (0 - 2 * PI).
6346  ori = orient3d(p1, o, np, p2);
6347  if (ori > 0.0) {
6348  theta = 2 * PI - theta;
6349  }
6350  }
6351 
6352  return theta;
6353 }
6354 
6356 // //
6357 // projpt2edge() Return the projection point from a point to an edge. //
6358 // //
6360 
6361 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
6362 {
6363  REAL v1[3], v2[3];
6364  REAL len, l_p;
6365 
6366  v1[0] = e2[0] - e1[0];
6367  v1[1] = e2[1] - e1[1];
6368  v1[2] = e2[2] - e1[2];
6369  v2[0] = p[0] - e1[0];
6370  v2[1] = p[1] - e1[1];
6371  v2[2] = p[2] - e1[2];
6372 
6373  len = sqrt(dot(v1, v1));
6374  assert(len != 0.0);
6375  v1[0] /= len;
6376  v1[1] /= len;
6377  v1[2] /= len;
6378  l_p = dot(v1, v2);
6379 
6380  prj[0] = e1[0] + l_p * v1[0];
6381  prj[1] = e1[1] + l_p * v1[1];
6382  prj[2] = e1[2] + l_p * v1[2];
6383 }
6384 
6386 // //
6387 // projpt2face() Return the projection point from a point to a face. //
6388 // //
6390 
6391 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
6392 {
6393  REAL fnormal[3], v1[3];
6394  REAL len, dist;
6395 
6396  // Get the unit face normal.
6397  facenormal(f1, f2, f3, fnormal, 1, NULL);
6398  len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
6399  fnormal[2]*fnormal[2]);
6400  fnormal[0] /= len;
6401  fnormal[1] /= len;
6402  fnormal[2] /= len;
6403  // Get the vector v1 = |p - f1|.
6404  v1[0] = p[0] - f1[0];
6405  v1[1] = p[1] - f1[1];
6406  v1[2] = p[2] - f1[2];
6407  // Get the project distance.
6408  dist = dot(fnormal, v1);
6409 
6410  // Get the project point.
6411  prj[0] = p[0] - dist * fnormal[0];
6412  prj[1] = p[1] - dist * fnormal[1];
6413  prj[2] = p[2] - dist * fnormal[2];
6414 }
6415 
6417 // //
6418 // facedihedral() Return the dihedral angle (in radian) between two //
6419 // adjoining faces. //
6420 // //
6421 // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are //
6422 // apexes of these two faces. Return the angle (between 0 to 2*pi) between //
6423 // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). //
6424 // //
6426 
6428 {
6429  REAL n1[3], n2[3];
6430  REAL n1len, n2len;
6431  REAL costheta, ori;
6432  REAL theta;
6433 
6434  facenormal(pa, pb, pc1, n1, 1, NULL);
6435  facenormal(pa, pb, pc2, n2, 1, NULL);
6436  n1len = sqrt(dot(n1, n1));
6437  n2len = sqrt(dot(n2, n2));
6438  costheta = dot(n1, n2) / (n1len * n2len);
6439  // Be careful rounding error!
6440  if (costheta > 1.0) {
6441  costheta = 1.0;
6442  } else if (costheta < -1.0) {
6443  costheta = -1.0;
6444  }
6445  theta = acos(costheta);
6446  ori = orient3d(pa, pb, pc1, pc2);
6447  if (ori > 0.0) {
6448  theta = 2 * PI - theta;
6449  }
6450 
6451  return theta;
6452 }
6453 
6455 // //
6456 // tetalldihedral() Get all (six) dihedral angles of a tet. //
6457 // //
6458 // If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles, //
6459 // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd' //
6460 // (or 'cosmind') is not NULL, it returns the cosine of the maximal (or //
6461 // minimal) dihedral angle. //
6462 // //
6464 
6466  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
6467 {
6468  REAL N[4][3], vol, cosd, len;
6469  int f1 = 0, f2 = 0, i, j;
6470 
6471  vol = 0; // Check if the tet is valid or not.
6472 
6473  // Get four normals of faces of the tet.
6474  tetallnormal(pa, pb, pc, pd, N, &vol);
6475 
6476  if (vol > 0) {
6477  // Normalize the normals.
6478  for (i = 0; i < 4; i++) {
6479  len = sqrt(dot(N[i], N[i]));
6480  if (len != 0.0) {
6481  for (j = 0; j < 3; j++) N[i][j] /= len;
6482  } else {
6483  // There are degeneracies, such as duplicated vertices.
6484  vol = 0; //assert(0);
6485  }
6486  }
6487  }
6488 
6489  if (vol <= 0) { // if (vol == 0.0) {
6490  // A degenerated tet or an inverted tet.
6491  facenormal(pc, pb, pd, N[0], 1, NULL);
6492  facenormal(pa, pc, pd, N[1], 1, NULL);
6493  facenormal(pb, pa, pd, N[2], 1, NULL);
6494  facenormal(pa, pb, pc, N[3], 1, NULL);
6495  // Normalize the normals.
6496  for (i = 0; i < 4; i++) {
6497  len = sqrt(dot(N[i], N[i]));
6498  if (len != 0.0) {
6499  for (j = 0; j < 3; j++) N[i][j] /= len;
6500  } else {
6501  // There are degeneracies, such as duplicated vertices.
6502  break; // Not a valid normal.
6503  }
6504  }
6505  if (i < 4) {
6506  // Do not calculate dihedral angles.
6507  // Set all angles be 0 degree. There will be no quality optimization for
6508  // this tet! Use volume optimization to correct it.
6509  if (cosdd != NULL) {
6510  for (i = 0; i < 6; i++) {
6511  cosdd[i] = -1.0; // 180 degree.
6512  }
6513  }
6514  // This tet has zero volume.
6515  if (cosmaxd != NULL) {
6516  *cosmaxd = -1.0; // 180 degree.
6517  }
6518  if (cosmind != NULL) {
6519  *cosmind = -1.0; // 180 degree.
6520  }
6521  return false;
6522  }
6523  }
6524 
6525  // Calculate the cosine of the dihedral angles of the edges.
6526  for (i = 0; i < 6; i++) {
6527  switch (i) {
6528  case 0: f1 = 0; f2 = 1; break; // [c,d].
6529  case 1: f1 = 1; f2 = 2; break; // [a,d].
6530  case 2: f1 = 2; f2 = 3; break; // [a,b].
6531  case 3: f1 = 0; f2 = 3; break; // [b,c].
6532  case 4: f1 = 2; f2 = 0; break; // [b,d].
6533  case 5: f1 = 1; f2 = 3; break; // [a,c].
6534  }
6535  cosd = -dot(N[f1], N[f2]);
6536  if (cosd < -1.0) cosd = -1.0; // Rounding.
6537  if (cosd > 1.0) cosd = 1.0; // Rounding.
6538  if (cosdd) cosdd[i] = cosd;
6539  if (cosmaxd || cosmind) {
6540  if (i == 0) {
6541  if (cosmaxd) *cosmaxd = cosd;
6542  if (cosmind) *cosmind = cosd;
6543  } else {
6544  if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
6545  if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
6546  }
6547  }
6548  }
6549 
6550  return true;
6551 }
6552 
6554 // //
6555 // tetallnormal() Get the in-normals of the four faces of a given tet. //
6556 // //
6557 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
6558 // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices //
6559 // of the mesh data structure). These normals are unnormalized. //
6560 // //
6562 
6564  REAL N[4][3], REAL* volume)
6565 {
6566  REAL A[4][4], rhs[4], D;
6567  int indx[4];
6568  int i, j;
6569 
6570  // get the entries of A[3][3].
6571  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
6572  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
6573  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
6574 
6575  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
6576  if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
6577  if (volume != NULL) {
6578  // Get the volume of the tet.
6579  *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
6580  }
6581  for (j = 0; j < 3; j++) {
6582  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6583  rhs[j] = 1.0; // Positive means the inside direction
6584  lu_solve(A, 3, indx, rhs, 0);
6585  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6586  }
6587  // Get the fourth normal by summing up the first three.
6588  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6589  } else {
6590  // The tet is degenerated.
6591  if (volume != NULL) {
6592  *volume = 0;
6593  }
6594  }
6595 }
6596 
6598 // //
6599 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
6600 // //
6601 // The aspect ratio of a tet is R/h, where R is the circumradius and h is //
6602 // the shortest height of the tet. //
6603 // //
6605 
6607 {
6608  REAL vda[3], vdb[3], vdc[3];
6609  REAL N[4][3], A[4][4], rhs[4], D;
6610  REAL H[4], volume, radius2, minheightinv;
6611  int indx[4];
6612  int i, j;
6613 
6614  // Set the matrix A = [vda, vdb, vdc]^T.
6615  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
6616  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
6617  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
6618  // Lu-decompose the matrix A.
6619  lu_decmp(A, 3, indx, &D, 0);
6620  // Get the volume of abcd.
6621  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
6622  // Check if it is zero.
6623  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
6624  // if (volume < 0.0) volume = -volume;
6625  // Check the radiu-edge ratio of the tet.
6626  rhs[0] = 0.5 * dot(vda, vda);
6627  rhs[1] = 0.5 * dot(vdb, vdb);
6628  rhs[2] = 0.5 * dot(vdc, vdc);
6629  lu_solve(A, 3, indx, rhs, 0);
6630  // Get the circumcenter.
6631  // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
6632  // Get the square of the circumradius.
6633  radius2 = dot(rhs, rhs);
6634 
6635  // Compute the 4 face normals (N[0], ..., N[3]).
6636  for (j = 0; j < 3; j++) {
6637  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6638  rhs[j] = 1.0; // Positive means the inside direction
6639  lu_solve(A, 3, indx, rhs, 0);
6640  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6641  }
6642  // Get the fourth normal by summing up the first three.
6643  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6644  // Normalized the normals.
6645  for (i = 0; i < 4; i++) {
6646  // H[i] is the inverse of the height of its corresponding face.
6647  H[i] = sqrt(dot(N[i], N[i]));
6648  // if (H[i] > 0.0) {
6649  // for (j = 0; j < 3; j++) N[i][j] /= H[i];
6650  // }
6651  }
6652  // Get the radius of the inscribed sphere.
6653  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
6654  // Get the biggest H[i] (corresponding to the smallest height).
6655  minheightinv = H[0];
6656  for (i = 1; i < 3; i++) {
6657  if (H[i] > minheightinv) minheightinv = H[i];
6658  }
6659 
6660  return sqrt(radius2) * minheightinv;
6661 }
6662 
6664 // //
6665 // circumsphere() Calculate the smallest circumsphere (center and radius) //
6666 // of the given three or four points. //
6667 // //
6668 // The circumsphere of four points (a tetrahedron) is unique if they are not //
6669 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
6670 // the diametral sphere of the triangle if they are not degenerate. //
6671 // //
6672 // Return TRUE if the input points are not degenerate and the circumcenter //
6673 // and circumradius are returned in 'cent' and 'radius' respectively if they //
6674 // are not NULLs. Otherwise, return FALSE, the four points are co-planar. //
6675 // //
6677 
6679  REAL* cent, REAL* radius)
6680 {
6681  REAL A[4][4], rhs[4], D;
6682  int indx[4];
6683 
6684  // Compute the coefficient matrix A (3x3).
6685  A[0][0] = pb[0] - pa[0];
6686  A[0][1] = pb[1] - pa[1];
6687  A[0][2] = pb[2] - pa[2];
6688  A[1][0] = pc[0] - pa[0];
6689  A[1][1] = pc[1] - pa[1];
6690  A[1][2] = pc[2] - pa[2];
6691  if (pd != NULL) {
6692  A[2][0] = pd[0] - pa[0];
6693  A[2][1] = pd[1] - pa[1];
6694  A[2][2] = pd[2] - pa[2];
6695  } else {
6696  cross(A[0], A[1], A[2]);
6697  }
6698 
6699  // Compute the right hand side vector b (3x1).
6700  rhs[0] = 0.5 * dot(A[0], A[0]);
6701  rhs[1] = 0.5 * dot(A[1], A[1]);
6702  if (pd != NULL) {
6703  rhs[2] = 0.5 * dot(A[2], A[2]);
6704  } else {
6705  rhs[2] = 0.0;
6706  }
6707 
6708  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
6709  // and backward and forward substitute..
6710  if (!lu_decmp(A, 3, indx, &D, 0)) {
6711  if (radius != (REAL *) NULL) *radius = 0.0;
6712  return false;
6713  }
6714  lu_solve(A, 3, indx, rhs, 0);
6715  if (cent != (REAL *) NULL) {
6716  cent[0] = pa[0] + rhs[0];
6717  cent[1] = pa[1] + rhs[1];
6718  cent[2] = pa[2] + rhs[2];
6719  }
6720  if (radius != (REAL *) NULL) {
6721  *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
6722  }
6723  return true;
6724 }
6725 
6727 // //
6728 // orthosphere() Calulcate the orthosphere of four weighted points. //
6729 // //
6730 // A weighted point (p, P^2) can be interpreted as a sphere centered at the //
6731 // point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + //
6732 // p[1]^2 + p[2]^2 - P^2. //
6733 // //
6735 
6737  REAL aheight, REAL bheight, REAL cheight,
6738  REAL dheight, REAL* orthocent, REAL* radius)
6739 {
6740  REAL A[4][4], rhs[4], D;
6741  int indx[4];
6742 
6743  // Set the coefficient matrix A (4 x 4).
6744  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
6745  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
6746  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
6747  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
6748 
6749  // Set the right hand side vector (4 x 1).
6750  rhs[0] = 0.5 * aheight;
6751  rhs[1] = 0.5 * bheight;
6752  rhs[2] = 0.5 * cheight;
6753  rhs[3] = 0.5 * dheight;
6754 
6755  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
6756  // and backward and forward substitute..
6757  if (!lu_decmp(A, 4, indx, &D, 0)) {
6758  if (radius != (REAL *) NULL) *radius = 0.0;
6759  return false;
6760  }
6761  lu_solve(A, 4, indx, rhs, 0);
6762 
6763  if (orthocent != (REAL *) NULL) {
6764  orthocent[0] = rhs[1];
6765  orthocent[1] = rhs[2];
6766  orthocent[2] = rhs[3];
6767  }
6768  if (radius != (REAL *) NULL) {
6769  // rhs[0] = - rheight / 2;
6770  // rheight = - 2 * rhs[0];
6771  // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2
6772  // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
6773  // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
6774  *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
6775  + 2.0 * rhs[0]);
6776  }
6777  return true;
6778 }
6779 
6781 // //
6782 // planelineint() Calculate the intersection of a line and a plane. //
6783 // //
6784 // The equation of a plane (points P are on the plane with normal N and P3 //
6785 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
6786 // line (points P on the line passing through P1 and P2) can be written as: //
6787 // P = P1 + u (P2 - P1). The intersection of these two occurs when: //
6788 // N dot (P1 + u (P2 - P1)) = N dot P3. //
6789 // Solving for u gives: //
6790 // N dot (P3 - P1) //
6791 // u = ------------------. //
6792 // N dot (P2 - P1) //
6793 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
6794 // to the line. Thus the line is either parallel to the plane and there are //
6795 // no solutions or the line is on the plane in which case there are an infi- //
6796 // nite number of solutions. //
6797 // //
6798 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
6799 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
6800 // //
6802 
6803 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
6804  REAL* ip, REAL* u)
6805 {
6806  REAL n[3], det, det1;
6807 
6808  // Calculate N.
6809  facenormal(pa, pb, pc, n, 1, NULL);
6810  // Calculate N dot (e2 - e1).
6811  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
6812  + n[2] * (e2[2] - e1[2]);
6813  if (det != 0.0) {
6814  // Calculate N dot (pa - e1)
6815  det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
6816  + n[2] * (pa[2] - e1[2]);
6817  *u = det1 / det;
6818  ip[0] = e1[0] + *u * (e2[0] - e1[0]);
6819  ip[1] = e1[1] + *u * (e2[1] - e1[1]);
6820  ip[2] = e1[2] + *u * (e2[2] - e1[2]);
6821  } else {
6822  *u = 0.0;
6823  }
6824 }
6825 
6827 // //
6828 // linelineint() Calculate the intersection(s) of two line segments. //
6829 // //
6830 // Calculate the line segment [P, Q] that is the shortest route between two //
6831 // lines from A to B and C to D. Calculate also the values of tp and tq //
6832 // where: P = A + tp (B - A), and Q = C + tq (D - C). //
6833 // //
6834 // Return 1 if the line segment exists. Otherwise, return 0. //
6835 // //
6837 
6839  REAL* Q, REAL* tp, REAL* tq)
6840 {
6841  REAL vab[3], vcd[3], vca[3];
6842  REAL vab_vab, vcd_vcd, vab_vcd;
6843  REAL vca_vab, vca_vcd;
6844  REAL det, eps;
6845  int i;
6846 
6847  for (i = 0; i < 3; i++) {
6848  vab[i] = B[i] - A[i];
6849  vcd[i] = D[i] - C[i];
6850  vca[i] = A[i] - C[i];
6851  }
6852 
6853  vab_vab = dot(vab, vab);
6854  vcd_vcd = dot(vcd, vcd);
6855  vab_vcd = dot(vab, vcd);
6856 
6857  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
6858  // Round the result.
6859  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
6860  if (eps < b->epsilon) {
6861  return 0;
6862  }
6863 
6864  vca_vab = dot(vca, vab);
6865  vca_vcd = dot(vca, vcd);
6866 
6867  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
6868  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
6869 
6870  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
6871  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
6872 
6873  return 1;
6874 }
6875 
6877 // //
6878 // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. //
6879 // //
6880 // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
6881 // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular //
6882 // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
6883 // vertices. (Wikipedia). //
6884 // //
6885 // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
6886 // the lower tetrahedral facet of the prism. The top tetrahedral facet is //
6887 // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by //
6888 // lifting each vertex of the lower facet into R^4 by a weight (height). A //
6889 // canonical choice of the weights is the square of Euclidean norm of of the //
6890 // points (vectors). //
6891 // //
6892 // //
6893 // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
6894 // //
6896 
6898 {
6899  REAL *p4, *p5, *p6, *p7;
6900  REAL w4, w5, w6, w7;
6901  REAL vol[4];
6902 
6903  p4 = p0;
6904  p5 = p1;
6905  p6 = p2;
6906  p7 = p3;
6907 
6908  // TO DO: these weights can be pre-calculated!
6909  w4 = dot(p0, p0);
6910  w5 = dot(p1, p1);
6911  w6 = dot(p2, p2);
6912  w7 = dot(p3, p3);
6913 
6914  // Calculate the volume of the tet-prism.
6915  vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
6916  vol[1] = orient4d(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0);
6917  vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0);
6918  vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0);
6919 
6920  return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
6921 }
6922 
6924 // //
6925 // calculateabovepoint() Calculate a point above a facet in 'dummypoint'. //
6926 // //
6928 
6930  point *ppb, point *ppc)
6931 {
6932  point *ppt, pa, pb, pc;
6933  REAL v1[3], v2[3], n[3];
6934  REAL lab, len, A, area;
6935  REAL x, y, z;
6936  int i;
6937 
6938  ppt = (point *) fastlookup(facpoints, 0);
6939  pa = *ppt; // a is the first point.
6940  pb = pc = NULL; // Avoid compiler warnings.
6941 
6942  // Get a point b s.t. the length of [a, b] is maximal.
6943  lab = 0;
6944  for (i = 1; i < facpoints->objects; i++) {
6945  ppt = (point *) fastlookup(facpoints, i);
6946  x = (*ppt)[0] - pa[0];
6947  y = (*ppt)[1] - pa[1];
6948  z = (*ppt)[2] - pa[2];
6949  len = x * x + y * y + z * z;
6950  if (len > lab) {
6951  lab = len;
6952  pb = *ppt;
6953  }
6954  }
6955  lab = sqrt(lab);
6956  if (lab == 0) {
6957  if (!b->quiet) {
6958  printf("Warning: All points of a facet are coincident with %d.\n",
6959  pointmark(pa));
6960  }
6961  return false;
6962  }
6963 
6964  // Get a point c s.t. the area of [a, b, c] is maximal.
6965  v1[0] = pb[0] - pa[0];
6966  v1[1] = pb[1] - pa[1];
6967  v1[2] = pb[2] - pa[2];
6968  A = 0;
6969  for (i = 1; i < facpoints->objects; i++) {
6970  ppt = (point *) fastlookup(facpoints, i);
6971  v2[0] = (*ppt)[0] - pa[0];
6972  v2[1] = (*ppt)[1] - pa[1];
6973  v2[2] = (*ppt)[2] - pa[2];
6974  cross(v1, v2, n);
6975  area = dot(n, n);
6976  if (area > A) {
6977  A = area;
6978  pc = *ppt;
6979  }
6980  }
6981  if (A == 0) {
6982  // All points are collinear. No above point.
6983  if (!b->quiet) {
6984  printf("Warning: All points of a facet are collinaer with [%d, %d].\n",
6985  pointmark(pa), pointmark(pb));
6986  }
6987  return false;
6988  }
6989 
6990  // Calculate an above point of this facet.
6991  facenormal(pa, pb, pc, n, 1, NULL);
6992  len = sqrt(dot(n, n));
6993  n[0] /= len;
6994  n[1] /= len;
6995  n[2] /= len;
6996  lab /= 2.0; // Half the maximal length.
6997  dummypoint[0] = pa[0] + lab * n[0];
6998  dummypoint[1] = pa[1] + lab * n[1];
6999  dummypoint[2] = pa[2] + lab * n[2];
7000 
7001  if (ppa != NULL) {
7002  // Return the three points.
7003  *ppa = pa;
7004  *ppb = pb;
7005  *ppc = pc;
7006  }
7007 
7008  return true;
7009 }
7010 
7012 // //
7013 // Calculate an above point. It lies above the plane containing the subface //
7014 // [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
7015 // is the normal of the plane. //
7016 // //
7018 
7020 {
7021  REAL n1[3], n2[3], *norm;
7022  REAL len, len1, len2;
7023 
7024  // Select a base.
7025  facenormal(pa, pb, pc, n1, 1, NULL);
7026  len1 = sqrt(dot(n1, n1));
7027  facenormal(pa, pb, pd, n2, 1, NULL);
7028  len2 = sqrt(dot(n2, n2));
7029  if (len1 > len2) {
7030  norm = n1;
7031  len = len1;
7032  } else {
7033  norm = n2;
7034  len = len2;
7035  }
7036  assert(len > 0);
7037  norm[0] /= len;
7038  norm[1] /= len;
7039  norm[2] /= len;
7040  len = distance(pa, pb);
7041  dummypoint[0] = pa[0] + len * norm[0];
7042  dummypoint[1] = pa[1] + len * norm[1];
7043  dummypoint[2] = pa[2] + len * norm[2];
7044 }
7045 
7049 
7053 
7055 // //
7056 // flip23() Perform a 2-to-3 flip (face-to-edge flip). //
7057 // //
7058 // 'fliptets' is an array of three tets (handles), where the [0] and [1] are //
7059 // [a,b,c,d] and [b,a,c,e]. The three new tets: [e,d,a,b], [e,d,b,c], and //
7060 // [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'. As a result, //
7061 // The face [a,b,c] is removed, and the edge [d,e] is created. //
7062 // //
7063 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7064 // the five vertices may be 'dummypoint'. There are two canonical cases: //
7065 // (1) d is 'dummypoint', then all three new tets are hull tets. If e is //
7066 // 'dummypoint', we reconfigure e to d, i.e., turn it up-side down. //
7067 // (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are //
7068 // hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
7069 // rotate the three input tets counterclockwisely (right-hand rule) //
7070 // until a or b is in c's position. //
7071 // //
7072 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7073 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7074 // after the insertion of a new point. It is assumed that 'd' is the new //
7075 // point. IN this case, only link faces of 'd' are queued. //
7076 // //
7078 
7079 void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
7080 {
7081  triface topcastets[3], botcastets[3];
7082  triface newface, casface;
7083  point pa, pb, pc, pd, pe;
7084  REAL attrib, volume;
7085  int dummyflag = 0; // range = {-1, 0, 1, 2}.
7086  int i;
7087 
7088  if (hullflag > 0) {
7089  // Check if e is dummypoint.
7090  if (oppo(fliptets[1]) == dummypoint) {
7091  // Swap the two old tets.
7092  newface = fliptets[0];
7093  fliptets[0] = fliptets[1];
7094  fliptets[1] = newface;
7095  dummyflag = -1; // d is dummypoint.
7096  } else {
7097  // Check if either a or b is dummypoint.
7098  if (org(fliptets[0]) == dummypoint) {
7099  dummyflag = 1; // a is dummypoint.
7100  enextself(fliptets[0]);
7101  eprevself(fliptets[1]);
7102  } else if (dest(fliptets[0]) == dummypoint) {
7103  dummyflag = 2; // b is dummypoint.
7104  eprevself(fliptets[0]);
7105  enextself(fliptets[1]);
7106  } else {
7107  dummyflag = 0; // either c or d may be dummypoint.
7108  }
7109  }
7110  }
7111 
7112  pa = org(fliptets[0]);
7113  pb = dest(fliptets[0]);
7114  pc = apex(fliptets[0]);
7115  pd = oppo(fliptets[0]);
7116  pe = oppo(fliptets[1]);
7117 
7118  flip23count++;
7119 
7120  // Get the outer boundary faces.
7121  for (i = 0; i < 3; i++) {
7122  fnext(fliptets[0], topcastets[i]);
7123  enextself(fliptets[0]);
7124  }
7125  for (i = 0; i < 3; i++) {
7126  fnext(fliptets[1], botcastets[i]);
7127  eprevself(fliptets[1]);
7128  }
7129 
7130  // Re-use fliptets[0] and fliptets[1].
7131  fliptets[0].ver = 11;
7132  fliptets[1].ver = 11;
7133  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7134  setelemmarker(fliptets[1].tet, 0);
7135  // NOTE: the element attributes and volume constraint remain unchanged.
7136  if (checksubsegflag) {
7137  // Dealloc the space to subsegments.
7138  if (fliptets[0].tet[8] != NULL) {
7139  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7140  fliptets[0].tet[8] = NULL;
7141  }
7142  if (fliptets[1].tet[8] != NULL) {
7143  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7144  fliptets[1].tet[8] = NULL;
7145  }
7146  }
7147  if (checksubfaceflag) {
7148  // Dealloc the space to subfaces.
7149  if (fliptets[0].tet[9] != NULL) {
7150  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7151  fliptets[0].tet[9] = NULL;
7152  }
7153  if (fliptets[1].tet[9] != NULL) {
7154  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7155  fliptets[1].tet[9] = NULL;
7156  }
7157  }
7158  // Create a new tet.
7159  maketetrahedron(&(fliptets[2]));
7160  // The new tet have the same attributes from the old tet.
7161  for (i = 0; i < numelemattrib; i++) {
7162  attrib = elemattribute(fliptets[0].tet, i);
7163  setelemattribute(fliptets[2].tet, i, attrib);
7164  }
7165  if (b->varvolume) {
7166  volume = volumebound(fliptets[0].tet);
7167  setvolumebound(fliptets[2].tet, volume);
7168  }
7169 
7170  if (hullflag > 0) {
7171  // Check if d is dummytet.
7172  if (pd != dummypoint) {
7173  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7174  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7175  // Check if c is dummypoint.
7176  if (pc != dummypoint) {
7177  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7178  } else {
7179  setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
7180  esymself(fliptets[2]); // [e,d,c,a] *
7181  }
7182  // The hullsize does not change.
7183  } else {
7184  // d is dummypoint.
7185  setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
7186  setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
7187  setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
7188  // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
7189  for (i = 0; i < 3; i++) {
7190  eprevesymself(fliptets[i]);
7191  enextself(fliptets[i]);
7192  }
7193  // We deleted one hull tet, and created three hull tets.
7194  hullsize += 2;
7195  }
7196  } else {
7197  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7198  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7199  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7200  }
7201 
7202  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7203  REAL volneg[2], volpos[3], vol_diff;
7204  if (pd != dummypoint) {
7205  if (pc != dummypoint) {
7206  volpos[0] = tetprismvol(pe, pd, pa, pb);
7207  volpos[1] = tetprismvol(pe, pd, pb, pc);
7208  volpos[2] = tetprismvol(pe, pd, pc, pa);
7209  volneg[0] = tetprismvol(pa, pb, pc, pd);
7210  volneg[1] = tetprismvol(pb, pa, pc, pe);
7211  } else { // pc == dummypoint
7212  volpos[0] = tetprismvol(pe, pd, pa, pb);
7213  volpos[1] = 0.;
7214  volpos[2] = 0.;
7215  volneg[0] = 0.;
7216  volneg[1] = 0.;
7217  }
7218  } else { // pd == dummypoint.
7219  volpos[0] = 0.;
7220  volpos[1] = 0.;
7221  volpos[2] = 0.;
7222  volneg[0] = 0.;
7223  volneg[1] = tetprismvol(pb, pa, pc, pe);
7224  }
7225  vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
7226  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7227  }
7228 
7229  // Bond three new tets together.
7230  for (i = 0; i < 3; i++) {
7231  esym(fliptets[i], newface);
7232  bond(newface, fliptets[(i + 1) % 3]);
7233  }
7234  // Bond to top outer boundary faces (at [a,b,c,d]).
7235  for (i = 0; i < 3; i++) {
7236  eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
7237  bond(newface, topcastets[i]);
7238  }
7239  // Bond bottom outer boundary faces (at [b,a,c,e]).
7240  for (i = 0; i < 3; i++) {
7241  edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
7242  bond(newface, botcastets[i]);
7243  }
7244 
7245  if (checksubsegflag) {
7246  // Bond subsegments if there are.
7247  // Each new tet has 5 edges to be checked (except the edge [e,d]).
7248  face checkseg;
7249  // The middle three: [a,b], [b,c], [c,a].
7250  for (i = 0; i < 3; i++) {
7251  if (issubseg(topcastets[i])) {
7252  tsspivot1(topcastets[i], checkseg);
7253  eorgoppo(fliptets[i], newface);
7254  tssbond1(newface, checkseg);
7255  sstbond1(checkseg, newface);
7256  if (fc->chkencflag & 1) {
7257  enqueuesubface(badsubsegs, &checkseg);
7258  }
7259  }
7260  }
7261  // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
7262  for (i = 0; i < 3; i++) {
7263  eprev(topcastets[i], casface);
7264  if (issubseg(casface)) {
7265  tsspivot1(casface, checkseg);
7266  enext(fliptets[i], newface);
7267  tssbond1(newface, checkseg);
7268  sstbond1(checkseg, newface);
7269  esym(fliptets[(i + 2) % 3], newface);
7270  eprevself(newface);
7271  tssbond1(newface, checkseg);
7272  sstbond1(checkseg, newface);
7273  if (fc->chkencflag & 1) {
7274  enqueuesubface(badsubsegs, &checkseg);
7275  }
7276  }
7277  }
7278  // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
7279  for (i = 0; i < 3; i++) {
7280  enext(botcastets[i], casface);
7281  if (issubseg(casface)) {
7282  tsspivot1(casface, checkseg);
7283  eprev(fliptets[i], newface);
7284  tssbond1(newface, checkseg);
7285  sstbond1(checkseg, newface);
7286  esym(fliptets[(i + 2) % 3], newface);
7287  enextself(newface);
7288  tssbond1(newface, checkseg);
7289  sstbond1(checkseg, newface);
7290  if (fc->chkencflag & 1) {
7291  enqueuesubface(badsubsegs, &checkseg);
7292  }
7293  }
7294  }
7295  } // if (checksubsegflag)
7296 
7297  if (checksubfaceflag) {
7298  // Bond 6 subfaces if there are.
7299  face checksh;
7300  for (i = 0; i < 3; i++) {
7301  if (issubface(topcastets[i])) {
7302  tspivot(topcastets[i], checksh);
7303  eorgoppo(fliptets[i], newface);
7304  sesymself(checksh);
7305  tsbond(newface, checksh);
7306  if (fc->chkencflag & 2) {
7307  enqueuesubface(badsubfacs, &checksh);
7308  }
7309  }
7310  }
7311  for (i = 0; i < 3; i++) {
7312  if (issubface(botcastets[i])) {
7313  tspivot(botcastets[i], checksh);
7314  edestoppo(fliptets[i], newface);
7315  sesymself(checksh);
7316  tsbond(newface, checksh);
7317  if (fc->chkencflag & 2) {
7318  enqueuesubface(badsubfacs, &checksh);
7319  }
7320  }
7321  }
7322  } // if (checksubfaceflag)
7323 
7324  if (fc->chkencflag & 4) {
7325  // Put three new tets into check list.
7326  for (i = 0; i < 3; i++) {
7327  enqueuetetrahedron(&(fliptets[i]));
7328  }
7329  }
7330 
7331  // Update the point-to-tet map.
7332  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7333  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7334  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
7335  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7336  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
7337 
7338  if (hullflag > 0) {
7339  if (dummyflag != 0) {
7340  // Restore the original position of the points (for flipnm()).
7341  if (dummyflag == -1) {
7342  // Reverse the edge.
7343  for (i = 0; i < 3; i++) {
7344  esymself(fliptets[i]);
7345  }
7346  // Swap the last two new tets.
7347  newface = fliptets[1];
7348  fliptets[1] = fliptets[2];
7349  fliptets[2] = newface;
7350  } else {
7351  // either a or b were swapped.
7352  if (dummyflag == 1) {
7353  // a is dummypoint.
7354  newface = fliptets[0];
7355  fliptets[0] = fliptets[2];
7356  fliptets[2] = fliptets[1];
7357  fliptets[1] = newface;
7358  } else { // dummyflag == 2
7359  // b is dummypoint.
7360  newface = fliptets[0];
7361  fliptets[0] = fliptets[1];
7362  fliptets[1] = fliptets[2];
7363  fliptets[2] = newface;
7364  }
7365  }
7366  }
7367  }
7368 
7369  if (fc->enqflag > 0) {
7370  // Queue faces which may be locally non-Delaunay.
7371  for (i = 0; i < 3; i++) {
7372  eprevesym(fliptets[i], newface);
7373  flippush(flipstack, &newface);
7374  }
7375  if (fc->enqflag > 1) {
7376  for (i = 0; i < 3; i++) {
7377  enextesym(fliptets[i], newface);
7378  flippush(flipstack, &newface);
7379  }
7380  }
7381  }
7382 
7383  recenttet = fliptets[0];
7384 }
7385 
7387 // //
7388 // flip32() Perform a 3-to-2 flip (edge-to-face flip). //
7389 // //
7390 // 'fliptets' is an array of three tets (handles), which are [e,d,a,b], //
7391 // [e,d,b,c], and [e,d,c,a]. The two new tets: [a,b,c,d] and [b,a,c,e] are //
7392 // returned in [0] and [1] of 'fliptets'. As a result, the edge [e,d] is //
7393 // replaced by the face [a,b,c]. //
7394 // //
7395 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7396 // the five vertices may be 'dummypoint'. There are two canonical cases: //
7397 // (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
7398 // we reconfigure e to d, i.e., turnover it. //
7399 // (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets. //
7400 // If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
7401 // three old tets counterclockwisely (right-hand rule) until a or b //
7402 // is in c's position. //
7403 // //
7404 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7405 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7406 // after the insertion of a new point. It is assumed that 'a' is the new //
7407 // point. In this case, only link faces of 'a' are queued. //
7408 // //
7409 // If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a //
7410 // segment. There may be two (interior) subfaces sharing at [e,d], which are //
7411 // [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), //
7412 // or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces //
7413 // and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted //
7414 // back into the tetrahedralization. //
7415 // //
7417 
7418 void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
7419 {
7420  triface topcastets[3], botcastets[3];
7421  triface newface, casface;
7422  face flipshs[3];
7423  face checkseg;
7424  point pa, pb, pc, pd, pe;
7425  REAL attrib, volume;
7426  int dummyflag = 0; // Rangle = {-1, 0, 1, 2}
7427  int spivot = -1, scount = 0; // for flip22()
7428  int t1ver;
7429  int i, j;
7430 
7431  if (hullflag > 0) {
7432  // Check if e is 'dummypoint'.
7433  if (org(fliptets[0]) == dummypoint) {
7434  // Reverse the edge.
7435  for (i = 0; i < 3; i++) {
7436  esymself(fliptets[i]);
7437  }
7438  // Swap the last two tets.
7439  newface = fliptets[1];
7440  fliptets[1] = fliptets[2];
7441  fliptets[2] = newface;
7442  dummyflag = -1; // e is dummypoint.
7443  } else {
7444  // Check if a or b is the 'dummypoint'.
7445  if (apex(fliptets[0]) == dummypoint) {
7446  dummyflag = 1; // a is dummypoint.
7447  newface = fliptets[0];
7448  fliptets[0] = fliptets[1];
7449  fliptets[1] = fliptets[2];
7450  fliptets[2] = newface;
7451  } else if (apex(fliptets[1]) == dummypoint) {
7452  dummyflag = 2; // b is dummypoint.
7453  newface = fliptets[0];
7454  fliptets[0] = fliptets[2];
7455  fliptets[2] = fliptets[1];
7456  fliptets[1] = newface;
7457  } else {
7458  dummyflag = 0; // either c or d may be dummypoint.
7459  }
7460  }
7461  }
7462 
7463  pa = apex(fliptets[0]);
7464  pb = apex(fliptets[1]);
7465  pc = apex(fliptets[2]);
7466  pd = dest(fliptets[0]);
7467  pe = org(fliptets[0]);
7468 
7469  flip32count++;
7470 
7471  // Get the outer boundary faces.
7472  for (i = 0; i < 3; i++) {
7473  eorgoppo(fliptets[i], casface);
7474  fsym(casface, topcastets[i]);
7475  }
7476  for (i = 0; i < 3; i++) {
7477  edestoppo(fliptets[i], casface);
7478  fsym(casface, botcastets[i]);
7479  }
7480 
7481  if (checksubfaceflag) {
7482  // Check if there are interior subfaces at the edge [e,d].
7483  for (i = 0; i < 3; i++) {
7484  tspivot(fliptets[i], flipshs[i]);
7485  if (flipshs[i].sh != NULL) {
7486  // Found an interior subface.
7487  stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
7488  scount++;
7489  } else {
7490  spivot = i;
7491  }
7492  }
7493  }
7494 
7495  // Re-use fliptets[0] and fliptets[1].
7496  fliptets[0].ver = 11;
7497  fliptets[1].ver = 11;
7498  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7499  setelemmarker(fliptets[1].tet, 0);
7500  if (checksubsegflag) {
7501  // Dealloc the space to subsegments.
7502  if (fliptets[0].tet[8] != NULL) {
7503  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7504  fliptets[0].tet[8] = NULL;
7505  }
7506  if (fliptets[1].tet[8] != NULL) {
7507  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7508  fliptets[1].tet[8] = NULL;
7509  }
7510  }
7511  if (checksubfaceflag) {
7512  // Dealloc the space to subfaces.
7513  if (fliptets[0].tet[9] != NULL) {
7514  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7515  fliptets[0].tet[9] = NULL;
7516  }
7517  if (fliptets[1].tet[9] != NULL) {
7518  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7519  fliptets[1].tet[9] = NULL;
7520  }
7521  }
7522  if (checksubfaceflag) {
7523  if (scount > 0) {
7524  // The element attributes and volume constraint must be set correctly.
7525  // There are two subfaces involved in this flip. The three tets are
7526  // separated into two different regions, one may be exterior. The
7527  // first region has two tets, and the second region has only one.
7528  // The two created tets must be in the same region as the first region.
7529  // The element attributes and volume constraint must be set correctly.
7530  //assert(spivot != -1);
7531  // The tet fliptets[spivot] is in the first region.
7532  for (j = 0; j < 2; j++) {
7533  for (i = 0; i < numelemattrib; i++) {
7534  attrib = elemattribute(fliptets[spivot].tet, i);
7535  setelemattribute(fliptets[j].tet, i, attrib);
7536  }
7537  if (b->varvolume) {
7538  volume = volumebound(fliptets[spivot].tet);
7539  setvolumebound(fliptets[j].tet, volume);
7540  }
7541  }
7542  }
7543  }
7544  // Delete an old tet.
7545  tetrahedrondealloc(fliptets[2].tet);
7546 
7547  if (hullflag > 0) {
7548  // Check if c is dummypointc.
7549  if (pc != dummypoint) {
7550  // Check if d is dummypoint.
7551  if (pd != dummypoint) {
7552  // No hull tet is involved.
7553  } else {
7554  // We deleted three hull tets, and created one hull tet.
7555  hullsize -= 2;
7556  }
7557  setvertices(fliptets[0], pa, pb, pc, pd);
7558  setvertices(fliptets[1], pb, pa, pc, pe);
7559  } else {
7560  // c is dummypoint. The two new tets are hull tets.
7561  setvertices(fliptets[0], pb, pa, pd, pc);
7562  setvertices(fliptets[1], pa, pb, pe, pc);
7563  // Adjust badc -> abcd.
7564  esymself(fliptets[0]);
7565  // Adjust abec -> bace.
7566  esymself(fliptets[1]);
7567  // The hullsize does not change.
7568  }
7569  } else {
7570  setvertices(fliptets[0], pa, pb, pc, pd);
7571  setvertices(fliptets[1], pb, pa, pc, pe);
7572  }
7573 
7574  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7575  REAL volneg[3], volpos[2], vol_diff;
7576  if (pc != dummypoint) {
7577  if (pd != dummypoint) {
7578  volneg[0] = tetprismvol(pe, pd, pa, pb);
7579  volneg[1] = tetprismvol(pe, pd, pb, pc);
7580  volneg[2] = tetprismvol(pe, pd, pc, pa);
7581  volpos[0] = tetprismvol(pa, pb, pc, pd);
7582  volpos[1] = tetprismvol(pb, pa, pc, pe);
7583  } else { // pd == dummypoint
7584  volneg[0] = 0.;
7585  volneg[1] = 0.;
7586  volneg[2] = 0.;
7587  volpos[0] = 0.;
7588  volpos[1] = tetprismvol(pb, pa, pc, pe);
7589  }
7590  } else { // pc == dummypoint.
7591  volneg[0] = tetprismvol(pe, pd, pa, pb);
7592  volneg[1] = 0.;
7593  volneg[2] = 0.;
7594  volpos[0] = 0.;
7595  volpos[1] = 0.;
7596  }
7597  vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
7598  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7599  }
7600 
7601  // Bond abcd <==> bace.
7602  bond(fliptets[0], fliptets[1]);
7603  // Bond new faces to top outer boundary faces (at abcd).
7604  for (i = 0; i < 3; i++) {
7605  esym(fliptets[0], newface);
7606  bond(newface, topcastets[i]);
7607  enextself(fliptets[0]);
7608  }
7609  // Bond new faces to bottom outer boundary faces (at bace).
7610  for (i = 0; i < 3; i++) {
7611  esym(fliptets[1], newface);
7612  bond(newface, botcastets[i]);
7613  eprevself(fliptets[1]);
7614  }
7615 
7616  if (checksubsegflag) {
7617  // Bond 9 segments to new (flipped) tets.
7618  for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
7619  if (issubseg(topcastets[i])) {
7620  tsspivot1(topcastets[i], checkseg);
7621  tssbond1(fliptets[0], checkseg);
7622  sstbond1(checkseg, fliptets[0]);
7623  tssbond1(fliptets[1], checkseg);
7624  sstbond1(checkseg, fliptets[1]);
7625  if (fc->chkencflag & 1) {
7626  enqueuesubface(badsubsegs, &checkseg);
7627  }
7628  }
7629  enextself(fliptets[0]);
7630  eprevself(fliptets[1]);
7631  }
7632  // The three top edges.
7633  for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
7634  esym(fliptets[0], newface);
7635  eprevself(newface);
7636  enext(topcastets[i], casface);
7637  if (issubseg(casface)) {
7638  tsspivot1(casface, checkseg);
7639  tssbond1(newface, checkseg);
7640  sstbond1(checkseg, newface);
7641  if (fc->chkencflag & 1) {
7642  enqueuesubface(badsubsegs, &checkseg);
7643  }
7644  }
7645  enextself(fliptets[0]);
7646  }
7647  // The three bot edges.
7648  for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
7649  esym(fliptets[1], newface);
7650  enextself(newface);
7651  eprev(botcastets[i], casface);
7652  if (issubseg(casface)) {
7653  tsspivot1(casface, checkseg);
7654  tssbond1(newface, checkseg);
7655  sstbond1(checkseg, newface);
7656  if (fc->chkencflag & 1) {
7657  enqueuesubface(badsubsegs, &checkseg);
7658  }
7659  }
7660  eprevself(fliptets[1]);
7661  }
7662  } // if (checksubsegflag)
7663 
7664  if (checksubfaceflag) {
7665  face checksh;
7666  // Bond the top three casing subfaces.
7667  for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
7668  if (issubface(topcastets[i])) {
7669  tspivot(topcastets[i], checksh);
7670  esym(fliptets[0], newface);
7671  sesymself(checksh);
7672  tsbond(newface, checksh);
7673  if (fc->chkencflag & 2) {
7674  enqueuesubface(badsubfacs, &checksh);
7675  }
7676  }
7677  enextself(fliptets[0]);
7678  }
7679  // Bond the bottom three casing subfaces.
7680  for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
7681  if (issubface(botcastets[i])) {
7682  tspivot(botcastets[i], checksh);
7683  esym(fliptets[1], newface);
7684  sesymself(checksh);
7685  tsbond(newface, checksh);
7686  if (fc->chkencflag & 2) {
7687  enqueuesubface(badsubfacs, &checksh);
7688  }
7689  }
7690  eprevself(fliptets[1]);
7691  }
7692 
7693  if (scount > 0) {
7694  face flipfaces[2];
7695  // Perform a 2-to-2 flip in subfaces.
7696  flipfaces[0] = flipshs[(spivot + 1) % 3];
7697  flipfaces[1] = flipshs[(spivot + 2) % 3];
7698  sesymself(flipfaces[1]);
7699  flip22(flipfaces, 0, fc->chkencflag);
7700  // Connect the flipped subfaces to flipped tets.
7701  // First go to the corresponding flipping edge.
7702  // Re-use top- and botcastets[0].
7703  topcastets[0] = fliptets[0];
7704  botcastets[0] = fliptets[1];
7705  for (i = 0; i < ((spivot + 1) % 3); i++) {
7706  enextself(topcastets[0]);
7707  eprevself(botcastets[0]);
7708  }
7709  // Connect the top subface to the top tets.
7710  esymself(topcastets[0]);
7711  sesymself(flipfaces[0]);
7712  // Check if there already exists a subface.
7713  tspivot(topcastets[0], checksh);
7714  if (checksh.sh == NULL) {
7715  tsbond(topcastets[0], flipfaces[0]);
7716  fsymself(topcastets[0]);
7717  sesymself(flipfaces[0]);
7718  tsbond(topcastets[0], flipfaces[0]);
7719  } else {
7720  // An invalid 2-to-2 flip. Report a bug.
7721  terminatetetgen(this, 2);
7722  }
7723  // Connect the bot subface to the bottom tets.
7724  esymself(botcastets[0]);
7725  sesymself(flipfaces[1]);
7726  // Check if there already exists a subface.
7727  tspivot(botcastets[0], checksh);
7728  if (checksh.sh == NULL) {
7729  tsbond(botcastets[0], flipfaces[1]);
7730  fsymself(botcastets[0]);
7731  sesymself(flipfaces[1]);
7732  tsbond(botcastets[0], flipfaces[1]);
7733  } else {
7734  // An invalid 2-to-2 flip. Report a bug.
7735  terminatetetgen(this, 2);
7736  }
7737  } // if (scount > 0)
7738  } // if (checksubfaceflag)
7739 
7740  if (fc->chkencflag & 4) {
7741  // Put two new tets into check list.
7742  for (i = 0; i < 2; i++) {
7743  enqueuetetrahedron(&(fliptets[i]));
7744  }
7745  }
7746 
7747  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7748  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7749  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
7750  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7751  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
7752 
7753  if (hullflag > 0) {
7754  if (dummyflag != 0) {
7755  // Restore the original position of the points (for flipnm()).
7756  if (dummyflag == -1) {
7757  // e were dummypoint. Swap the two new tets.
7758  newface = fliptets[0];
7759  fliptets[0] = fliptets[1];
7760  fliptets[1] = newface;
7761  } else {
7762  // a or b was dummypoint.
7763  if (dummyflag == 1) {
7764  eprevself(fliptets[0]);
7765  enextself(fliptets[1]);
7766  } else { // dummyflag == 2
7767  enextself(fliptets[0]);
7768  eprevself(fliptets[1]);
7769  }
7770  }
7771  }
7772  }
7773 
7774  if (fc->enqflag > 0) {
7775  // Queue faces which may be locally non-Delaunay.
7776  // pa = org(fliptets[0]); // 'a' may be a new vertex.
7777  enextesym(fliptets[0], newface);
7778  flippush(flipstack, &newface);
7779  eprevesym(fliptets[1], newface);
7780  flippush(flipstack, &newface);
7781  if (fc->enqflag > 1) {
7782  //pb = dest(fliptets[0]);
7783  eprevesym(fliptets[0], newface);
7784  flippush(flipstack, &newface);
7785  enextesym(fliptets[1], newface);
7786  flippush(flipstack, &newface);
7787  //pc = apex(fliptets[0]);
7788  esym(fliptets[0], newface);
7789  flippush(flipstack, &newface);
7790  esym(fliptets[1], newface);
7791  flippush(flipstack, &newface);
7792  }
7793  }
7794 
7795  recenttet = fliptets[0];
7796 }
7797 
7799 // //
7800 // flip41() Perform a 4-to-1 flip (Remove a vertex). //
7801 // //
7802 // 'fliptets' is an array of four tetrahedra in the star of the removing //
7803 // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
7804 // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
7805 // p]. On return, 'fliptets[0]' is the new tet [a,b,c,d]. //
7806 // //
7807 // If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
7808 // The 'hullsize' may be changed. Note that p may be dummypoint. In this //
7809 // case, four hull tets are replaced by one real tet. //
7810 // //
7811 // If 'checksubface' flag is set (>0), it is possible that there are three //
7812 // interior subfaces connecting at p. If so, a 3-to-1 flip is performed to //
7813 // to remove p from the surface triangulation. //
7814 // //
7815 // If it is called by the routine incrementalflip(), we assume that d is the //
7816 // newly inserted vertex. //
7817 // //
7819 
7820 void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
7821 {
7822  triface topcastets[3], botcastet;
7823  triface newface, neightet;
7824  face flipshs[4];
7825  point pa, pb, pc, pd, pp;
7826  int dummyflag = 0; // in {0, 1, 2, 3, 4}
7827  int spivot = -1, scount = 0;
7828  int t1ver;
7829  int i;
7830 
7831  pa = org(fliptets[3]);
7832  pb = dest(fliptets[3]);
7833  pc = apex(fliptets[3]);
7834  pd = dest(fliptets[0]);
7835  pp = org(fliptets[0]); // The removing vertex.
7836 
7837  flip41count++;
7838 
7839  // Get the outer boundary faces.
7840  for (i = 0; i < 3; i++) {
7841  enext(fliptets[i], topcastets[i]);
7842  fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
7843  enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
7844  }
7845  fsym(fliptets[3], botcastet); // [b,a,c,#]
7846 
7847  if (checksubfaceflag) {
7848  // Check if there are three subfaces at 'p'.
7849  // Re-use 'newface'.
7850  for (i = 0; i < 3; i++) {
7851  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
7852  tspivot(newface, flipshs[i]);
7853  if (flipshs[i].sh != NULL) {
7854  spivot = i; // Remember this subface.
7855  scount++;
7856  }
7857  enextself(fliptets[3]);
7858  }
7859  if (scount > 0) {
7860  // There are three subfaces connecting at p.
7861  if (scount < 3) {
7862  // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
7863  assert(scount == 1); // spivot >= 0
7864  // Go to the tet containing the three subfaces.
7865  fsym(topcastets[spivot], neightet);
7866  // Get the three subfaces connecting at p.
7867  for (i = 0; i < 3; i++) {
7868  esym(neightet, newface);
7869  tspivot(newface, flipshs[i]);
7870  assert(flipshs[i].sh != NULL);
7871  eprevself(neightet);
7872  }
7873  } else {
7874  spivot = 3; // The new subface is [a,b,c].
7875  }
7876  }
7877  } // if (checksubfaceflag)
7878 
7879 
7880  // Re-use fliptets[0] for [a,b,c,d].
7881  fliptets[0].ver = 11;
7882  setelemmarker(fliptets[0].tet, 0); // Clean all flags.
7883  // NOTE: the element attributes and volume constraint remain unchanged.
7884  if (checksubsegflag) {
7885  // Dealloc the space to subsegments.
7886  if (fliptets[0].tet[8] != NULL) {
7887  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7888  fliptets[0].tet[8] = NULL;
7889  }
7890  }
7891  if (checksubfaceflag) {
7892  // Dealloc the space to subfaces.
7893  if (fliptets[0].tet[9] != NULL) {
7894  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7895  fliptets[0].tet[9] = NULL;
7896  }
7897  }
7898  // Delete the other three tets.
7899  for (i = 1; i < 4; i++) {
7900  tetrahedrondealloc(fliptets[i].tet);
7901  }
7902 
7903  if (pp != dummypoint) {
7904  // Mark the point pp as unused.
7906  unuverts++;
7907  }
7908 
7909  // Create the new tet [a,b,c,d].
7910  if (hullflag > 0) {
7911  // One of the five vertices may be 'dummypoint'.
7912  if (pa == dummypoint) {
7913  // pa is dummypoint.
7914  setvertices(fliptets[0], pc, pb, pd, pa);
7915  esymself(fliptets[0]); // [b,c,a,d]
7916  eprevself(fliptets[0]); // [a,b,c,d]
7917  dummyflag = 1;
7918  } else if (pb == dummypoint) {
7919  setvertices(fliptets[0], pa, pc, pd, pb);
7920  esymself(fliptets[0]); // [c,a,b,d]
7921  enextself(fliptets[0]); // [a,b,c,d]
7922  dummyflag = 2;
7923  } else if (pc == dummypoint) {
7924  setvertices(fliptets[0], pb, pa, pd, pc);
7925  esymself(fliptets[0]); // [a,b,c,d]
7926  dummyflag = 3;
7927  } else if (pd == dummypoint) {
7928  setvertices(fliptets[0], pa, pb, pc, pd);
7929  dummyflag = 4;
7930  } else {
7931  setvertices(fliptets[0], pa, pb, pc, pd);
7932  if (pp == dummypoint) {
7933  dummyflag = -1;
7934  } else {
7935  dummyflag = 0;
7936  }
7937  }
7938  if (dummyflag > 0) {
7939  // We deleted 3 hull tets, and create 1 hull tet.
7940  hullsize -= 2;
7941  } else if (dummyflag < 0) {
7942  // We deleted 4 hull tets.
7943  hullsize -= 4;
7944  // meshedges does not change.
7945  }
7946  } else {
7947  setvertices(fliptets[0], pa, pb, pc, pd);
7948  }
7949 
7950  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7951  REAL volneg[4], volpos[1], vol_diff;
7952  if (dummyflag > 0) {
7953  if (pa == dummypoint) {
7954  volneg[0] = 0.;
7955  volneg[1] = tetprismvol(pp, pd, pb, pc);
7956  volneg[2] = 0.;
7957  volneg[3] = 0.;
7958  } else if (pb == dummypoint) {
7959  volneg[0] = 0.;
7960  volneg[1] = 0.;
7961  volneg[2] = tetprismvol(pp, pd, pc, pa);
7962  volneg[3] = 0.;
7963  } else if (pc == dummypoint) {
7964  volneg[0] = tetprismvol(pp, pd, pa, pb);
7965  volneg[1] = 0.;
7966  volneg[2] = 0.;
7967  volneg[3] = 0.;
7968  } else { // pd == dummypoint
7969  volneg[0] = 0.;
7970  volneg[1] = 0.;
7971  volneg[2] = 0.;
7972  volneg[3] = tetprismvol(pa, pb, pc, pp);
7973  }
7974  volpos[0] = 0.;
7975  } else if (dummyflag < 0) {
7976  volneg[0] = 0.;
7977  volneg[1] = 0.;
7978  volneg[2] = 0.;
7979  volneg[3] = 0.;
7980  volpos[0] = tetprismvol(pa, pb, pc, pd);
7981  } else {
7982  volneg[0] = tetprismvol(pp, pd, pa, pb);
7983  volneg[1] = tetprismvol(pp, pd, pb, pc);
7984  volneg[2] = tetprismvol(pp, pd, pc, pa);
7985  volneg[3] = tetprismvol(pa, pb, pc, pp);
7986  volpos[0] = tetprismvol(pa, pb, pc, pd);
7987  }
7988  vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
7989  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7990  }
7991 
7992  // Bond the new tet to adjacent tets.
7993  for (i = 0; i < 3; i++) {
7994  esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
7995  bond(newface, topcastets[i]);
7996  enextself(fliptets[0]);
7997  }
7998  bond(fliptets[0], botcastet);
7999 
8000  if (checksubsegflag) {
8001  face checkseg;
8002  // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
8003  for (i = 0; i < 3; i++) {
8004  eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
8005  if (issubseg(newface)) {
8006  tsspivot1(newface, checkseg);
8007  esym(fliptets[0], newface);
8008  enextself(newface); // At edges [a,d], [b,d], [c,d].
8009  tssbond1(newface, checkseg);
8010  sstbond1(checkseg, newface);
8011  if (fc->chkencflag & 1) {
8012  enqueuesubface(badsubsegs, &checkseg);
8013  }
8014  }
8015  enextself(fliptets[0]);
8016  }
8017  for (i = 0; i < 3; i++) {
8018  if (issubseg(topcastets[i])) {
8019  tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
8020  tssbond1(fliptets[0], checkseg);
8021  sstbond1(checkseg, fliptets[0]);
8022  if (fc->chkencflag & 1) {
8023  enqueuesubface(badsubsegs, &checkseg);
8024  }
8025  }
8026  enextself(fliptets[0]);
8027  }
8028  }
8029 
8030  if (checksubfaceflag) {
8031  face checksh;
8032  // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
8033  for (i = 0; i < 3; i++) {
8034  if (issubface(topcastets[i])) {
8035  tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
8036  esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
8037  sesymself(checksh);
8038  tsbond(newface, checksh);
8039  if (fc->chkencflag & 2) {
8040  enqueuesubface(badsubfacs, &checksh);
8041  }
8042  }
8043  enextself(fliptets[0]);
8044  }
8045  if (issubface(botcastet)) {
8046  tspivot(botcastet, checksh); // At face [b,a,c]
8047  sesymself(checksh);
8048  tsbond(fliptets[0], checksh);
8049  if (fc->chkencflag & 2) {
8050  enqueuesubface(badsubfacs, &checksh);
8051  }
8052  }
8053 
8054  if (spivot >= 0) {
8055  // Perform a 3-to-1 flip in surface triangulation.
8056  // Depending on the value of 'spivot', the three subfaces are:
8057  // - 0: [a,b,p], [b,d,p], [d,a,p]
8058  // - 1: [b,c,p], [c,d,p], [d,b,p]
8059  // - 2: [c,a,p], [a,d,p], [d,c,p]
8060  // - 3: [a,b,p], [b,c,p], [c,a,p]
8061  // Adjust the three subfaces such that their origins are p, i.e.,
8062  // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
8063  for (i = 0; i < 3; i++) {
8064  senext2self(flipshs[i]);
8065  }
8066  flip31(flipshs, 0);
8067  // Delete the three old subfaces.
8068  for (i = 0; i < 3; i++) {
8069  shellfacedealloc(subfaces, flipshs[i].sh);
8070  }
8071  if (spivot < 3) {
8072  // // Bond the new subface to the new tet [a,b,c,d].
8073  tsbond(topcastets[spivot], flipshs[3]);
8074  fsym(topcastets[spivot], newface);
8075  sesym(flipshs[3], checksh);
8076  tsbond(newface, checksh);
8077  } else {
8078  // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
8079  tsbond(fliptets[0], flipshs[3]);
8080  fsym(fliptets[0], newface);
8081  sesym(flipshs[3], checksh);
8082  tsbond(newface, checksh);
8083  }
8084  } // if (spivot > 0)
8085  } // if (checksubfaceflag)
8086 
8087  if (fc->chkencflag & 4) {
8088  enqueuetetrahedron(&(fliptets[0]));
8089  }
8090 
8091  // Update the point-to-tet map.
8092  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8093  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8094  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8095  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8096 
8097  if (fc->enqflag > 0) {
8098  // Queue faces which may be locally non-Delaunay.
8099  flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
8100  if (fc->enqflag > 1) {
8101  for (i = 0; i < 3; i++) {
8102  esym(fliptets[0], newface);
8103  flippush(flipstack, &newface);
8104  enextself(fliptets[0]);
8105  }
8106  }
8107  }
8108 
8109  recenttet = fliptets[0];
8110 }
8111 
8113 // //
8114 // flipnm() Flip an edge through a sequence of elementary flips. //
8115 // //
8116 // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
8117 // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
8118 // use the right-hand rule. //
8119 // //
8120 // 'level' (>= 0) indicates the current link level. If 'level > 0', we are //
8121 // flipping a link edge of an edge [a',b'], and 'abedgepivot' indicates //
8122 // which link edge, i.e., [c',b'] or [a',c'], is [a,b] These two parameters //
8123 // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that //
8124 // do not inside the reduced star of edge [a',b']. //
8125 // //
8126 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8127 // in flipnm([a,b]) so that the mesh is returned to its original state //
8128 // before doing the flipnm([a,b]) operation. //
8129 // //
8130 // The return value is an integer nn, where nn <= n. If nn is 2, then the //
8131 // edge is flipped. The first and the second tets in 'abtets' are new tets. //
8132 // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets //
8133 // in the current star of [a,b]. //
8134 // //
8135 // ASSUMPTIONS: //
8136 // - Neither a nor b is 'dummypoint'. //
8137 // - [a,b] must not be a segment. //
8138 // //
8140 
8141 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
8142  flipconstraints* fc)
8143 {
8144  triface fliptets[3], spintet, flipedge;
8145  triface *tmpabtets, *parytet;
8146  point pa, pb, pc, pd, pe, pf;
8147  REAL ori;
8148  int hullflag, hulledgeflag;
8149  int reducflag, rejflag;
8150  int reflexlinkedgecount;
8151  int edgepivot;
8152  int n1, nn;
8153  int t1ver;
8154  int i, j;
8155 
8156  pa = org(abtets[0]);
8157  pb = dest(abtets[0]);
8158 
8159  if (n > 3) {
8160  // Try to reduce the size of the Star(ab) by flipping a face in it.
8161  reflexlinkedgecount = 0;
8162 
8163  for (i = 0; i < n; i++) {
8164  // Let the face of 'abtets[i]' be [a,b,c].
8165  if (checksubfaceflag) {
8166  if (issubface(abtets[i])) {
8167  continue; // Skip a subface.
8168  }
8169  }
8170  // Do not flip this face if it is involved in two Stars.
8171  if ((elemcounter(abtets[i]) > 1) ||
8172  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8173  continue;
8174  }
8175 
8176  pc = apex(abtets[i]);
8177  pd = apex(abtets[(i + 1) % n]);
8178  pe = apex(abtets[(i - 1 + n) % n]);
8179  if ((pd == dummypoint) || (pe == dummypoint)) {
8180  continue; // [a,b,c] is a hull face.
8181  }
8182 
8183 
8184  // Decide whether [a,b,c] is flippable or not.
8185  reducflag = 0;
8186 
8187  hullflag = (pc == dummypoint); // pc may be dummypoint.
8188  hulledgeflag = 0;
8189  if (hullflag == 0) {
8190  ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
8191  if (ori > 0) {
8192  ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
8193  if (ori > 0) {
8194  // Test if [a,b] is locally convex OR flat.
8195  ori = orient3d(pa, pb, pd, pe);
8196  if (ori > 0) {
8197  // Found a 2-to-3 flip: [a,b,c] => [e,d]
8198  reducflag = 1;
8199  } else if (ori == 0) {
8200  // [a,b] is flat.
8201  if (n == 4) {
8202  // The "flat" tet can be removed immediately by a 3-to-2 flip.
8203  reducflag = 1;
8204  // Check if [e,d] is a hull edge.
8205  pf = apex(abtets[(i + 2) % n]);
8206  hulledgeflag = (pf == dummypoint);
8207  }
8208  }
8209  }
8210  }
8211  if (!reducflag) {
8212  reflexlinkedgecount++;
8213  }
8214  } else {
8215  // 'c' is dummypoint.
8216  if (n == 4) {
8217  // Let the vertex opposite to 'c' is 'f'.
8218  // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
8219  // are valid tets.
8220  // Note: When the mesh is not convex, it is possible that [a,b] is
8221  // locally non-convex (at hull faces [a,b,e] and [b,a,d]).
8222  // In this case, an edge flip [a,b] to [e,d] is still possible.
8223  pf = apex(abtets[(i + 2) % n]);
8224  assert(pf != dummypoint);
8225  ori = orient3d(pd, pe, pf, pa);
8226  if (ori < 0) {
8227  ori = orient3d(pe, pd, pf, pb);
8228  if (ori < 0) {
8229  // Found a 4-to-4 flip: [a,b] => [e,d]
8230  reducflag = 1;
8231  ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
8232  hulledgeflag = 1; // [e,d] is a hull edge.
8233  }
8234  }
8235  }
8236  } // if (hullflag)
8237 
8238  if (reducflag) {
8239  if (nonconvex && hulledgeflag) {
8240  // We will create a hull edge [e,d]. Make sure it does not exist.
8241  if (getedge(pe, pd, &spintet)) {
8242  // The 2-to-3 flip is not a topological valid flip.
8243  reducflag = 0;
8244  }
8245  }
8246  }
8247 
8248  if (reducflag) {
8249  // [a,b,c] could be removed by a 2-to-3 flip.
8250  rejflag = 0;
8251  if (fc->checkflipeligibility) {
8252  // Check if the flip can be performed.
8253  rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
8254  abedgepivot, fc);
8255  }
8256  if (!rejflag) {
8257  // Do flip: [a,b,c] => [e,d].
8258  fliptets[0] = abtets[i];
8259  fsym(fliptets[0], fliptets[1]); // abtets[i-1].
8260  flip23(fliptets, hullflag, fc);
8261 
8262  // Shrink the array 'abtets', maintain the original order.
8263  // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
8264  // are flipped, i.e., they do not in Star(ab) anymore.
8265  // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
8266  // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
8267  //
8268  // before after
8269  // [0] |___________| [0] |___________|
8270  // ... |___________| ... |___________|
8271  // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_|
8272  // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_|
8273  // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_|
8274  // ... |___________| ... |___________|
8275  // [n-2] |___________| [n-2] |___________|
8276  // [n-1] |___________| [n-1] |_[i]_2-t-3_|
8277  //
8278  edestoppoself(fliptets[0]); // [a,b,e,d]
8279  // Increase the counter of this new tet (it is in Star(ab)).
8280  increaseelemcounter(fliptets[0]);
8281  abtets[(i - 1 + n) % n] = fliptets[0];
8282  for (j = i; j < n - 1; j++) {
8283  abtets[j] = abtets[j + 1]; // Upshift
8284  }
8285  // The last entry 'abtets[n-1]' is empty. It is used in two ways:
8286  // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
8287  // (ii) it remembers the position [i] where this flip took place.
8288  // These informations let us to either undo this flip or recover
8289  // the original edge link (for collecting new created tets).
8290  //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remembered.
8291  abtets[n - 1].tet = (tetrahedron *) pc;
8292  abtets[n - 1].ver = 0; // Clear it.
8293  // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
8294  // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
8295  abtets[n - 1].ver |= (1 << 4);
8296  // The poisition [i] of this flip is saved above the 7th bit.
8297  abtets[n - 1].ver |= (i << 6);
8298 
8299  if (fc->collectnewtets) {
8300  // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
8301  // Re-use the global array 'cavetetlist'.
8302  for (j = 1; j < 3; j++) {
8303  cavetetlist->newindex((void **) &parytet);
8304  *parytet = fliptets[j]; // fliptets[1], fliptets[2].
8305  }
8306  }
8307 
8308  // Star(ab) is reduced. Try to flip the edge [a,b].
8309  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8310 
8311  if (nn == 2) {
8312  // The edge has been flipped.
8313  return nn;
8314  } else { // if (nn > 2)
8315  // The edge is not flipped.
8316  if (fc->unflip || (ori == 0)) {
8317  // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
8318  // transform [e,d] => [a,b,c].
8319  // 'ori == 0' means that the previous flip created a degenerated
8320  // tet. It must be removed.
8321  // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
8322  // find another two tets [e,d,b,c] and [e,d,c,a].
8323  fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
8324  edestoppoself(fliptets[0]); // [e,d,a,b]
8325  fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
8326  fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
8327  assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK
8328  // Restore the two original tets in Star(ab).
8329  flip32(fliptets, hullflag, fc);
8330  // Marktest the two restored tets in Star(ab).
8331  for (j = 0; j < 2; j++) {
8332  increaseelemcounter(fliptets[j]);
8333  }
8334  // Expand the array 'abtets', maintain the original order.
8335  for (j = n - 2; j>= i; j--) {
8336  abtets[j + 1] = abtets[j]; // Downshift
8337  }
8338  // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
8339  // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
8340  // respectively.
8341  esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
8342  abtets[i] = fliptets[0]; // [a,b,c,d]
8343  nn++;
8344  if (fc->collectnewtets) {
8345  // Pop two (flipped) tets from the stack.
8346  cavetetlist->objects -= 2;
8347  }
8348  } // if (unflip || (ori == 0))
8349  } // if (nn > 2)
8350 
8351  if (!fc->unflip) {
8352  // The flips are not reversed. The current Star(ab) can not be
8353  // further reduced. Return its current size (# of tets).
8354  return nn;
8355  }
8356  // unflip is set.
8357  // Continue the search for flips.
8358  }
8359  } // if (reducflag)
8360  } // i
8361 
8362  // The Star(ab) is not reduced.
8363  if (reflexlinkedgecount > 0) {
8364  // There are reflex edges in the Link(ab).
8365  if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
8366  ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
8367  // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
8368  for (i = 0; i < n; i++) {
8369  // Do not flip this face [a,b,c] if there are two Stars involved.
8370  if ((elemcounter(abtets[i]) > 1) ||
8371  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8372  continue;
8373  }
8374  pc = apex(abtets[i]);
8375  if (pc == dummypoint) {
8376  continue; // [a,b] is a hull edge.
8377  }
8378  pd = apex(abtets[(i + 1) % n]);
8379  pe = apex(abtets[(i - 1 + n) % n]);
8380  if ((pd == dummypoint) || (pe == dummypoint)) {
8381  continue; // [a,b,c] is a hull face.
8382  }
8383 
8384 
8385  edgepivot = 0; // No edge is selected yet.
8386 
8387  // Test if [b,c] is locally convex or flat.
8388  ori = orient3d(pb, pc, pd, pe);
8389  if (ori <= 0) {
8390  // Select the edge [c,b].
8391  enext(abtets[i], flipedge); // [b,c,a,d]
8392  edgepivot = 1;
8393  }
8394  if (!edgepivot) {
8395  // Test if [c,a] is locally convex or flat.
8396  ori = orient3d(pc, pa, pd, pe);
8397  if (ori <= 0) {
8398  // Select the edge [a,c].
8399  eprev(abtets[i], flipedge); // [c,a,b,d].
8400  edgepivot = 2;
8401  }
8402  }
8403 
8404  if (!edgepivot) continue;
8405 
8406  // An edge is selected.
8407  if (checksubsegflag) {
8408  // Do not flip it if it is a segment.
8409  if (issubseg(flipedge)) {
8410  if (fc->collectencsegflag) {
8411  face checkseg, *paryseg;
8412  tsspivot1(flipedge, checkseg);
8413  if (!sinfected(checkseg)) {
8414  // Queue this segment in list.
8415  sinfect(checkseg);
8416  caveencseglist->newindex((void **) &paryseg);
8417  *paryseg = checkseg;
8418  }
8419  }
8420  continue;
8421  }
8422  }
8423 
8424  // Try to flip the selected edge ([c,b] or [a,c]).
8425  esymself(flipedge);
8426  // Count the number of tets at the edge.
8427  n1 = 0;
8428  j = 0; // Sum of the star counters.
8429  spintet = flipedge;
8430  while (1) {
8431  n1++;
8432  j += (elemcounter(spintet));
8433  fnextself(spintet);
8434  if (spintet.tet == flipedge.tet) break;
8435  }
8436  assert(n1 >= 3);
8437  if (j > 2) {
8438  // The Star(flipedge) overlaps other Stars.
8439  continue; // Do not flip this edge.
8440  }
8441  // Only two tets can be marktested.
8442  assert(j == 2);
8443 
8444  if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
8445  // The star size exceeds the given limit.
8446  continue; // Do not flip it.
8447  }
8448 
8449  // Allocate spaces for Star(flipedge).
8450  tmpabtets = new triface[n1];
8451  // Form the Star(flipedge).
8452  j = 0;
8453  spintet = flipedge;
8454  while (1) {
8455  tmpabtets[j] = spintet;
8456  // Increase the star counter of this tet.
8457  increaseelemcounter(tmpabtets[j]);
8458  j++;
8459  fnextself(spintet);
8460  if (spintet.tet == flipedge.tet) break;
8461  }
8462 
8463  // Try to flip the selected edge away.
8464  nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
8465 
8466  if (nn == 2) {
8467  // The edge is flipped. Star(ab) is reduced.
8468  // Shrink the array 'abtets', maintain the original order.
8469  if (edgepivot == 1) {
8470  // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
8471  spintet = tmpabtets[0]; // [d,a,e,b]
8472  enextself(spintet);
8473  esymself(spintet);
8474  enextself(spintet); // [a,b,e,d]
8475  } else {
8476  // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
8477  spintet = tmpabtets[1]; // [b,d,e,a]
8478  eprevself(spintet);
8479  esymself(spintet);
8480  eprevself(spintet); // [a,b,e,d]
8481  } // edgepivot == 2
8482  assert(elemcounter(spintet) == 0); // It's a new tet.
8483  increaseelemcounter(spintet); // It is in Star(ab).
8484  // Put the new tet at [i-1]-th entry.
8485  abtets[(i - 1 + n) % n] = spintet;
8486  for (j = i; j < n - 1; j++) {
8487  abtets[j] = abtets[j + 1]; // Upshift
8488  }
8489  // Remember the flips in the last entry of the array 'abtets'.
8490  // They can be used to recover the flipped edge.
8491  abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
8492  abtets[n - 1].ver = 0; // Clear it.
8493  // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
8494  abtets[n - 1].ver |= edgepivot;
8495  // Use the 6th bit to signal this n1-to-m1 flip.
8496  abtets[n - 1].ver |= (1 << 5);
8497  // The poisition [i] of this flip is saved from 7th to 19th bit.
8498  abtets[n - 1].ver |= (i << 6);
8499  // The size of the star 'n1' is saved from 20th bit.
8500  abtets[n - 1].ver |= (n1 << 19);
8501 
8502  // Remember the flipped link vertex 'c'. It can be used to recover
8503  // the original edge link of [a,b], and to collect new tets.
8504  tmpabtets[0].tet = (tetrahedron *) pc;
8505  tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
8506 
8507  // Continue to flip the edge [a,b].
8508  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8509 
8510  if (nn == 2) {
8511  // The edge has been flipped.
8512  return nn;
8513  } else { // if (nn > 2) {
8514  // The edge is not flipped.
8515  if (fc->unflip) {
8516  // Recover the flipped edge ([c,b] or [a,c]).
8517  assert(nn == (n - 1));
8518  // The sequence of flips are saved in 'tmpabtets'.
8519  // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
8520  // the flipping of edge [c,b] or [a,c].It must still exist in
8521  // Star(ab). It is the start tet to recover the flipped edge.
8522  if (edgepivot == 1) {
8523  // The flip edge is [c,b].
8524  tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8525  eprevself(tmpabtets[0]);
8526  esymself(tmpabtets[0]);
8527  eprevself(tmpabtets[0]); // [d,a,e,b]
8528  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
8529  } else {
8530  // The flip edge is [a,c].
8531  tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8532  enextself(tmpabtets[1]);
8533  esymself(tmpabtets[1]);
8534  enextself(tmpabtets[1]); // [b,d,e,a]
8535  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
8536  } // if (edgepivot == 2)
8537 
8538  // Recover the flipped edge ([c,b] or [a,c]).
8539  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8540 
8541  // Insert the two recovered tets into Star(ab).
8542  for (j = n - 2; j >= i; j--) {
8543  abtets[j + 1] = abtets[j]; // Downshift
8544  }
8545  if (edgepivot == 1) {
8546  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
8547  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
8548  // tmpabtets[2] is [c,b,e,d]
8549  fliptets[0] = tmpabtets[1];
8550  enextself(fliptets[0]);
8551  esymself(fliptets[0]); // [a,b,e,c]
8552  fliptets[1] = tmpabtets[0];
8553  esymself(fliptets[1]);
8554  eprevself(fliptets[1]); // [a,b,c,d]
8555  } else {
8556  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
8557  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
8558  // tmpabtets[2] is [a,c,e,d]
8559  fliptets[0] = tmpabtets[1];
8560  eprevself(fliptets[0]);
8561  esymself(fliptets[0]); // [a,b,e,c]
8562  fliptets[1] = tmpabtets[0];
8563  esymself(fliptets[1]);
8564  enextself(fliptets[1]); // [a,b,c,d]
8565  } // edgepivot == 2
8566  for (j = 0; j < 2; j++) {
8567  increaseelemcounter(fliptets[j]);
8568  }
8569  // Insert the two recovered tets into Star(ab).
8570  abtets[(i - 1 + n) % n] = fliptets[0];
8571  abtets[i] = fliptets[1];
8572  nn++;
8573  // Release the allocated spaces.
8574  delete [] tmpabtets;
8575  } // if (unflip)
8576  } // if (nn > 2)
8577 
8578  if (!fc->unflip) {
8579  // The flips are not reversed. The current Star(ab) can not be
8580  // further reduced. Return its size (# of tets).
8581  return nn;
8582  }
8583  // unflip is set.
8584  // Continue the search for flips.
8585  } else {
8586  // The selected edge is not flipped.
8587  if (fc->unflip) {
8588  // The memory should already be freed.
8589  assert(nn == n1);
8590  } else {
8591  // Release the memory used in this attempted flip.
8592  flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
8593  }
8594  // Decrease the star counters of tets in Star(flipedge).
8595  for (j = 0; j < nn; j++) {
8596  assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK
8597  decreaseelemcounter(tmpabtets[j]);
8598  }
8599  // Release the allocated spaces.
8600  delete [] tmpabtets;
8601  }
8602  } // i
8603  } // if (level...)
8604  } // if (reflexlinkedgecount > 0)
8605  } else {
8606  // Check if a 3-to-2 flip is possible.
8607  // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
8608  // we rearrange them such that the vertex e is dummypoint.
8609  hullflag = 0;
8610 
8611  if (apex(abtets[0]) == dummypoint) {
8612  pc = apex(abtets[1]);
8613  pd = apex(abtets[2]);
8614  pe = apex(abtets[0]);
8615  hullflag = 1;
8616  } else if (apex(abtets[1]) == dummypoint) {
8617  pc = apex(abtets[2]);
8618  pd = apex(abtets[0]);
8619  pe = apex(abtets[1]);
8620  hullflag = 2;
8621  } else {
8622  pc = apex(abtets[0]);
8623  pd = apex(abtets[1]);
8624  pe = apex(abtets[2]);
8625  hullflag = (pe == dummypoint) ? 3 : 0;
8626  }
8627 
8628  reducflag = 0;
8629  rejflag = 0;
8630 
8631 
8632  if (hullflag == 0) {
8633  // Make sure that no inverted tet will be created, i.e. the new tets
8634  // [d,c,e,a] and [c,d,e,b] must be valid tets.
8635  ori = orient3d(pd, pc, pe, pa);
8636  if (ori < 0) {
8637  ori = orient3d(pc, pd, pe, pb);
8638  if (ori < 0) {
8639  reducflag = 1;
8640  }
8641  }
8642  } else {
8643  // [a,b] is a hull edge.
8644  // Note: This can happen when it is in the middle of a 4-to-4 flip.
8645  // Note: [a,b] may even be a non-convex hull edge.
8646  if (!nonconvex) {
8647  // The mesh is convex, only do flip if it is a coplanar hull edge.
8648  ori = orient3d(pa, pb, pc, pd);
8649  if (ori == 0) {
8650  reducflag = 1;
8651  }
8652  } else { // nonconvex
8653  reducflag = 1;
8654  }
8655  if (reducflag == 1) {
8656  // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
8657  // Make sure that no inverted tet will be created.
8658  point searchpt = NULL, chkpt;
8659  REAL bigvol = 0.0, ori1, ori2;
8660  // Search an interior vertex which is an apex of edge [c,d].
8661  // In principle, it can be arbitrary interior vertex. To avoid
8662  // numerical issue, we choose the vertex which belongs to a tet
8663  // 't' at edge [c,d] and 't' has the biggest volume.
8664  fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
8665  eorgoppoself(fliptets[0]); // [d,c,b,a]
8666  spintet = fliptets[0];
8667  while (1) {
8668  fnextself(spintet);
8669  chkpt = oppo(spintet);
8670  if (chkpt == pb) break;
8671  if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
8672  ori = -orient3d(pd, pc, apex(spintet), chkpt);
8673  assert(ori > 0);
8674  if (ori > bigvol) {
8675  bigvol = ori;
8676  searchpt = chkpt;
8677  }
8678  }
8679  }
8680  if (searchpt != NULL) {
8681  // Now valid the configuration.
8682  ori1 = orient3d(pd, pc, searchpt, pa);
8683  ori2 = orient3d(pd, pc, searchpt, pb);
8684  if (ori1 * ori2 >= 0.0) {
8685  reducflag = 0; // Not valid.
8686  } else {
8687  ori1 = orient3d(pa, pb, searchpt, pc);
8688  ori2 = orient3d(pa, pb, searchpt, pd);
8689  if (ori1 * ori2 >= 0.0) {
8690  reducflag = 0; // Not valid.
8691  }
8692  }
8693  } else {
8694  // No valid searchpt is found.
8695  reducflag = 0; // Do not flip it.
8696  }
8697  } // if (reducflag == 1)
8698  } // if (hullflag == 1)
8699 
8700  if (reducflag) {
8701  // A 3-to-2 flip is possible.
8702  if (checksubfaceflag) {
8703  // This edge (must not be a segment) can be flipped ONLY IF it belongs
8704  // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in
8705  // the surface mesh will be automatically performed within the
8706  // 3-to-2 flip.
8707  nn = 0;
8708  edgepivot = -1; // Re-use it.
8709  for (j = 0; j < 3; j++) {
8710  if (issubface(abtets[j])) {
8711  nn++; // Found a subface.
8712  } else {
8713  edgepivot = j;
8714  }
8715  }
8716  assert(nn < 3);
8717  if (nn == 1) {
8718  // Found only 1 subface containing this edge. This can happen in
8719  // the boundary recovery phase. The neighbor subface is not yet
8720  // recovered. This edge should not be flipped at this moment.
8721  rejflag = 1;
8722  } else if (nn == 2) {
8723  // Found two subfaces. A 2-to-2 flip is possible. Validate it.
8724  // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
8725  eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
8726  if (issubface(spintet)) {
8727  rejflag = 1; // Conflict to a 2-to-2 flip.
8728  } else {
8729  esymself(spintet);
8730  if (issubface(spintet)) {
8731  rejflag = 1; // Conflict to a 2-to-2 flip.
8732  }
8733  }
8734  }
8735  }
8736  if (!rejflag && fc->checkflipeligibility) {
8737  // Here we must exchange 'a' and 'b'. Since in the check... function,
8738  // we assume the following point sequence, 'a,b,c,d,e', where
8739  // the face [a,b,c] will be flipped and the edge [e,d] will be
8740  // created. The two new tets are [a,b,c,d] and [b,a,c,e].
8741  rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
8742  abedgepivot, fc);
8743  }
8744  if (!rejflag) {
8745  // Do flip: [a,b] => [c,d,e]
8746  flip32(abtets, hullflag, fc);
8747  if (fc->remove_ndelaunay_edge) {
8748  if (level == 0) {
8749  // It is the desired removing edge. Check if we have improved
8750  // the objective function.
8751  if ((fc->tetprism_vol_sum >= 0.0) ||
8752  (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
8753  // No improvement! flip back: [c,d,e] => [a,b].
8754  flip23(abtets, hullflag, fc);
8755  // Increase the element counter -- They are in cavity.
8756  for (j = 0; j < 3; j++) {
8757  increaseelemcounter(abtets[j]);
8758  }
8759  return 3;
8760  }
8761  } // if (level == 0)
8762  }
8763  if (fc->collectnewtets) {
8764  // Collect new tets.
8765  if (level == 0) {
8766  // Push the two new tets into stack.
8767  for (j = 0; j < 2; j++) {
8768  cavetetlist->newindex((void **) &parytet);
8769  *parytet = abtets[j];
8770  }
8771  } else {
8772  // Only one of the new tets is collected. The other one is inside
8773  // the reduced edge star. 'abedgepivot' is either '1' or '2'.
8774  cavetetlist->newindex((void **) &parytet);
8775  if (abedgepivot == 1) { // [c,b]
8776  *parytet = abtets[1];
8777  } else {
8778  assert(abedgepivot == 2); // [a,c]
8779  *parytet = abtets[0];
8780  }
8781  }
8782  } // if (fc->collectnewtets)
8783  return 2;
8784  }
8785  } // if (reducflag)
8786  } // if (n == 3)
8787 
8788  // The current (reduced) Star size.
8789  return n;
8790 }
8791 
8793 // //
8794 // flipnm_post() Post process a n-to-m flip. //
8795 // //
8796 // IMPORTANT: This routine only works when there is no other flip operation //
8797 // is done after flipnm([a,b]) which attempts to remove an edge [a,b]. //
8798 // //
8799 // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
8800 // [a,b] before flipnm([a,b]). 'nn' (< n) is the value returned by flipnm. //
8801 // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
8802 // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
8803 // b] and its initial Star([a,b]). If 'nn >= 3' edge [a,b] still exists in //
8804 // current mesh and 'nn' is the current number of tets in Star([a,b]). //
8805 // //
8806 // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a //
8807 // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet //
8808 // 'abtets[t-1]', where '0 <= t <= i'. These information can be used to //
8809 // undo the flips performed in flipnm([a,b]) or to collect new tets created //
8810 // by the flipnm([a,b]) operation. //
8811 // //
8812 // Default, this routine only walks through the flips and frees the spaces //
8813 // allocated during the flipnm([a,b]) operation. //
8814 // //
8815 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8816 // in flipnm([a,b]) so that the mesh is returned to its original state //
8817 // before doing the flipnm([a,b]) operation. //
8818 // //
8819 // //
8821 
8822 int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
8823  flipconstraints* fc)
8824 {
8825  triface fliptets[3], flipface;
8826  triface *tmpabtets;
8827  int fliptype;
8828  int edgepivot;
8829  int t, n1;
8830  int i, j;
8831 
8832 
8833  if (nn == 2) {
8834  // The edge [a,b] has been flipped.
8835  // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
8836  // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
8837  if (fc->unflip) {
8838  // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
8839  flip23(abtets, 1, fc);
8840  if (fc->collectnewtets) {
8841  // Pop up new (flipped) tets from the stack.
8842  if (abedgepivot == 0) {
8843  // Two new tets were collected.
8844  cavetetlist->objects -= 2;
8845  } else {
8846  // Only one of the two new tets was collected.
8847  cavetetlist->objects -= 1;
8848  }
8849  }
8850  }
8851  // The initial size of Star(ab) is 3.
8852  nn++;
8853  }
8854 
8855  // Walk through the performed flips.
8856  for (i = nn; i < n; i++) {
8857  // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
8858  // At the end of this step, the size of the Star([a,b]) is 'i+1'.
8859  // The sizes of the Link([a,b]) are the same.
8860  fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
8861  if (fliptype == 1) {
8862  // It was a 2-to-3 flip: [a,b,c]->[e,d].
8863  t = (abtets[i].ver >> 6);
8864  assert(t <= i);
8865  if (fc->unflip) {
8866  if (b->verbose > 2) {
8867  printf(" Recover a 2-to-3 flip at f[%d].\n", t);
8868  }
8869  // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
8870  // it is created by a 2-to-3 flip [a,b,c] => [e,d].
8871  fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
8872  eprevself(fliptets[0]);
8873  esymself(fliptets[0]);
8874  enextself(fliptets[0]); // [e,d,a,b]
8875  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
8876  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
8877  // Do a 3-to-2 flip: [e,d] => [a,b,c].
8878  // NOTE: hull tets may be invloved.
8879  flip32(fliptets, 1, fc);
8880  // Expand the array 'abtets', maintain the original order.
8881  // The new array length is (i+1).
8882  for (j = i - 1; j >= t; j--) {
8883  abtets[j + 1] = abtets[j]; // Downshift
8884  }
8885  // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
8886  // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
8887  // the (t-1)-th and t-th entries, respectively.
8888  esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
8889  abtets[t] = fliptets[0]; // [a,b,c,d]
8890  if (fc->collectnewtets) {
8891  // Pop up two (flipped) tets from the stack.
8892  cavetetlist->objects -= 2;
8893  }
8894  }
8895  } else if (fliptype == 2) {
8896  tmpabtets = (triface *) (abtets[i].tet);
8897  n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
8898  edgepivot = (abtets[i].ver & 3);
8899  t = ((abtets[i].ver >> 6) & 8191);
8900  assert(t <= i);
8901  if (fc->unflip) {
8902  if (b->verbose > 2) {
8903  printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
8904  edgepivot, t);
8905  }
8906  // Recover the flipped edge ([c,b] or [a,c]).
8907  // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
8908  // the flipping of edge [c,b] or [a,c]. It must still exist in
8909  // Star(ab). Use it to recover the flipped edge.
8910  if (edgepivot == 1) {
8911  // The flip edge is [c,b].
8912  tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
8913  eprevself(tmpabtets[0]);
8914  esymself(tmpabtets[0]);
8915  eprevself(tmpabtets[0]); // [d,a,e,b]
8916  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
8917  } else {
8918  // The flip edge is [a,c].
8919  tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
8920  enextself(tmpabtets[1]);
8921  esymself(tmpabtets[1]);
8922  enextself(tmpabtets[1]); // [b,d,e,a]
8923  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
8924  } // if (edgepivot == 2)
8925 
8926  // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
8927  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8928 
8929  // Insert the two recovered tets into the original Star(ab).
8930  for (j = i - 1; j >= t; j--) {
8931  abtets[j + 1] = abtets[j]; // Downshift
8932  }
8933  if (edgepivot == 1) {
8934  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
8935  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
8936  // tmpabtets[2] is [c,b,e,d]
8937  fliptets[0] = tmpabtets[1];
8938  enextself(fliptets[0]);
8939  esymself(fliptets[0]); // [a,b,e,c]
8940  fliptets[1] = tmpabtets[0];
8941  esymself(fliptets[1]);
8942  eprevself(fliptets[1]); // [a,b,c,d]
8943  } else {
8944  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
8945  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
8946  // tmpabtets[2] is [a,c,e,d]
8947  fliptets[0] = tmpabtets[1];
8948  eprevself(fliptets[0]);
8949  esymself(fliptets[0]); // [a,b,e,c]
8950  fliptets[1] = tmpabtets[0];
8951  esymself(fliptets[1]);
8952  enextself(fliptets[1]); // [a,b,c,d]
8953  } // edgepivot == 2
8954  // Insert the two recovered tets into Star(ab).
8955  abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
8956  abtets[t] = fliptets[1];
8957  }
8958  else {
8959  // Only free the spaces.
8960  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8961  } // if (!unflip)
8962  if (b->verbose > 2) {
8963  printf(" Release %d spaces at f[%d].\n", n1, i);
8964  }
8965  delete [] tmpabtets;
8966  }
8967  } // i
8968 
8969  return 1;
8970 }
8971 
8973 // //
8974 // insertpoint() Insert a point into current tetrahedralization. //
8975 // //
8976 // The Bowyer-Watson (B-W) algorithm is used to add a new point p into the //
8977 // tetrahedralization T. It first finds a "cavity", denoted as C, in T, C //
8978 // consists of tetrahedra in T that "conflict" with p. If T is a Delaunay //
8979 // tetrahedralization, then all boundary faces (triangles) of C are visible //
8980 // by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
8981 // tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
8982 // C and p. If T is not a DT, then C may be not star-shaped. It must be //
8983 // modified so that it becomes star-shaped. //
8984 // //
8986 
8987 int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
8988  face *splitseg, insertvertexflags *ivf)
8989 {
8990  arraypool *swaplist;
8991  triface *cavetet, spintet, neightet, neineitet, *parytet;
8992  triface oldtet, newtet, newneitet;
8993  face checksh, neighsh, *parysh;
8994  face checkseg, *paryseg;
8995  point *pts, pa, pb, pc, *parypt;
8996  enum locateresult loc = OUTSIDE;
8997  REAL sign, ori;
8998  REAL attrib, volume;
8999  bool enqflag;
9000  int t1ver;
9001  int i, j, k, s;
9002 
9003  if (b->verbose > 2) {
9004  printf(" Insert point %d\n", pointmark(insertpt));
9005  }
9006 
9007  // Locate the point.
9008  if (searchtet->tet != NULL) {
9009  loc = (enum locateresult) ivf->iloc;
9010  }
9011 
9012  if (loc == OUTSIDE) {
9013  if (searchtet->tet == NULL) {
9014  if (!b->weighted) {
9015  randomsample(insertpt, searchtet);
9016  } else {
9017  // Weighted DT. There may exist dangling vertex.
9018  *searchtet = recenttet;
9019  }
9020  }
9021  // Locate the point.
9022  loc = locate(insertpt, searchtet);
9023  }
9024 
9025  ivf->iloc = (int) loc; // The return value.
9026 
9027  if (b->weighted) {
9028  if (loc != OUTSIDE) {
9029  // Check if this vertex is regular.
9030  pts = (point *) searchtet->tet;
9031  assert(pts[7] != dummypoint);
9032  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9033  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9034  insertpt[3]);
9035  if (sign > 0) {
9036  // This new vertex does not lie below the lower hull. Skip it.
9037  setpointtype(insertpt, NREGULARVERTEX);
9038  nonregularcount++;
9039  ivf->iloc = (int) NONREGULAR;
9040  return 0;
9041  }
9042  }
9043  }
9044 
9045  // Create the initial cavity C(p) which contains all tetrahedra that
9046  // intersect p. It may include 1, 2, or n tetrahedra.
9047  // If p lies on a segment or subface, also create the initial sub-cavity
9048  // sC(p) which contains all subfaces (and segment) which intersect p.
9049 
9050  if (loc == OUTSIDE) {
9051  flip14count++;
9052  // The current hull will be enlarged.
9053  // Add four adjacent boundary tets into list.
9054  for (i = 0; i < 4; i++) {
9055  decode(searchtet->tet[i], neightet);
9056  neightet.ver = epivot[neightet.ver];
9057  cavebdrylist->newindex((void **) &parytet);
9058  *parytet = neightet;
9059  }
9060  infect(*searchtet);
9061  caveoldtetlist->newindex((void **) &parytet);
9062  *parytet = *searchtet;
9063  } else if (loc == INTETRAHEDRON) {
9064  flip14count++;
9065  // Add four adjacent boundary tets into list.
9066  for (i = 0; i < 4; i++) {
9067  decode(searchtet->tet[i], neightet);
9068  neightet.ver = epivot[neightet.ver];
9069  cavebdrylist->newindex((void **) &parytet);
9070  *parytet = neightet;
9071  }
9072  infect(*searchtet);
9073  caveoldtetlist->newindex((void **) &parytet);
9074  *parytet = *searchtet;
9075  } else if (loc == ONFACE) {
9076  flip26count++;
9077  // Add six adjacent boundary tets into list.
9078  j = (searchtet->ver & 3); // The current face number.
9079  for (i = 1; i < 4; i++) {
9080  decode(searchtet->tet[(j + i) % 4], neightet);
9081  neightet.ver = epivot[neightet.ver];
9082  cavebdrylist->newindex((void **) &parytet);
9083  *parytet = neightet;
9084  }
9085  decode(searchtet->tet[j], spintet);
9086  j = (spintet.ver & 3); // The current face number.
9087  for (i = 1; i < 4; i++) {
9088  decode(spintet.tet[(j + i) % 4], neightet);
9089  neightet.ver = epivot[neightet.ver];
9090  cavebdrylist->newindex((void **) &parytet);
9091  *parytet = neightet;
9092  }
9093  infect(spintet);
9094  caveoldtetlist->newindex((void **) &parytet);
9095  *parytet = spintet;
9096  infect(*searchtet);
9097  caveoldtetlist->newindex((void **) &parytet);
9098  *parytet = *searchtet;
9099 
9100  if (ivf->splitbdflag) {
9101  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9102  // Create the initial sub-cavity sC(p).
9103  smarktest(*splitsh);
9104  caveshlist->newindex((void **) &parysh);
9105  *parysh = *splitsh;
9106  }
9107  } // if (splitbdflag)
9108  } else if (loc == ONEDGE) {
9109  flipn2ncount++;
9110  // Add all adjacent boundary tets into list.
9111  spintet = *searchtet;
9112  while (1) {
9113  eorgoppo(spintet, neightet);
9114  decode(neightet.tet[neightet.ver & 3], neightet);
9115  neightet.ver = epivot[neightet.ver];
9116  cavebdrylist->newindex((void **) &parytet);
9117  *parytet = neightet;
9118  edestoppo(spintet, neightet);
9119  decode(neightet.tet[neightet.ver & 3], neightet);
9120  neightet.ver = epivot[neightet.ver];
9121  cavebdrylist->newindex((void **) &parytet);
9122  *parytet = neightet;
9123  infect(spintet);
9124  caveoldtetlist->newindex((void **) &parytet);
9125  *parytet = spintet;
9126  fnextself(spintet);
9127  if (spintet.tet == searchtet->tet) break;
9128  } // while (1)
9129 
9130  if (ivf->splitbdflag) {
9131  // Create the initial sub-cavity sC(p).
9132  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9133  smarktest(*splitseg);
9134  splitseg->shver = 0;
9135  spivot(*splitseg, *splitsh);
9136  }
9137  if (splitsh != NULL) {
9138  if (splitsh->sh != NULL) {
9139  // Collect all subfaces share at this edge.
9140  pa = sorg(*splitsh);
9141  neighsh = *splitsh;
9142  while (1) {
9143  // Adjust the origin of its edge to be 'pa'.
9144  if (sorg(neighsh) != pa) {
9145  sesymself(neighsh);
9146  }
9147  // Add this face into list (in B-W cavity).
9148  smarktest(neighsh);
9149  caveshlist->newindex((void **) &parysh);
9150  *parysh = neighsh;
9151  // Add this face into face-at-splitedge list.
9152  cavesegshlist->newindex((void **) &parysh);
9153  *parysh = neighsh;
9154  // Go to the next face at the edge.
9155  spivotself(neighsh);
9156  // Stop if all faces at the edge have been visited.
9157  if (neighsh.sh == splitsh->sh) break;
9158  if (neighsh.sh == NULL) break;
9159  } // while (1)
9160  } // if (not a dangling segment)
9161  }
9162  } // if (splitbdflag)
9163  } else if (loc == INSTAR) {
9164  // We assume that all tets in the star are given in 'caveoldtetlist',
9165  // and they are all infected.
9166  assert(caveoldtetlist->objects > 0);
9167  // Collect the boundary faces of the star.
9168  for (i = 0; i < caveoldtetlist->objects; i++) {
9169  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9170  // Check its 4 neighbor tets.
9171  for (j = 0; j < 4; j++) {
9172  decode(cavetet->tet[j], neightet);
9173  if (!infected(neightet)) {
9174  // It's a boundary face.
9175  neightet.ver = epivot[neightet.ver];
9176  cavebdrylist->newindex((void **) &parytet);
9177  *parytet = neightet;
9178  }
9179  }
9180  }
9181  } else if (loc == ONVERTEX) {
9182  // The point already exist. Do nothing and return.
9183  return 0;
9184  }
9185 
9186 
9187  if (ivf->assignmeshsize) {
9188  // Assign mesh size for the new point.
9189  if (bgm != NULL) {
9190  // Interpolate the mesh size from the background mesh.
9191  bgm->decode(point2bgmtet(org(*searchtet)), neightet);
9192  int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
9193  if (bgmloc != (int) OUTSIDE) {
9194  insertpt[pointmtrindex] =
9195  bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
9196  setpoint2bgmtet(insertpt, bgm->encode(neightet));
9197  }
9198  } else {
9199  insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
9200  }
9201  } // if (assignmeshsize)
9202 
9203  if (ivf->bowywat) {
9204  // Update the cavity C(p) using the Bowyer-Watson algorithm.
9205  swaplist = cavetetlist;
9207  cavebdrylist = swaplist;
9208  for (i = 0; i < cavetetlist->objects; i++) {
9209  // 'cavetet' is an adjacent tet at outside of the cavity.
9210  cavetet = (triface *) fastlookup(cavetetlist, i);
9211  // The tet may be tested and included in the (enlarged) cavity.
9212  if (!infected(*cavetet)) {
9213  // Check for two possible cases for this tet:
9214  // (1) It is a cavity tet, or
9215  // (2) it is a cavity boundary face.
9216  enqflag = false;
9217  if (!marktested(*cavetet)) {
9218  // Do Delaunay (in-sphere) test.
9219  pts = (point *) cavetet->tet;
9220  if (pts[7] != dummypoint) {
9221  // A volume tet. Operate on it.
9222  if (b->weighted) {
9223  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9224  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9225  insertpt[3]);
9226  } else {
9227  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
9228  }
9229  enqflag = (sign < 0.0);
9230  } else {
9231  if (!nonconvex) {
9232  // Test if this hull face is visible by the new point.
9233  ori = orient3d(pts[4], pts[5], pts[6], insertpt);
9234  if (ori < 0) {
9235  // A visible hull face.
9236  //if (!nonconvex) {
9237  // Include it in the cavity. The convex hull will be enlarged.
9238  enqflag = true; // (ori < 0.0);
9239  //}
9240  } else if (ori == 0.0) {
9241  // A coplanar hull face. We need to test if this hull face is
9242  // Delaunay or not. We test if the adjacent tet (not faked)
9243  // of this hull face is Delaunay or not.
9244  decode(cavetet->tet[3], neineitet);
9245  if (!infected(neineitet)) {
9246  if (!marktested(neineitet)) {
9247  // Do Delaunay test on this tet.
9248  pts = (point *) neineitet.tet;
9249  assert(pts[7] != dummypoint);
9250  if (b->weighted) {
9251  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9252  pts[4][3], pts[5][3], pts[6][3],
9253  pts[7][3], insertpt[3]);
9254  } else {
9255  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9256  }
9257  enqflag = (sign < 0.0);
9258  }
9259  } else {
9260  // The adjacent tet is non-Delaunay. The hull face is non-
9261  // Delaunay as well. Include it in the cavity.
9262  enqflag = true;
9263  } // if (!infected(neineitet))
9264  } // if (ori == 0.0)
9265  } else {
9266  // A hull face (must be a subface).
9267  // We FIRST include it in the initial cavity if the adjacent tet
9268  // (not faked) of this hull face is not Delaunay wrt p.
9269  // Whether it belongs to the final cavity will be determined
9270  // during the validation process. 'validflag'.
9271  decode(cavetet->tet[3], neineitet);
9272  if (!infected(neineitet)) {
9273  if (!marktested(neineitet)) {
9274  // Do Delaunay test on this tet.
9275  pts = (point *) neineitet.tet;
9276  assert(pts[7] != dummypoint);
9277  if (b->weighted) {
9278  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9279  pts[4][3], pts[5][3], pts[6][3],
9280  pts[7][3], insertpt[3]);
9281  } else {
9282  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9283  }
9284  enqflag = (sign < 0.0);
9285  }
9286  } else {
9287  // The adjacent tet is non-Delaunay. The hull face is non-
9288  // Delaunay as well. Include it in the cavity.
9289  enqflag = true;
9290  } // if (infected(neineitet))
9291  } // if (nonconvex)
9292  } // if (pts[7] != dummypoint)
9293  marktest(*cavetet); // Only test it once.
9294  } // if (!marktested(*cavetet))
9295 
9296  if (enqflag) {
9297  // Found a tet in the cavity. Put other three faces in check list.
9298  k = (cavetet->ver & 3); // The current face number
9299  for (j = 1; j < 4; j++) {
9300  decode(cavetet->tet[(j + k) % 4], neightet);
9301  cavetetlist->newindex((void **) &parytet);
9302  *parytet = neightet;
9303  }
9304  infect(*cavetet);
9305  caveoldtetlist->newindex((void **) &parytet);
9306  *parytet = *cavetet;
9307  } else {
9308  // Found a boundary face of the cavity.
9309  cavetet->ver = epivot[cavetet->ver];
9310  cavebdrylist->newindex((void **) &parytet);
9311  *parytet = *cavetet;
9312  }
9313  } // if (!infected(*cavetet))
9314  } // i
9315 
9316  cavetetlist->restart(); // Clear the working list.
9317  } // if (ivf->bowywat)
9318 
9319  if (checksubsegflag) {
9320  // Collect all segments of C(p).
9321  shellface *ssptr;
9322  for (i = 0; i < caveoldtetlist->objects; i++) {
9323  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9324  if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
9325  for (j = 0; j < 6; j++) {
9326  if (ssptr[j]) {
9327  sdecode(ssptr[j], checkseg);
9328  if (!sinfected(checkseg)) {
9329  sinfect(checkseg);
9330  cavetetseglist->newindex((void **) &paryseg);
9331  *paryseg = checkseg;
9332  }
9333  }
9334  } // j
9335  }
9336  } // i
9337  // Uninfect collected segments.
9338  for (i = 0; i < cavetetseglist->objects; i++) {
9339  paryseg = (face *) fastlookup(cavetetseglist, i);
9340  suninfect(*paryseg);
9341  }
9342 
9343  if (ivf->rejflag & 1) {
9344  // Reject this point if it encroaches upon any segment.
9345  face *paryseg1;
9346  for (i = 0; i < cavetetseglist->objects; i++) {
9347  paryseg1 = (face *) fastlookup(cavetetseglist, i);
9348  if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4],
9349  insertpt)) {
9350  encseglist->newindex((void **) &paryseg);
9351  *paryseg = *paryseg1;
9352  }
9353  } // i
9354  if (encseglist->objects > 0) {
9355  insertpoint_abort(splitseg, ivf);
9356  ivf->iloc = (int) ENCSEGMENT;
9357  return 0;
9358  }
9359  }
9360  } // if (checksubsegflag)
9361 
9362  if (checksubfaceflag) {
9363  // Collect all subfaces of C(p).
9364  shellface *sptr;
9365  for (i = 0; i < caveoldtetlist->objects; i++) {
9366  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9367  if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
9368  for (j = 0; j < 4; j++) {
9369  if (sptr[j]) {
9370  sdecode(sptr[j], checksh);
9371  if (!sinfected(checksh)) {
9372  sinfect(checksh);
9373  cavetetshlist->newindex((void **) &parysh);
9374  *parysh = checksh;
9375  }
9376  }
9377  } // j
9378  }
9379  } // i
9380  // Uninfect collected subfaces.
9381  for (i = 0; i < cavetetshlist->objects; i++) {
9382  parysh = (face *) fastlookup(cavetetshlist, i);
9383  suninfect(*parysh);
9384  }
9385 
9386  if (ivf->rejflag & 2) {
9387  REAL rd, cent[3];
9388  badface *bface;
9389  // Reject this point if it encroaches upon any subface.
9390  for (i = 0; i < cavetetshlist->objects; i++) {
9391  parysh = (face *) fastlookup(cavetetshlist, i);
9392  if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4],
9393  (point) parysh->sh[5], insertpt, cent, &rd)) {
9394  encshlist->newindex((void **) &bface);
9395  bface->ss = *parysh;
9396  bface->forg = (point) parysh->sh[3]; // Not a dad one.
9397  for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
9398  bface->key = rd;
9399  }
9400  }
9401  if (encshlist->objects > 0) {
9402  insertpoint_abort(splitseg, ivf);
9403  ivf->iloc = (int) ENCSUBFACE;
9404  return 0;
9405  }
9406  }
9407  } // if (checksubfaceflag)
9408 
9409  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
9410  // The vertex lies outside of the domain. And it does not encroach
9411  // upon any boundary segment or subface. Do not insert it.
9412  insertpoint_abort(splitseg, ivf);
9413  return 0;
9414  }
9415 
9416  if (ivf->splitbdflag) {
9417  // The new point locates in surface mesh. Update the sC(p).
9418  // We have already 'smarktested' the subfaces which directly intersect
9419  // with p in 'caveshlist'. From them, we 'smarktest' their neighboring
9420  // subfaces which are included in C(p). Do not across a segment.
9421  for (i = 0; i < caveshlist->objects; i++) {
9422  parysh = (face *) fastlookup(caveshlist, i);
9423  assert(smarktested(*parysh));
9424  checksh = *parysh;
9425  for (j = 0; j < 3; j++) {
9426  if (!isshsubseg(checksh)) {
9427  spivot(checksh, neighsh);
9428  assert(neighsh.sh != NULL);
9429  if (!smarktested(neighsh)) {
9430  stpivot(neighsh, neightet);
9431  if (infected(neightet)) {
9432  fsymself(neightet);
9433  if (infected(neightet)) {
9434  // This subface is inside C(p).
9435  // Check if its diametrical circumsphere encloses 'p'.
9436  // The purpose of this check is to avoid forming invalid
9437  // subcavity in surface mesh.
9438  sign = incircle3d(sorg(neighsh), sdest(neighsh),
9439  sapex(neighsh), insertpt);
9440  if (sign < 0) {
9441  smarktest(neighsh);
9442  caveshlist->newindex((void **) &parysh);
9443  *parysh = neighsh;
9444  }
9445  }
9446  }
9447  }
9448  }
9449  senextself(checksh);
9450  } // j
9451  } // i
9452  } // if (ivf->splitbdflag)
9453 
9454  if (ivf->validflag) {
9455  // Validate C(p) and update it if it is not star-shaped.
9456  int cutcount = 0;
9457 
9458  if (ivf->respectbdflag) {
9459  // The initial cavity may include subfaces which are not on the facets
9460  // being splitting. Find them and make them as boundary of C(p).
9461  // Comment: We have already 'smarktested' the subfaces in sC(p). They
9462  // are completely inside C(p).
9463  for (i = 0; i < cavetetshlist->objects; i++) {
9464  parysh = (face *) fastlookup(cavetetshlist, i);
9465  stpivot(*parysh, neightet);
9466  if (infected(neightet)) {
9467  fsymself(neightet);
9468  if (infected(neightet)) {
9469  // Found a subface inside C(p).
9470  if (!smarktested(*parysh)) {
9471  // It is possible that this face is a boundary subface.
9472  // Check if it is a hull face.
9473  //assert(apex(neightet) != dummypoint);
9474  if (oppo(neightet) != dummypoint) {
9475  fsymself(neightet);
9476  }
9477  if (oppo(neightet) != dummypoint) {
9478  ori = orient3d(org(neightet), dest(neightet), apex(neightet),
9479  insertpt);
9480  if (ori < 0) {
9481  // A visible face, get its neighbor face.
9482  fsymself(neightet);
9483  ori = -ori; // It must be invisible by p.
9484  }
9485  } else {
9486  // A hull tet. It needs to be cut.
9487  ori = 1;
9488  }
9489  // Cut this tet if it is either invisible by or coplanar with p.
9490  if (ori >= 0) {
9491  uninfect(neightet);
9492  unmarktest(neightet);
9493  cutcount++;
9494  neightet.ver = epivot[neightet.ver];
9495  cavebdrylist->newindex((void **) &parytet);
9496  *parytet = neightet;
9497  // Add three new faces to find new boundaries.
9498  for (j = 0; j < 3; j++) {
9499  esym(neightet, neineitet);
9500  neineitet.ver = epivot[neineitet.ver];
9501  cavebdrylist->newindex((void **) &parytet);
9502  *parytet = neineitet;
9503  enextself(neightet);
9504  }
9505  } // if (ori >= 0)
9506  }
9507  }
9508  }
9509  } // i
9510 
9511  // The initial cavity may include segments in its interior. We need to
9512  // Update the cavity so that these segments are on the boundary of
9513  // the cavity.
9514  for (i = 0; i < cavetetseglist->objects; i++) {
9515  paryseg = (face *) fastlookup(cavetetseglist, i);
9516  // Check this segment if it is not a splitting segment.
9517  if (!smarktested(*paryseg)) {
9518  sstpivot1(*paryseg, neightet);
9519  spintet = neightet;
9520  while (1) {
9521  if (!infected(spintet)) break;
9522  fnextself(spintet);
9523  if (spintet.tet == neightet.tet) break;
9524  }
9525  if (infected(spintet)) {
9526  // Find an adjacent tet at this segment such that both faces
9527  // at this segment are not visible by p.
9528  pa = org(neightet);
9529  pb = dest(neightet);
9530  spintet = neightet;
9531  j = 0;
9532  while (1) {
9533  // Check if this face is visible by p.
9534  pc = apex(spintet);
9535  if (pc != dummypoint) {
9536  ori = orient3d(pa, pb, pc, insertpt);
9537  if (ori >= 0) {
9538  // Not visible. Check another face in this tet.
9539  esym(spintet, neineitet);
9540  pc = apex(neineitet);
9541  if (pc != dummypoint) {
9542  ori = orient3d(pb, pa, pc, insertpt);
9543  if (ori >= 0) {
9544  // Not visible. Found this face.
9545  j = 1; // Flag that it is found.
9546  break;
9547  }
9548  }
9549  }
9550  }
9551  fnextself(spintet);
9552  if (spintet.tet == neightet.tet) break;
9553  }
9554  if (j == 0) {
9555  // Not found such a face.
9556  assert(0); // debug this case.
9557  }
9558  neightet = spintet;
9559  if (b->verbose > 3) {
9560  printf(" Cut tet (%d, %d, %d, %d)\n",
9561  pointmark(org(neightet)), pointmark(dest(neightet)),
9562  pointmark(apex(neightet)), pointmark(oppo(neightet)));
9563  }
9564  uninfect(neightet);
9565  unmarktest(neightet);
9566  cutcount++;
9567  neightet.ver = epivot[neightet.ver];
9568  cavebdrylist->newindex((void **) &parytet);
9569  *parytet = neightet;
9570  // Add three new faces to find new boundaries.
9571  for (j = 0; j < 3; j++) {
9572  esym(neightet, neineitet);
9573  neineitet.ver = epivot[neineitet.ver];
9574  cavebdrylist->newindex((void **) &parytet);
9575  *parytet = neineitet;
9576  enextself(neightet);
9577  }
9578  }
9579  }
9580  } // i
9581  } // if (ivf->respectbdflag)
9582 
9583  // Update the cavity by removing invisible faces until it is star-shaped.
9584  for (i = 0; i < cavebdrylist->objects; i++) {
9585  cavetet = (triface *) fastlookup(cavebdrylist, i);
9586  // 'cavetet' is an exterior tet adjacent to the cavity.
9587  // Check if its neighbor is inside C(p).
9588  fsym(*cavetet, neightet);
9589  if (infected(neightet)) {
9590  if (apex(*cavetet) != dummypoint) {
9591  // It is a cavity boundary face. Check its visibility.
9592  if (oppo(neightet) != dummypoint) {
9593  ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
9594  insertpt);
9595  enqflag = (ori > 0);
9596  // Comment: if ori == 0 (coplanar case), we also cut the tet.
9597  } else {
9598  // It is a hull face. And its adjacent tet (at inside of the
9599  // domain) has been cut from the cavity. Cut it as well.
9600  //assert(nonconvex);
9601  enqflag = false;
9602  }
9603  } else {
9604  enqflag = true; // A hull edge.
9605  }
9606  if (enqflag) {
9607  // This face is valid, save it.
9608  cavetetlist->newindex((void **) &parytet);
9609  *parytet = *cavetet;
9610  } else {
9611  uninfect(neightet);
9612  unmarktest(neightet);
9613  cutcount++;
9614  // Add three new faces to find new boundaries.
9615  for (j = 0; j < 3; j++) {
9616  esym(neightet, neineitet);
9617  neineitet.ver = epivot[neineitet.ver];
9618  cavebdrylist->newindex((void **) &parytet);
9619  *parytet = neineitet;
9620  enextself(neightet);
9621  }
9622  // 'cavetet' is not on the cavity boundary anymore.
9623  unmarktest(*cavetet);
9624  }
9625  } else {
9626  // 'cavetet' is not on the cavity boundary anymore.
9627  unmarktest(*cavetet);
9628  }
9629  } // i
9630 
9631  if (cutcount > 0) {
9632  // The cavity has been updated.
9633  // Update the cavity boundary faces.
9634  cavebdrylist->restart();
9635  for (i = 0; i < cavetetlist->objects; i++) {
9636  cavetet = (triface *) fastlookup(cavetetlist, i);
9637  // 'cavetet' was an exterior tet adjacent to the cavity.
9638  fsym(*cavetet, neightet);
9639  if (infected(neightet)) {
9640  // It is a cavity boundary face.
9641  cavebdrylist->newindex((void **) &parytet);
9642  *parytet = *cavetet;
9643  } else {
9644  // Not a cavity boundary face.
9645  unmarktest(*cavetet);
9646  }
9647  }
9648 
9649  // Update the list of old tets.
9650  cavetetlist->restart();
9651  for (i = 0; i < caveoldtetlist->objects; i++) {
9652  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9653  if (infected(*cavetet)) {
9654  cavetetlist->newindex((void **) &parytet);
9655  *parytet = *cavetet;
9656  }
9657  }
9658  // Swap 'cavetetlist' and 'caveoldtetlist'.
9659  swaplist = caveoldtetlist;
9661  cavetetlist = swaplist;
9662 
9663  // The cavity should contain at least one tet.
9664  if (caveoldtetlist->objects == 0l) {
9665  insertpoint_abort(splitseg, ivf);
9666  ivf->iloc = (int) BADELEMENT;
9667  return 0;
9668  }
9669 
9670  if (ivf->splitbdflag) {
9671  int cutshcount = 0;
9672  // Update the sub-cavity sC(p).
9673  for (i = 0; i < caveshlist->objects; i++) {
9674  parysh = (face *) fastlookup(caveshlist, i);
9675  if (smarktested(*parysh)) {
9676  enqflag = false;
9677  stpivot(*parysh, neightet);
9678  if (infected(neightet)) {
9679  fsymself(neightet);
9680  if (infected(neightet)) {
9681  enqflag = true;
9682  }
9683  }
9684  if (!enqflag) {
9685  sunmarktest(*parysh);
9686  // Use the last entry of this array to fill this entry.
9687  j = caveshlist->objects - 1;
9688  checksh = * (face *) fastlookup(caveshlist, j);
9689  *parysh = checksh;
9690  cutshcount++;
9691  caveshlist->objects--; // The list is shrinked.
9692  i--;
9693  }
9694  }
9695  }
9696 
9697  if (cutshcount > 0) {
9698  i = 0; // Count the number of invalid subfaces/segments.
9699  // Valid the updated sub-cavity sC(p).
9700  if (loc == ONFACE) {
9701  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9702  // The to-be split subface should be in sC(p).
9703  if (!smarktested(*splitsh)) i++;
9704  }
9705  } else if (loc == ONEDGE) {
9706  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9707  // The to-be split segment should be in sC(p).
9708  if (!smarktested(*splitseg)) i++;
9709  }
9710  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9711  // All subfaces at this edge should be in sC(p).
9712  pa = sorg(*splitsh);
9713  neighsh = *splitsh;
9714  while (1) {
9715  // Adjust the origin of its edge to be 'pa'.
9716  if (sorg(neighsh) != pa) {
9717  sesymself(neighsh);
9718  }
9719  // Add this face into list (in B-W cavity).
9720  if (!smarktested(neighsh)) i++;
9721  // Go to the next face at the edge.
9722  spivotself(neighsh);
9723  // Stop if all faces at the edge have been visited.
9724  if (neighsh.sh == splitsh->sh) break;
9725  if (neighsh.sh == NULL) break;
9726  } // while (1)
9727  }
9728  }
9729 
9730  if (i > 0) {
9731  // The updated sC(p) is invalid. Do not insert this vertex.
9732  insertpoint_abort(splitseg, ivf);
9733  ivf->iloc = (int) BADELEMENT;
9734  return 0;
9735  }
9736  } // if (cutshcount > 0)
9737  } // if (ivf->splitbdflag)
9738  } // if (cutcount > 0)
9739 
9740  } // if (ivf->validflag)
9741 
9742  if (ivf->refineflag) {
9743  // The new point is inserted by Delaunay refinement, i.e., it is the
9744  // circumcenter of a tetrahedron, or a subface, or a segment.
9745  // Do not insert this point if the tetrahedron, or subface, or segment
9746  // is not inside the final cavity.
9747  if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
9748  ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
9749  insertpoint_abort(splitseg, ivf);
9750  ivf->iloc = (int) BADELEMENT;
9751  return 0;
9752  }
9753  } // if (ivf->refineflag)
9754 
9755  if (b->plc && (loc != INSTAR)) {
9756  // Reject the new point if it lies too close to an existing point (b->plc),
9757  // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
9758  // Collect the list of vertices of the initial cavity.
9759  if (loc == OUTSIDE) {
9760  pts = (point *) &(searchtet->tet[4]);
9761  for (i = 0; i < 3; i++) {
9762  cavetetvertlist->newindex((void **) &parypt);
9763  *parypt = pts[i];
9764  }
9765  } else if (loc == INTETRAHEDRON) {
9766  pts = (point *) &(searchtet->tet[4]);
9767  for (i = 0; i < 4; i++) {
9768  cavetetvertlist->newindex((void **) &parypt);
9769  *parypt = pts[i];
9770  }
9771  } else if (loc == ONFACE) {
9772  pts = (point *) &(searchtet->tet[4]);
9773  for (i = 0; i < 3; i++) {
9774  cavetetvertlist->newindex((void **) &parypt);
9775  *parypt = pts[i];
9776  }
9777  if (pts[3] != dummypoint) {
9778  cavetetvertlist->newindex((void **) &parypt);
9779  *parypt = pts[3];
9780  }
9781  fsym(*searchtet, spintet);
9782  if (oppo(spintet) != dummypoint) {
9783  cavetetvertlist->newindex((void **) &parypt);
9784  *parypt = oppo(spintet);
9785  }
9786  } else if (loc == ONEDGE) {
9787  spintet = *searchtet;
9788  cavetetvertlist->newindex((void **) &parypt);
9789  *parypt = org(spintet);
9790  cavetetvertlist->newindex((void **) &parypt);
9791  *parypt = dest(spintet);
9792  while (1) {
9793  if (apex(spintet) != dummypoint) {
9794  cavetetvertlist->newindex((void **) &parypt);
9795  *parypt = apex(spintet);
9796  }
9797  fnextself(spintet);
9798  if (spintet.tet == searchtet->tet) break;
9799  }
9800  }
9801 
9802  int rejptflag = (ivf->rejflag & 4);
9803  REAL rd;
9804  pts = NULL;
9805 
9806  for (i = 0; i < cavetetvertlist->objects; i++) {
9807  parypt = (point *) fastlookup(cavetetvertlist, i);
9808  rd = distance(*parypt, insertpt);
9809  // Is the point very close to an existing point?
9810  if (rd < b->minedgelength) {
9811  pts = parypt;
9812  loc = NEARVERTEX;
9813  break;
9814  }
9815  if (rejptflag) {
9816  // Is the point encroaches upon an existing point?
9817  if (rd < (0.5 * (*parypt)[pointmtrindex])) {
9818  pts = parypt;
9819  loc = ENCVERTEX;
9820  break;
9821  }
9822  }
9823  }
9824  cavetetvertlist->restart(); // Clear the work list.
9825 
9826  if (pts != NULL) {
9827  // The point is either too close to an existing vertex (NEARVERTEX)
9828  // or encroaches upon (inside the protecting ball) of that vertex.
9829  if (loc == NEARVERTEX) {
9830  if (b->nomergevertex) { // -M0/1 option.
9831  // In this case, we still insert this vertex. Although it is very
9832  // close to an existing vertex. Give a warning, anyway.
9833  if (!b->quiet) {
9834  printf("Warning: Two points, %d and %d, are very close.\n",
9835  pointmark(insertpt), pointmark(*pts));
9836  printf(" Creating a very short edge (len = %g) (< %g).\n",
9837  rd, b->minedgelength);
9838  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
9839  b->epsilon);
9840  printf(" to avoid this warning.\n");
9841  }
9842  } else {
9843  insertpt[3] = rd; // Only for reporting.
9844  setpoint2ppt(insertpt, *pts);
9845  insertpoint_abort(splitseg, ivf);
9846  ivf->iloc = (int) loc;
9847  return 0;
9848  }
9849  } else { // loc == ENCVERTEX
9850  // The point lies inside the protection ball.
9851  setpoint2ppt(insertpt, *pts);
9852  insertpoint_abort(splitseg, ivf);
9853  ivf->iloc = (int) loc;
9854  return 0;
9855  }
9856  }
9857  } // if (b->plc && (loc != INSTAR))
9858 
9859  if (b->weighted || ivf->cdtflag || ivf->smlenflag
9860  ) {
9861  // There may be other vertices inside C(p). We need to find them.
9862  // Collect all vertices of C(p).
9863  for (i = 0; i < caveoldtetlist->objects; i++) {
9864  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9865  //assert(infected(*cavetet));
9866  pts = (point *) &(cavetet->tet[4]);
9867  for (j = 0; j < 4; j++) {
9868  if (pts[j] != dummypoint) {
9869  if (!pinfected(pts[j])) {
9870  pinfect(pts[j]);
9871  cavetetvertlist->newindex((void **) &parypt);
9872  *parypt = pts[j];
9873  }
9874  }
9875  } // j
9876  } // i
9877  // Uninfect all collected (cavity) vertices.
9878  for (i = 0; i < cavetetvertlist->objects; i++) {
9879  parypt = (point *) fastlookup(cavetetvertlist, i);
9880  puninfect(*parypt);
9881  }
9882  if (ivf->smlenflag) {
9883  REAL len;
9884  // Get the length of the shortest edge connecting to 'newpt'.
9885  parypt = (point *) fastlookup(cavetetvertlist, 0);
9886  ivf->smlen = distance(*parypt, insertpt);
9887  ivf->parentpt = *parypt;
9888  for (i = 1; i < cavetetvertlist->objects; i++) {
9889  parypt = (point *) fastlookup(cavetetvertlist, i);
9890  len = distance(*parypt, insertpt);
9891  if (len < ivf->smlen) {
9892  ivf->smlen = len;
9893  ivf->parentpt = *parypt;
9894  }
9895  }
9896  }
9897  }
9898 
9899 
9900  if (ivf->cdtflag) {
9901  // Unmark tets.
9902  for (i = 0; i < caveoldtetlist->objects; i++) {
9903  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9904  unmarktest(*cavetet);
9905  }
9906  for (i = 0; i < cavebdrylist->objects; i++) {
9907  cavetet = (triface *) fastlookup(cavebdrylist, i);
9908  unmarktest(*cavetet);
9909  }
9910  // Clean up arrays which are not needed.
9911  cavetetlist->restart();
9912  if (checksubsegflag) {
9914  }
9915  if (checksubfaceflag) {
9917  }
9918  return 1;
9919  }
9920 
9921  // Before re-mesh C(p). Process the segments and subfaces which are on the
9922  // boundary of C(p). Make sure that each such segment or subface is
9923  // connecting to a tet outside C(p). So we can re-connect them to the
9924  // new tets inside the C(p) later.
9925 
9926  if (checksubsegflag) {
9927  for (i = 0; i < cavetetseglist->objects; i++) {
9928  paryseg = (face *) fastlookup(cavetetseglist, i);
9929  // Operate on it if it is not the splitting segment, i.e., in sC(p).
9930  if (!smarktested(*paryseg)) {
9931  // Check if the segment is inside the cavity.
9932  // 'j' counts the num of adjacent tets of this seg.
9933  // 'k' counts the num of adjacent tets which are 'sinfected'.
9934  j = k = 0;
9935  sstpivot1(*paryseg, neightet);
9936  spintet = neightet;
9937  while (1) {
9938  j++;
9939  if (!infected(spintet)) {
9940  neineitet = spintet; // An outer tet. Remember it.
9941  } else {
9942  k++; // An in tet.
9943  }
9944  fnextself(spintet);
9945  if (spintet.tet == neightet.tet) break;
9946  }
9947  // assert(j > 0);
9948  if (k == 0) {
9949  // The segment is not connect to C(p) anymore. Remove it by
9950  // Replacing it by the last entry of this list.
9951  s = cavetetseglist->objects - 1;
9952  checkseg = * (face *) fastlookup(cavetetseglist, s);
9953  *paryseg = checkseg;
9955  i--;
9956  } else if (k < j) {
9957  // The segment is on the boundary of C(p).
9958  sstbond1(*paryseg, neineitet);
9959  } else { // k == j
9960  // The segment is inside C(p).
9961  if (!ivf->splitbdflag) {
9962  checkseg = *paryseg;
9963  sinfect(checkseg); // Flag it as an interior segment.
9964  caveencseglist->newindex((void **) &paryseg);
9965  *paryseg = checkseg;
9966  } else {
9967  assert(0); // Not possible.
9968  }
9969  }
9970  } else {
9971  // assert(smarktested(*paryseg));
9972  // Flag it as an interior segment. Do not queue it, since it will
9973  // be deleted after the segment splitting.
9974  sinfect(*paryseg);
9975  }
9976  } // i
9977  } // if (checksubsegflag)
9978 
9979  if (checksubfaceflag) {
9980  for (i = 0; i < cavetetshlist->objects; i++) {
9981  parysh = (face *) fastlookup(cavetetshlist, i);
9982  // Operate on it if it is not inside the sub-cavity sC(p).
9983  if (!smarktested(*parysh)) {
9984  // Check if this subface is inside the cavity.
9985  k = 0;
9986  for (j = 0; j < 2; j++) {
9987  stpivot(*parysh, neightet);
9988  if (!infected(neightet)) {
9989  checksh = *parysh; // Remember this side.
9990  } else {
9991  k++;
9992  }
9993  sesymself(*parysh);
9994  }
9995  if (k == 0) {
9996  // The subface is not connected to C(p). Remove it.
9997  s = cavetetshlist->objects - 1;
9998  checksh = * (face *) fastlookup(cavetetshlist, s);
9999  *parysh = checksh;
10001  i--;
10002  } else if (k == 1) {
10003  // This side is the outer boundary of C(p).
10004  *parysh = checksh;
10005  } else { // k == 2
10006  if (!ivf->splitbdflag) {
10007  checksh = *parysh;
10008  sinfect(checksh); // Flag it.
10009  caveencshlist->newindex((void **) &parysh);
10010  *parysh = checksh;
10011  } else {
10012  assert(0); // Not possible.
10013  }
10014  }
10015  } else {
10016  // assert(smarktested(*parysh));
10017  // Flag it as an interior subface. Do not queue it. It will be
10018  // deleted after the facet point insertion.
10019  sinfect(*parysh);
10020  }
10021  } // i
10022  } // if (checksubfaceflag)
10023 
10024  // Create new tetrahedra to fill the cavity.
10025 
10026  for (i = 0; i < cavebdrylist->objects; i++) {
10027  cavetet = (triface *) fastlookup(cavebdrylist, i);
10028  neightet = *cavetet;
10029  unmarktest(neightet); // Unmark it.
10030  // Get the oldtet (inside the cavity).
10031  fsym(neightet, oldtet);
10032  if (apex(neightet) != dummypoint) {
10033  // Create a new tet in the cavity.
10034  maketetrahedron(&newtet);
10035  setorg(newtet, dest(neightet));
10036  setdest(newtet, org(neightet));
10037  setapex(newtet, apex(neightet));
10038  setoppo(newtet, insertpt);
10039  } else {
10040  // Create a new hull tet.
10041  hullsize++;
10042  maketetrahedron(&newtet);
10043  setorg(newtet, org(neightet));
10044  setdest(newtet, dest(neightet));
10045  setapex(newtet, insertpt);
10046  setoppo(newtet, dummypoint); // It must opposite to face 3.
10047  // Adjust back to the cavity bounday face.
10048  esymself(newtet);
10049  }
10050  // The new tet inherits attribtes from the old tet.
10051  for (j = 0; j < numelemattrib; j++) {
10052  attrib = elemattribute(oldtet.tet, j);
10053  setelemattribute(newtet.tet, j, attrib);
10054  }
10055  if (b->varvolume) {
10056  volume = volumebound(oldtet.tet);
10057  setvolumebound(newtet.tet, volume);
10058  }
10059  // Connect newtet <==> neightet, this also disconnect the old bond.
10060  bond(newtet, neightet);
10061  // oldtet still connects to neightet.
10062  *cavetet = oldtet; // *cavetet = newtet;
10063  } // i
10064 
10065  // Set a handle for speeding point location.
10066  recenttet = newtet;
10067  //setpoint2tet(insertpt, encode(newtet));
10068  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
10069 
10070  // Re-use this list to save new interior cavity faces.
10071  cavetetlist->restart();
10072 
10073  // Connect adjacent new tetrahedra together.
10074  for (i = 0; i < cavebdrylist->objects; i++) {
10075  cavetet = (triface *) fastlookup(cavebdrylist, i);
10076  // cavtet is an oldtet, get the newtet at this face.
10077  oldtet = *cavetet;
10078  fsym(oldtet, neightet);
10079  fsym(neightet, newtet);
10080  // Comment: oldtet and newtet must be at the same directed edge.
10081  // Connect the three other faces of this newtet.
10082  for (j = 0; j < 3; j++) {
10083  esym(newtet, neightet); // Go to the face.
10084  if (neightet.tet[neightet.ver & 3] == NULL) {
10085  // Find the adjacent face of this newtet.
10086  spintet = oldtet;
10087  while (1) {
10088  fnextself(spintet);
10089  if (!infected(spintet)) break;
10090  }
10091  fsym(spintet, newneitet);
10092  esymself(newneitet);
10093  assert(newneitet.tet[newneitet.ver & 3] == NULL);
10094  bond(neightet, newneitet);
10095  if (ivf->lawson > 1) {
10096  cavetetlist->newindex((void **) &parytet);
10097  *parytet = neightet;
10098  }
10099  }
10100  //setpoint2tet(org(newtet), encode(newtet));
10101  setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
10102  enextself(newtet);
10103  enextself(oldtet);
10104  }
10105  *cavetet = newtet; // Save the new tet.
10106  } // i
10107 
10108  if (checksubfaceflag) {
10109  // Connect subfaces on the boundary of the cavity to the new tets.
10110  for (i = 0; i < cavetetshlist->objects; i++) {
10111  parysh = (face *) fastlookup(cavetetshlist, i);
10112  // Connect it if it is not a missing subface.
10113  if (!sinfected(*parysh)) {
10114  stpivot(*parysh, neightet);
10115  fsym(neightet, spintet);
10116  sesymself(*parysh);
10117  tsbond(spintet, *parysh);
10118  }
10119  }
10120  }
10121 
10122  if (checksubsegflag) {
10123  // Connect segments on the boundary of the cavity to the new tets.
10124  for (i = 0; i < cavetetseglist->objects; i++) {
10125  paryseg = (face *) fastlookup(cavetetseglist, i);
10126  // Connect it if it is not a missing segment.
10127  if (!sinfected(*paryseg)) {
10128  sstpivot1(*paryseg, neightet);
10129  spintet = neightet;
10130  while (1) {
10131  tssbond1(spintet, *paryseg);
10132  fnextself(spintet);
10133  if (spintet.tet == neightet.tet) break;
10134  }
10135  }
10136  }
10137  }
10138 
10139  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10140  ((splitseg != NULL) && (splitseg->sh != NULL))) {
10141  // Split a subface or a segment.
10142  sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
10143  }
10144 
10145  if (checksubfaceflag) {
10146  if (ivf->splitbdflag) {
10147  // Recover new subfaces in C(p).
10148  for (i = 0; i < caveshbdlist->objects; i++) {
10149  // Get an old subface at edge [a, b].
10150  parysh = (face *) fastlookup(caveshbdlist, i);
10151  spivot(*parysh, checksh); // The new subface [a, b, p].
10152  // Do not recover a deleted new face (degenerated).
10153  if (checksh.sh[3] != NULL) {
10154  // Note that the old subface still connects to adjacent old tets
10155  // of C(p), which still connect to the tets outside C(p).
10156  stpivot(*parysh, neightet);
10157  assert(infected(neightet));
10158  // Find the adjacent tet containing the edge [a,b] outside C(p).
10159  spintet = neightet;
10160  while (1) {
10161  fnextself(spintet);
10162  if (!infected(spintet)) break;
10163  assert(spintet.tet != neightet.tet);
10164  }
10165  // The adjacent tet connects to a new tet in C(p).
10166  fsym(spintet, neightet);
10167  assert(!infected(neightet));
10168  // Find the tet containing the face [a, b, p].
10169  spintet = neightet;
10170  while (1) {
10171  fnextself(spintet);
10172  if (apex(spintet) == insertpt) break;
10173  assert(spintet.tet != neightet.tet);
10174  }
10175  // Adjust the edge direction in spintet and checksh.
10176  if (sorg(checksh) != org(spintet)) {
10177  sesymself(checksh);
10178  assert(sorg(checksh) == org(spintet));
10179  }
10180  assert(sdest(checksh) == dest(spintet));
10181  // Connect the subface to two adjacent tets.
10182  tsbond(spintet, checksh);
10183  fsymself(spintet);
10184  sesymself(checksh);
10185  tsbond(spintet, checksh);
10186  } // if (checksh.sh[3] != NULL)
10187  }
10188  // There should be no missing interior subfaces in C(p).
10189  assert(caveencshlist->objects == 0l);
10190  } else {
10191  // The Boundary recovery phase.
10192  // Put all new subfaces into stack for recovery.
10193  for (i = 0; i < caveshbdlist->objects; i++) {
10194  // Get an old subface at edge [a, b].
10195  parysh = (face *) fastlookup(caveshbdlist, i);
10196  spivot(*parysh, checksh); // The new subface [a, b, p].
10197  // Do not recover a deleted new face (degenerated).
10198  if (checksh.sh[3] != NULL) {
10199  subfacstack->newindex((void **) &parysh);
10200  *parysh = checksh;
10201  }
10202  }
10203  // Put all interior subfaces into stack for recovery.
10204  for (i = 0; i < caveencshlist->objects; i++) {
10205  parysh = (face *) fastlookup(caveencshlist, i);
10206  assert(sinfected(*parysh));
10207  // Some subfaces inside C(p) might be split in sinsertvertex().
10208  // Only queue those faces which are not split.
10209  if (!smarktested(*parysh)) {
10210  checksh = *parysh;
10211  suninfect(checksh);
10212  stdissolve(checksh); // Detach connections to old tets.
10213  subfacstack->newindex((void **) &parysh);
10214  *parysh = checksh;
10215  }
10216  }
10217  }
10218  } // if (checksubfaceflag)
10219 
10220  if (checksubsegflag) {
10221  if (ivf->splitbdflag) {
10222  if (splitseg != NULL) {
10223  // Recover the two new subsegments in C(p).
10224  for (i = 0; i < cavesegshlist->objects; i++) {
10225  paryseg = (face *) fastlookup(cavesegshlist, i);
10226  // Insert this subsegment into C(p).
10227  checkseg = *paryseg;
10228  // Get the adjacent new subface.
10229  checkseg.shver = 0;
10230  spivot(checkseg, checksh);
10231  if (checksh.sh != NULL) {
10232  // Get the adjacent new tetrahedron.
10233  stpivot(checksh, neightet);
10234  } else {
10235  // It's a dangling segment.
10236  point2tetorg(sorg(checkseg), neightet);
10237  finddirection(&neightet, sdest(checkseg));
10238  assert(dest(neightet) == sdest(checkseg));
10239  }
10240  assert(!infected(neightet));
10241  sstbond1(checkseg, neightet);
10242  spintet = neightet;
10243  while (1) {
10244  tssbond1(spintet, checkseg);
10245  fnextself(spintet);
10246  if (spintet.tet == neightet.tet) break;
10247  }
10248  }
10249  } // if (splitseg != NULL)
10250  // There should be no interior segment in C(p).
10251  assert(caveencseglist->objects == 0l);
10252  } else {
10253  // The Boundary Recovery Phase.
10254  // Queue missing segments in C(p) for recovery.
10255  if (splitseg != NULL) {
10256  // Queue two new subsegments in C(p) for recovery.
10257  for (i = 0; i < cavesegshlist->objects; i++) {
10258  paryseg = (face *) fastlookup(cavesegshlist, i);
10259  checkseg = *paryseg;
10260  //sstdissolve1(checkseg); // It has not been connected yet.
10261  s = randomnation(subsegstack->objects + 1);
10262  subsegstack->newindex((void **) &paryseg);
10263  *paryseg = * (face *) fastlookup(subsegstack, s);
10264  paryseg = (face *) fastlookup(subsegstack, s);
10265  *paryseg = checkseg;
10266  }
10267  } // if (splitseg != NULL)
10268  for (i = 0; i < caveencseglist->objects; i++) {
10269  paryseg = (face *) fastlookup(caveencseglist, i);
10270  assert(sinfected(*paryseg));
10271  if (!smarktested(*paryseg)) { // It may be split.
10272  checkseg = *paryseg;
10273  suninfect(checkseg);
10274  sstdissolve1(checkseg); // Detach connections to old tets.
10275  s = randomnation(subsegstack->objects + 1);
10276  subsegstack->newindex((void **) &paryseg);
10277  *paryseg = * (face *) fastlookup(subsegstack, s);
10278  paryseg = (face *) fastlookup(subsegstack, s);
10279  *paryseg = checkseg;
10280  }
10281  }
10282  }
10283  } // if (checksubsegflag)
10284 
10285  if (b->weighted
10286  ) {
10287  // Some vertices may be completed inside the cavity. They must be
10288  // detected and added to recovering list.
10289  // Since every "live" vertex must contain a pointer to a non-dead
10290  // tetrahedron, we can check for each vertex this pointer.
10291  for (i = 0; i < cavetetvertlist->objects; i++) {
10292  pts = (point *) fastlookup(cavetetvertlist, i);
10293  decode(point2tet(*pts), *searchtet);
10294  assert(searchtet->tet != NULL); // No tet has been deleted yet.
10295  if (infected(*searchtet)) {
10296  if (b->weighted) {
10297  if (b->verbose > 1) {
10298  printf(" Point #%d is non-regular after the insertion of #%d.\n",
10299  pointmark(*pts), pointmark(insertpt));
10300  }
10302  nonregularcount++;
10303  }
10304  }
10305  }
10306  }
10307 
10308  if (ivf->chkencflag & 1) {
10309  // Queue all segment outside C(p).
10310  for (i = 0; i < cavetetseglist->objects; i++) {
10311  paryseg = (face *) fastlookup(cavetetseglist, i);
10312  // Skip if it is the split segment.
10313  if (!sinfected(*paryseg)) {
10314  enqueuesubface(badsubsegs, paryseg);
10315  }
10316  }
10317  if (splitseg != NULL) {
10318  // Queue the two new subsegments inside C(p).
10319  for (i = 0; i < cavesegshlist->objects; i++) {
10320  paryseg = (face *) fastlookup(cavesegshlist, i);
10321  enqueuesubface(badsubsegs, paryseg);
10322  }
10323  }
10324  } // if (chkencflag & 1)
10325 
10326  if (ivf->chkencflag & 2) {
10327  // Queue all subfaces outside C(p).
10328  for (i = 0; i < cavetetshlist->objects; i++) {
10329  parysh = (face *) fastlookup(cavetetshlist, i);
10330  // Skip if it is a split subface.
10331  if (!sinfected(*parysh)) {
10332  enqueuesubface(badsubfacs, parysh);
10333  }
10334  }
10335  // Queue all new subfaces inside C(p).
10336  for (i = 0; i < caveshbdlist->objects; i++) {
10337  // Get an old subface at edge [a, b].
10338  parysh = (face *) fastlookup(caveshbdlist, i);
10339  spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
10340  // Do not recover a deleted new face (degenerated).
10341  if (checksh.sh[3] != NULL) {
10342  enqueuesubface(badsubfacs, &checksh);
10343  }
10344  }
10345  } // if (chkencflag & 2)
10346 
10347  if (ivf->chkencflag & 4) {
10348  // Queue all new tetrahedra in C(p).
10349  for (i = 0; i < cavebdrylist->objects; i++) {
10350  cavetet = (triface *) fastlookup(cavebdrylist, i);
10351  enqueuetetrahedron(cavetet);
10352  }
10353  }
10354 
10355  // C(p) is re-meshed successfully.
10356 
10357  // Delete the old tets in C(p).
10358  for (i = 0; i < caveoldtetlist->objects; i++) {
10359  searchtet = (triface *) fastlookup(caveoldtetlist, i);
10360  if (ishulltet(*searchtet)) {
10361  hullsize--;
10362  }
10363  tetrahedrondealloc(searchtet->tet);
10364  }
10365 
10366  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10367  ((splitseg != NULL) && (splitseg->sh != NULL))) {
10368  // Delete the old subfaces in sC(p).
10369  for (i = 0; i < caveshlist->objects; i++) {
10370  parysh = (face *) fastlookup(caveshlist, i);
10371  if (checksubfaceflag) {//if (bowywat == 2) {
10372  // It is possible that this subface still connects to adjacent
10373  // tets which are not in C(p). If so, clear connections in the
10374  // adjacent tets at this subface.
10375  stpivot(*parysh, neightet);
10376  if (neightet.tet != NULL) {
10377  if (neightet.tet[4] != NULL) {
10378  // Found an adjacent tet. It must be not in C(p).
10379  assert(!infected(neightet));
10380  tsdissolve(neightet);
10381  fsymself(neightet);
10382  assert(!infected(neightet));
10383  tsdissolve(neightet);
10384  }
10385  }
10386  }
10387  shellfacedealloc(subfaces, parysh->sh);
10388  }
10389  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10390  // Delete the old segment in sC(p).
10391  shellfacedealloc(subsegs, splitseg->sh);
10392  }
10393  }
10394 
10395  if (ivf->lawson) {
10396  for (i = 0; i < cavebdrylist->objects; i++) {
10397  searchtet = (triface *) fastlookup(cavebdrylist, i);
10398  flippush(flipstack, searchtet);
10399  }
10400  if (ivf->lawson > 1) {
10401  for (i = 0; i < cavetetlist->objects; i++) {
10402  searchtet = (triface *) fastlookup(cavetetlist, i);
10403  flippush(flipstack, searchtet);
10404  }
10405  }
10406  }
10407 
10408 
10409  // Clean the working lists.
10410 
10412  cavebdrylist->restart();
10413  cavetetlist->restart();
10414 
10415  if (checksubsegflag) {
10418  }
10419 
10420  if (checksubfaceflag) {
10423  }
10424 
10425  if (b->weighted || ivf->validflag) {
10427  }
10428 
10429  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10430  ((splitseg != NULL) && (splitseg->sh != NULL))) {
10431  caveshlist->restart();
10432  caveshbdlist->restart();
10434  }
10435 
10436  return 1; // Point is inserted.
10437 }
10438 
10440 // //
10441 // insertpoint_abort() Abort the insertion of a new vertex. //
10442 // //
10443 // The cavity will be restored. All working lists are cleared. //
10444 // //
10446 
10448 {
10449  triface *cavetet;
10450  face *parysh;
10451  int i;
10452 
10453  for (i = 0; i < caveoldtetlist->objects; i++) {
10454  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10455  uninfect(*cavetet);
10456  unmarktest(*cavetet);
10457  }
10458  for (i = 0; i < cavebdrylist->objects; i++) {
10459  cavetet = (triface *) fastlookup(cavebdrylist, i);
10460  unmarktest(*cavetet);
10461  }
10462  cavetetlist->restart();
10463  cavebdrylist->restart();
10467  if (ivf->splitbdflag) {
10468  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10469  sunmarktest(*splitseg);
10470  }
10471  for (i = 0; i < caveshlist->objects; i++) {
10472  parysh = (face *) fastlookup(caveshlist, i);
10473  assert(smarktested(*parysh));
10474  sunmarktest(*parysh);
10475  }
10476  caveshlist->restart();
10478  }
10479 }
10480 
10484 
10488 
10490 // //
10491 // transfernodes() Read the vertices from the input (tetgenio). //
10492 // //
10493 // Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
10494 // All points are indexed (the first point index is 'in->firstnumber'). Each //
10495 // point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
10496 // ...) and the diameter (longest) of the point set are calculated. //
10497 // //
10499 
10501 {
10502  point pointloop;
10503  REAL x, y, z, w;
10504  int coordindex;
10505  int attribindex;
10506  int mtrindex;
10507  int i, j;
10508 
10509  if (b->psc) {
10510  assert(in->pointparamlist != NULL);
10511  }
10512 
10513  // Read the points.
10514  coordindex = 0;
10515  attribindex = 0;
10516  mtrindex = 0;
10517  for (i = 0; i < in->numberofpoints; i++) {
10518  makepoint(&pointloop, UNUSEDVERTEX);
10519  // Read the point coordinates.
10520  x = pointloop[0] = in->pointlist[coordindex++];
10521  y = pointloop[1] = in->pointlist[coordindex++];
10522  z = pointloop[2] = in->pointlist[coordindex++];
10523  // Read the point attributes. (Including point weights.)
10524  for (j = 0; j < in->numberofpointattributes; j++) {
10525  pointloop[3 + j] = in->pointattributelist[attribindex++];
10526  }
10527  // Read the point metric tensor.
10528  for (j = 0; j < in->numberofpointmtrs; j++) {
10529  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
10530  }
10531  if (b->weighted) { // -w option
10532  if (in->numberofpointattributes > 0) {
10533  // The first point attribute is its weight.
10534  //w = in->pointattributelist[in->numberofpointattributes * i];
10535  w = pointloop[3];
10536  } else {
10537  // No given weight available. Default choose the maximum
10538  // absolute value among its coordinates.
10539  w = fabs(x);
10540  if (w < fabs(y)) w = fabs(y);
10541  if (w < fabs(z)) w = fabs(z);
10542  }
10543  if (b->weighted_param == 0) {
10544  pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
10545  } else { // -w1 option
10546  pointloop[3] = w; // Regular tetrahedralization.
10547  }
10548  }
10549  // Determine the smallest and largest x, y and z coordinates.
10550  if (i == 0) {
10551  xmin = xmax = x;
10552  ymin = ymax = y;
10553  zmin = zmax = z;
10554  } else {
10555  xmin = (x < xmin) ? x : xmin;
10556  xmax = (x > xmax) ? x : xmax;
10557  ymin = (y < ymin) ? y : ymin;
10558  ymax = (y > ymax) ? y : ymax;
10559  zmin = (z < zmin) ? z : zmin;
10560  zmax = (z > zmax) ? z : zmax;
10561  }
10562  if (b->psc) {
10563  // Read the geometry parameters.
10564  setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
10565  setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
10566  setpointgeomtag(pointloop, in->pointparamlist[i].tag);
10567  if (in->pointparamlist[i].type == 0) {
10568  setpointtype(pointloop, RIDGEVERTEX);
10569  } else if (in->pointparamlist[i].type == 1) {
10570  setpointtype(pointloop, FREESEGVERTEX);
10571  } else if (in->pointparamlist[i].type == 2) {
10572  setpointtype(pointloop, FREEFACETVERTEX);
10573  } else if (in->pointparamlist[i].type == 3) {
10574  setpointtype(pointloop, FREEVOLVERTEX);
10575  }
10576  }
10577  }
10578 
10579  // 'longest' is the largest possible edge length formed by input vertices.
10580  x = xmax - xmin;
10581  y = ymax - ymin;
10582  z = zmax - zmin;
10583  longest = sqrt(x * x + y * y + z * z);
10584  if (longest == 0.0) {
10585  printf("Error: The point set is trivial.\n");
10586  terminatetetgen(this, 3);
10587  }
10588 
10589  // Two identical points are distinguished by 'lengthlimit'.
10590  if (b->minedgelength == 0.0) {
10592  }
10593 }
10594 
10596 // //
10597 // hilbert_init() Initialize the Gray code permutation table. //
10598 // //
10599 // The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray //
10600 // code sequences traveled by the 1st order Hilbert curve in 3 dimensions. //
10601 // The first column is the Gray code of the entry point of the curve, and //
10602 // the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
10603 // the exit point of curve lies. //
10604 // //
10605 // The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
10606 // indices from 0 to 7, modulo by '3'. The code for generating this table is //
10607 // from: http://graphics.stanford.edu/~seander/bithacks.html. //
10608 // //
10610 
10612 {
10613  int gc[8], N, mask, travel_bit;
10614  int e, d, f, k, g;
10615  int v, c;
10616  int i;
10617 
10618  N = (n == 2) ? 4 : 8;
10619  mask = (n == 2) ? 3 : 7;
10620 
10621  // Generate the Gray code sequence.
10622  for (i = 0; i < N; i++) {
10623  gc[i] = i ^ (i >> 1);
10624  }
10625 
10626  for (e = 0; e < N; e++) {
10627  for (d = 0; d < n; d++) {
10628  // Calculate the end point (f).
10629  f = e ^ (1 << d); // Toggle the d-th bit of 'e'.
10630  // travel_bit = 2**p, the bit we want to travel.
10631  travel_bit = e ^ f;
10632  for (i = 0; i < N; i++) {
10633  // // Rotate gc[i] left by (p + 1) % n bits.
10634  k = gc[i] * (travel_bit * 2);
10635  g = ((k | (k / N)) & mask);
10636  // Calculate the permuted Gray code by xor with the start point (e).
10637  transgc[e][d][i] = (g ^ e);
10638  }
10639  assert(transgc[e][d][0] == e);
10640  assert(transgc[e][d][N - 1] == f);
10641  } // d
10642  } // e
10643 
10644  // Count the consecutive '1' bits (trailing) on the right.
10645  tsb1mod3[0] = 0;
10646  for (i = 1; i < N; i++) {
10647  v = ~i; // Count the 0s.
10648  v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
10649  for (c = 0; v; c++) {
10650  v >>= 1;
10651  }
10652  tsb1mod3[i] = c % n;
10653  }
10654 }
10655 
10657 // //
10658 // hilbert_sort3() Sort points using the 3d Hilbert curve. //
10659 // //
10661 
10662 int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
10663  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10664  REAL bzmin, REAL bzmax)
10665 {
10666  point swapvert;
10667  int axis, d;
10668  REAL split;
10669  int i, j;
10670 
10671 
10672  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
10673  // correspoding to x-, or y- or z-axis.
10674  axis = (gc0 ^ gc1) >> 1;
10675 
10676  // Calulate the split position along the axis.
10677  if (axis == 0) {
10678  split = 0.5 * (bxmin + bxmax);
10679  } else if (axis == 1) {
10680  split = 0.5 * (bymin + bymax);
10681  } else { // == 2
10682  split = 0.5 * (bzmin + bzmax);
10683  }
10684 
10685  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
10686  // of the axis is to the positive of the axis, otherwise, it is -1.
10687  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
10688 
10689 
10690  // Partition the vertices into left- and right-arrays such that left points
10691  // have Hilbert indices lower than the right points.
10692  i = 0;
10693  j = arraysize - 1;
10694 
10695  // Partition the vertices into left- and right-arrays.
10696  if (d > 0) {
10697  do {
10698  for (; i < arraysize; i++) {
10699  if (vertexarray[i][axis] >= split) break;
10700  }
10701  for (; j >= 0; j--) {
10702  if (vertexarray[j][axis] < split) break;
10703  }
10704  // Is the partition finished?
10705  if (i == (j + 1)) break;
10706  // Swap i-th and j-th vertices.
10707  swapvert = vertexarray[i];
10708  vertexarray[i] = vertexarray[j];
10709  vertexarray[j] = swapvert;
10710  // Continue patitioning the array;
10711  } while (true);
10712  } else {
10713  do {
10714  for (; i < arraysize; i++) {
10715  if (vertexarray[i][axis] <= split) break;
10716  }
10717  for (; j >= 0; j--) {
10718  if (vertexarray[j][axis] > split) break;
10719  }
10720  // Is the partition finished?
10721  if (i == (j + 1)) break;
10722  // Swap i-th and j-th vertices.
10723  swapvert = vertexarray[i];
10724  vertexarray[i] = vertexarray[j];
10725  vertexarray[j] = swapvert;
10726  // Continue patitioning the array;
10727  } while (true);
10728  }
10729 
10730  return i;
10731 }
10732 
10733 void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
10734  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10735  REAL bzmin, REAL bzmax, int depth)
10736 {
10737  REAL x1, x2, y1, y2, z1, z2;
10738  int p[9], w, e_w, d_w, k, ei, di;
10739  int n = 3, mask = 7;
10740 
10741  p[0] = 0;
10742  p[8] = arraysize;
10743 
10744  // Sort the points according to the 1st order Hilbert curve in 3d.
10745  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
10746  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10747  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
10748  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10749  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
10750  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10751  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
10752  transgc[e][d][2], transgc[e][d][3],
10753  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
10754  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
10755  transgc[e][d][5], transgc[e][d][6],
10756  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10757  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
10758  transgc[e][d][4], transgc[e][d][5],
10759  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10760  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
10761  transgc[e][d][6], transgc[e][d][7],
10762  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
10763 
10764  if (b->hilbert_order > 0) {
10765  // A maximum order is prescribed.
10766  if ((depth + 1) == b->hilbert_order) {
10767  // The maximum prescribed order is reached.
10768  return;
10769  }
10770  }
10771 
10772  // Recursively sort the points in sub-boxes.
10773  for (w = 0; w < 8; w++) {
10774  // w is the local Hilbert index (NOT Gray code).
10775  // Sort into the sub-box either there are more than 2 points in it, or
10776  // the prescribed order of the curve is not reached yet.
10777  //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
10778  if ((p[w+1] - p[w]) > b->hilbert_limit) {
10779  // Calculcate the start point (ei) of the curve in this sub-box.
10780  // update e = e ^ (e(w) left_rotate (d+1)).
10781  if (w == 0) {
10782  e_w = 0;
10783  } else {
10784  // calculate e(w) = gc(2 * floor((w - 1) / 2)).
10785  k = 2 * ((w - 1) / 2);
10786  e_w = k ^ (k >> 1); // = gc(k).
10787  }
10788  k = e_w;
10789  e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
10790  ei = e ^ e_w;
10791  // Calulcate the direction (di) of the curve in this sub-box.
10792  // update d = (d + d(w) + 1) % n
10793  if (w == 0) {
10794  d_w = 0;
10795  } else {
10796  d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
10797  }
10798  di = (d + d_w + 1) % n;
10799  // Calculate the bounding box of the sub-box.
10800  if (transgc[e][d][w] & 1) { // x-axis
10801  x1 = 0.5 * (bxmin + bxmax);
10802  x2 = bxmax;
10803  } else {
10804  x1 = bxmin;
10805  x2 = 0.5 * (bxmin + bxmax);
10806  }
10807  if (transgc[e][d][w] & 2) { // y-axis
10808  y1 = 0.5 * (bymin + bymax);
10809  y2 = bymax;
10810  } else {
10811  y1 = bymin;
10812  y2 = 0.5 * (bymin + bymax);
10813  }
10814  if (transgc[e][d][w] & 4) { // z-axis
10815  z1 = 0.5 * (bzmin + bzmax);
10816  z2 = bzmax;
10817  } else {
10818  z1 = bzmin;
10819  z2 = 0.5 * (bzmin + bzmax);
10820  }
10821  hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
10822  x1, x2, y1, y2, z1, z2, depth+1);
10823  } // if (p[w+1] - p[w] > 1)
10824  } // w
10825 }
10826 
10828 // //
10829 // brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. //
10830 // //
10832 
10833 void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
10834  int threshold, REAL ratio, int *depth)
10835 {
10836  int middle;
10837 
10838  middle = 0;
10839  if (arraysize >= threshold) {
10840  (*depth)++;
10841  middle = arraysize * ratio;
10842  brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
10843  }
10844  // Sort the right-array (rnd-th round) using the Hilbert curve.
10845  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
10846  xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
10847 }
10848 
10850 // //
10851 // randomnation() Generate a random number between 0 and 'choices' - 1. //
10852 // //
10854 
10855 unsigned long tetgenmesh::randomnation(unsigned int choices)
10856 {
10857  unsigned long newrandom;
10858 
10859  if (choices >= 714025l) {
10860  newrandom = (randomseed * 1366l + 150889l) % 714025l;
10861  randomseed = (newrandom * 1366l + 150889l) % 714025l;
10862  newrandom = newrandom * (choices / 714025l) + randomseed;
10863  if (newrandom >= choices) {
10864  return newrandom - choices;
10865  } else {
10866  return newrandom;
10867  }
10868  } else {
10869  randomseed = (randomseed * 1366l + 150889l) % 714025l;
10870  return randomseed % choices;
10871  }
10872 }
10873 
10875 // //
10876 // randomsample() Randomly sample the tetrahedra for point loation. //
10877 // //
10878 // Searching begins from one of handles: the input 'searchtet', a recently //
10879 // encountered tetrahedron 'recenttet', or from one chosen from a random //
10880 // sample. The choice is made by determining which one's origin is closest //
10881 // to the point we are searching for. //
10882 // //
10884 
10885 void tetgenmesh::randomsample(point searchpt,triface *searchtet)
10886 {
10887  tetrahedron *firsttet, *tetptr;
10888  point torg;
10889  void **sampleblock;
10890  uintptr_t alignptr;
10891  long sampleblocks, samplesperblock, samplenum;
10892  long tetblocks, i, j;
10893  REAL searchdist, dist;
10894 
10895  if (b->verbose > 2) {
10896  printf(" Random sampling tetrahedra for searching point %d.\n",
10897  pointmark(searchpt));
10898  }
10899 
10900  if (!nonconvex) {
10901  if (searchtet->tet == NULL) {
10902  // A null tet. Choose the recenttet as the starting tet.
10903  *searchtet = recenttet;
10904  // Recenttet should not be dead.
10905  assert(recenttet.tet[4] != NULL);
10906  }
10907 
10908  // 'searchtet' should be a valid tetrahedron. Choose the base face
10909  // whose vertices must not be 'dummypoint'.
10910  searchtet->ver = 3;
10911  // Record the distance from its origin to the searching point.
10912  torg = org(*searchtet);
10913  searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10914  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10915  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10916 
10917  // If a recently encountered tetrahedron has been recorded and has not
10918  // been deallocated, test it as a good starting point.
10919  if (recenttet.tet != searchtet->tet) {
10920  recenttet.ver = 3;
10921  torg = org(recenttet);
10922  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10923  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10924  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10925  if (dist < searchdist) {
10926  *searchtet = recenttet;
10927  searchdist = dist;
10928  }
10929  }
10930  } else {
10931  // The mesh is non-convex. Do not use 'recenttet'.
10932  assert(samples >= 1l); // Make sure at least 1 sample.
10933  searchdist = longest;
10934  }
10935 
10936  // Select "good" candidate using k random samples, taking the closest one.
10937  // The number of random samples taken is proportional to the fourth root
10938  // of the number of tetrahedra in the mesh.
10939  while (samples * samples * samples * samples < tetrahedrons->items) {
10940  samples++;
10941  }
10942  // Find how much blocks in current tet pool.
10943  tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
10944  / b->tetrahedraperblock;
10945  // Find the average samples per block. Each block at least have 1 sample.
10946  samplesperblock = 1 + (samples / tetblocks);
10947  sampleblocks = samples / samplesperblock;
10948  sampleblock = tetrahedrons->firstblock;
10949  for (i = 0; i < sampleblocks; i++) {
10950  alignptr = (uintptr_t) (sampleblock + 1);
10951  firsttet = (tetrahedron *)
10952  (alignptr + (uintptr_t) tetrahedrons->alignbytes
10953  - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
10954  for (j = 0; j < samplesperblock; j++) {
10955  if (i == tetblocks - 1) {
10956  // This is the last block.
10957  samplenum = randomnation((int)
10959  } else {
10960  samplenum = randomnation(b->tetrahedraperblock);
10961  }
10962  tetptr = (tetrahedron *)
10963  (firsttet + (samplenum * tetrahedrons->itemwords));
10964  torg = (point) tetptr[4];
10965  if (torg != (point) NULL) {
10966  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
10967  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
10968  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
10969  if (dist < searchdist) {
10970  searchtet->tet = tetptr;
10971  searchtet->ver = 11; // torg = org(t);
10972  searchdist = dist;
10973  }
10974  } else {
10975  // A dead tet. Re-sample it.
10976  if (i != tetblocks - 1) j--;
10977  }
10978  }
10979  sampleblock = (void **) *sampleblock;
10980  }
10981 }
10982 
10984 // //
10985 // locate() Find a tetrahedron containing a given point. //
10986 // //
10987 // Begins its search from 'searchtet', assume there is a line segment L from //
10988 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
10989 // towards 'searchpt' by traversing all faces intersected by L. //
10990 // //
10991 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
10992 // returned value indicates one of the following cases: //
10993 // - ONVERTEX, the search point lies on the origin of 'searchtet'. //
10994 // - ONEDGE, the search point lies on an edge of 'searchtet'. //
10995 // - ONFACE, the search point lies on a face of 'searchtet'. //
10996 // - INTET, the search point lies in the interior of 'searchtet'. //
10997 // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a //
10998 // hull face which is visible by the search point. //
10999 // //
11000 // WARNING: This routine is designed for convex triangulations, and will not //
11001 // generally work after the holes and concavities have been carved. //
11002 // //
11004 
11006  triface* searchtet)
11007 {
11008  point torg, tdest, tapex, toppo;
11009  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
11010  REAL ori, oriorg, oridest, oriapex;
11011  enum locateresult loc = OUTSIDE;
11012  int t1ver;
11013  int s;
11014 
11015  if (searchtet->tet == NULL) {
11016  // A null tet. Choose the recenttet as the starting tet.
11017  searchtet->tet = recenttet.tet;
11018  }
11019 
11020  // Check if we are in the outside of the convex hull.
11021  if (ishulltet(*searchtet)) {
11022  // Get its adjacent tet (inside the hull).
11023  searchtet->ver = 3;
11024  fsymself(*searchtet);
11025  }
11026 
11027  // Let searchtet be the face such that 'searchpt' lies above to it.
11028  for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
11029  torg = org(*searchtet);
11030  tdest = dest(*searchtet);
11031  tapex = apex(*searchtet);
11032  ori = orient3d(torg, tdest, tapex, searchpt);
11033  if (ori < 0.0) break;
11034  }
11035  assert(searchtet->ver != 4);
11036 
11037  // Walk through tetrahedra to locate the point.
11038  while (true) {
11039 
11040  toppo = oppo(*searchtet);
11041 
11042  // Check if the vertex is we seek.
11043  if (toppo == searchpt) {
11044  // Adjust the origin of searchtet to be searchpt.
11045  esymself(*searchtet);
11046  eprevself(*searchtet);
11047  loc = ONVERTEX; // return ONVERTEX;
11048  break;
11049  }
11050 
11051  // We enter from one of serarchtet's faces, which face do we exit?
11052  oriorg = orient3d(tdest, tapex, toppo, searchpt);
11053  oridest = orient3d(tapex, torg, toppo, searchpt);
11054  oriapex = orient3d(torg, tdest, toppo, searchpt);
11055 
11056  // Now decide which face to move. It is possible there are more than one
11057  // faces are viable moves. If so, randomly choose one.
11058  if (oriorg < 0) {
11059  if (oridest < 0) {
11060  if (oriapex < 0) {
11061  // All three faces are possible.
11062  s = randomnation(3); // 's' is in {0,1,2}.
11063  if (s == 0) {
11064  nextmove = ORGMOVE;
11065  } else if (s == 1) {
11066  nextmove = DESTMOVE;
11067  } else {
11068  nextmove = APEXMOVE;
11069  }
11070  } else {
11071  // Two faces, opposite to origin and destination, are viable.
11072  //s = randomnation(2); // 's' is in {0,1}.
11073  if (randomnation(2)) {
11074  nextmove = ORGMOVE;
11075  } else {
11076  nextmove = DESTMOVE;
11077  }
11078  }
11079  } else {
11080  if (oriapex < 0) {
11081  // Two faces, opposite to origin and apex, are viable.
11082  //s = randomnation(2); // 's' is in {0,1}.
11083  if (randomnation(2)) {
11084  nextmove = ORGMOVE;
11085  } else {
11086  nextmove = APEXMOVE;
11087  }
11088  } else {
11089  // Only the face opposite to origin is viable.
11090  nextmove = ORGMOVE;
11091  }
11092  }
11093  } else {
11094  if (oridest < 0) {
11095  if (oriapex < 0) {
11096  // Two faces, opposite to destination and apex, are viable.
11097  //s = randomnation(2); // 's' is in {0,1}.
11098  if (randomnation(2)) {
11099  nextmove = DESTMOVE;
11100  } else {
11101  nextmove = APEXMOVE;
11102  }
11103  } else {
11104  // Only the face opposite to destination is viable.
11105  nextmove = DESTMOVE;
11106  }
11107  } else {
11108  if (oriapex < 0) {
11109  // Only the face opposite to apex is viable.
11110  nextmove = APEXMOVE;
11111  } else {
11112  // The point we seek must be on the boundary of or inside this
11113  // tetrahedron. Check for boundary cases.
11114  if (oriorg == 0) {
11115  // Go to the face opposite to origin.
11116  enextesymself(*searchtet);
11117  if (oridest == 0) {
11118  eprevself(*searchtet); // edge oppo->apex
11119  if (oriapex == 0) {
11120  // oppo is duplicated with p.
11121  loc = ONVERTEX; // return ONVERTEX;
11122  break;
11123  }
11124  loc = ONEDGE; // return ONEDGE;
11125  break;
11126  }
11127  if (oriapex == 0) {
11128  enextself(*searchtet); // edge dest->oppo
11129  loc = ONEDGE; // return ONEDGE;
11130  break;
11131  }
11132  loc = ONFACE; // return ONFACE;
11133  break;
11134  }
11135  if (oridest == 0) {
11136  // Go to the face opposite to destination.
11137  eprevesymself(*searchtet);
11138  if (oriapex == 0) {
11139  eprevself(*searchtet); // edge oppo->org
11140  loc = ONEDGE; // return ONEDGE;
11141  break;
11142  }
11143  loc = ONFACE; // return ONFACE;
11144  break;
11145  }
11146  if (oriapex == 0) {
11147  // Go to the face opposite to apex
11148  esymself(*searchtet);
11149  loc = ONFACE; // return ONFACE;
11150  break;
11151  }
11152  loc = INTETRAHEDRON; // return INTETRAHEDRON;
11153  break;
11154  }
11155  }
11156  }
11157 
11158  // Move to the selected face.
11159  if (nextmove == ORGMOVE) {
11160  enextesymself(*searchtet);
11161  } else if (nextmove == DESTMOVE) {
11162  eprevesymself(*searchtet);
11163  } else {
11164  esymself(*searchtet);
11165  }
11166  // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
11167  fsymself(*searchtet);
11168  if (oppo(*searchtet) == dummypoint) {
11169  loc = OUTSIDE; // return OUTSIDE;
11170  break;
11171  }
11172 
11173  // Retreat the three vertices of the base face.
11174  torg = org(*searchtet);
11175  tdest = dest(*searchtet);
11176  tapex = apex(*searchtet);
11177 
11178  } // while (true)
11179 
11180  return loc;
11181 }
11182 
11184 // //
11185 // flippush() Push a face (possibly will be flipped) into flipstack. //
11186 // //
11187 // The face is marked. The flag is used to check the validity of the face on //
11188 // its popup. Some other flips may change it already. //
11189 // //
11191 
11192 void tetgenmesh::flippush(badface*& fstack, triface* flipface)
11193 {
11194  if (!facemarked(*flipface)) {
11195  badface *newflipface = (badface *) flippool->alloc();
11196  newflipface->tt = *flipface;
11197  markface(newflipface->tt);
11198  // Push this face into stack.
11199  newflipface->nextitem = fstack;
11200  fstack = newflipface;
11201  }
11202 }
11203 
11205 // //
11206 // incrementalflip() Incrementally flipping to construct DT. //
11207 // //
11208 // Faces need to be checked for flipping are already queued in 'flipstack'. //
11209 // Return the total number of performed flips. //
11210 // //
11211 // Comment: This routine should be only used in the incremental Delaunay //
11212 // construction. In other cases, lawsonflip3d() should be used. //
11213 // //
11214 // If the new point lies outside of the convex hull ('hullflag' is set). The //
11215 // incremental flip algorithm still works as usual. However, we must ensure //
11216 // that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
11217 // edge or face. Otherwise, the underlying space of the triangulation becomes//
11218 // non-manifold and it is not possible to flip further. //
11219 // Thanks to Joerg Rambau and Frank Lutz for helping in this issue. //
11220 // //
11222 
11224 {
11225  badface *popface;
11226  triface fliptets[5], *parytet;
11227  point *pts, *parypt, pe;
11228  REAL sign, ori;
11229  int flipcount = 0;
11230  int t1ver;
11231  int i;
11232 
11233  if (b->verbose > 2) {
11234  printf(" Lawson flip (%ld faces).\n", flippool->items);
11235  }
11236 
11237  if (hullflag) {
11238  // 'newpt' lies in the outside of the convex hull.
11239  // Mark all hull vertices which are connecting to it.
11240  popface = flipstack;
11241  while (popface != NULL) {
11242  pts = (point *) popface->tt.tet;
11243  for (i = 4; i < 8; i++) {
11244  if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
11245  if (!pinfected(pts[i])) {
11246  pinfect(pts[i]);
11247  cavetetvertlist->newindex((void **) &parypt);
11248  *parypt = pts[i];
11249  }
11250  }
11251  }
11252  popface = popface->nextitem;
11253  }
11254  }
11255 
11256  // Loop until the queue is empty.
11257  while (flipstack != NULL) {
11258 
11259  // Pop a face from the stack.
11260  popface = flipstack;
11261  fliptets[0] = popface->tt;
11262  flipstack = flipstack->nextitem; // The next top item in stack.
11263  flippool->dealloc((void *) popface);
11264 
11265  // Skip it if it is a dead tet (destroyed by previous flips).
11266  if (isdeadtet(fliptets[0])) continue;
11267  // Skip it if it is not the same tet as we saved.
11268  if (!facemarked(fliptets[0])) continue;
11269 
11270  unmarkface(fliptets[0]);
11271 
11272  if ((point) fliptets[0].tet[7] == dummypoint) {
11273  // It must be a hull edge.
11274  fliptets[0].ver = epivot[fliptets[0].ver];
11275  // A hull edge. The current convex hull may be enlarged.
11276  fsym(fliptets[0], fliptets[1]);
11277  pts = (point *) fliptets[1].tet;
11278  ori = orient3d(pts[4], pts[5], pts[6], newpt);
11279  if (ori < 0) {
11280  // Visible. The convex hull will be enlarged.
11281  // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
11282  // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
11283  enext(fliptets[1], fliptets[2]);
11284  eprev(fliptets[1], fliptets[3]);
11285  fnextself(fliptets[2]); // [a,c,e,*]
11286  fnextself(fliptets[3]); // [c,b,e,*]
11287  if (oppo(fliptets[2]) == newpt) {
11288  if (oppo(fliptets[3]) == newpt) {
11289  // Both tets exist! A 4-to-1 flip is found.
11290  terminatetetgen(this, 2); // Report a bug.
11291  } else {
11292  esym(fliptets[2], fliptets[0]);
11293  fnext(fliptets[0], fliptets[1]);
11294  fnext(fliptets[1], fliptets[2]);
11295  // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
11296  // This corresponds to my standard labels, where edge [e,d] is
11297  // repalced by face [a,b,c], and a is the new vertex.
11298  // [0] [c,a,d,e] (d = newpt)
11299  // [1] [c,a,e,b] (c = dummypoint)
11300  // [2] [c,a,b,d]
11301  flip32(fliptets, 1, fc);
11302  }
11303  } else {
11304  if (oppo(fliptets[3]) == newpt) {
11305  fnext(fliptets[3], fliptets[0]);
11306  fnext(fliptets[0], fliptets[1]);
11307  fnext(fliptets[1], fliptets[2]);
11308  // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
11309  // [0] [c,b,d,a] (d = newpt)
11310  // [1] [c,b,a,e] (c = dummypoint)
11311  // [2] [c,b,e,d]
11312  flip32(fliptets, 1, fc);
11313  } else {
11314  if (hullflag) {
11315  // Reject this flip if pe is already marked.
11316  pe = oppo(fliptets[1]);
11317  if (!pinfected(pe)) {
11318  pinfect(pe);
11319  cavetetvertlist->newindex((void **) &parypt);
11320  *parypt = pe;
11321  // Perform a 2-to-3 flip.
11322  flip23(fliptets, 1, fc);
11323  } else {
11324  // Reject this flip.
11325  flipcount--;
11326  }
11327  } else {
11328  // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
11329  // [0] [a,b,c,d], d = newpt.
11330  // [1] [b,a,c,e], c = dummypoint.
11331  flip23(fliptets, 1, fc);
11332  }
11333  }
11334  }
11335  flipcount++;
11336  }
11337  continue;
11338  } // if (dummypoint)
11339 
11340  fsym(fliptets[0], fliptets[1]);
11341  if ((point) fliptets[1].tet[7] == dummypoint) {
11342  // A hull face is locally Delaunay.
11343  continue;
11344  }
11345  // Check if the adjacent tet has already been tested.
11346  if (marktested(fliptets[1])) {
11347  // It has been tested and it is Delaunay.
11348  continue;
11349  }
11350 
11351  // Test whether the face is locally Delaunay or not.
11352  pts = (point *) fliptets[1].tet;
11353  if (b->weighted) {
11354  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
11355  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
11356  newpt[3]);
11357  } else {
11358  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
11359  }
11360 
11361 
11362  if (sign < 0) {
11363  point pd = newpt;
11364  point pe = oppo(fliptets[1]);
11365  // Check the convexity of its three edges. Stop checking either a
11366  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
11367  // encountered, and 'fliptet' represents that edge.
11368  for (i = 0; i < 3; i++) {
11369  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
11370  if (ori <= 0) break;
11371  enextself(fliptets[0]);
11372  }
11373  if (ori > 0) {
11374  // A 2-to-3 flip is found.
11375  // [0] [a,b,c,d],
11376  // [1] [b,a,c,e]. no dummypoint.
11377  flip23(fliptets, 0, fc);
11378  flipcount++;
11379  } else { // ori <= 0
11380  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
11381  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
11382  // Check if there are three or four tets sharing at this edge.
11383  esymself(fliptets[0]); // [b,a,d,c]
11384  for (i = 0; i < 3; i++) {
11385  fnext(fliptets[i], fliptets[i+1]);
11386  }
11387  if (fliptets[3].tet == fliptets[0].tet) {
11388  // A 3-to-2 flip is found. (No hull tet.)
11389  flip32(fliptets, 0, fc);
11390  flipcount++;
11391  } else {
11392  // There are more than 3 tets at this edge.
11393  fnext(fliptets[3], fliptets[4]);
11394  if (fliptets[4].tet == fliptets[0].tet) {
11395  if (ori == 0) {
11396  // A 4-to-4 flip is found. (Two hull tets may be involved.)
11397  // Current tets in 'fliptets':
11398  // [0] [b,a,d,c] (d may be newpt)
11399  // [1] [b,a,c,e]
11400  // [2] [b,a,e,f] (f may be dummypoint)
11401  // [3] [b,a,f,d]
11402  esymself(fliptets[0]); // [a,b,c,d]
11403  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
11404  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
11405  // It will be removed by the followed 3-to-2 flip.
11406  flip23(fliptets, 0, fc); // No hull tet.
11407  fnext(fliptets[3], fliptets[1]);
11408  fnext(fliptets[1], fliptets[2]);
11409  // Current tets in 'fliptets':
11410  // [0] [...]
11411  // [1] [b,a,d,e] (degenerated, d may be new point).
11412  // [2] [b,a,e,f] (f may be dummypoint)
11413  // [3] [b,a,f,d]
11414  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
11415  // Hull tets may be involved (f may be dummypoint).
11416  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
11417  flipcount++;
11418  }
11419  }
11420  }
11421  } // ori
11422  } else {
11423  // The adjacent tet is Delaunay. Mark it to avoid testing it again.
11424  marktest(fliptets[1]);
11425  // Save it for unmarking it later.
11426  cavebdrylist->newindex((void **) &parytet);
11427  *parytet = fliptets[1];
11428  }
11429 
11430  } // while (flipstack)
11431 
11432  // Unmark saved tetrahedra.
11433  for (i = 0; i < cavebdrylist->objects; i++) {
11434  parytet = (triface *) fastlookup(cavebdrylist, i);
11435  unmarktest(*parytet);
11436  }
11437  cavebdrylist->restart();
11438 
11439  if (hullflag) {
11440  // Unmark infected vertices.
11441  for (i = 0; i < cavetetvertlist->objects; i++) {
11442  parypt = (point *) fastlookup(cavetetvertlist, i);
11443  puninfect(*parypt);
11444  }
11446  }
11447 
11448 
11449  return flipcount;
11450 }
11451 
11453 // //
11454 // initialdelaunay() Create an initial Delaunay tetrahedralization. //
11455 // //
11456 // The tetrahedralization contains only one tetrahedron abcd, and four hull //
11457 // tetrahedra. The points pa, pb, pc, and pd must be linearly independent. //
11458 // //
11460 
11462 {
11463  triface firsttet, tetopa, tetopb, tetopc, tetopd;
11464  triface worktet, worktet1;
11465 
11466  if (b->verbose > 2) {
11467  printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
11468  pointmark(pb), pointmark(pc), pointmark(pd));
11469  }
11470 
11471  // Create the first tetrahedron.
11472  maketetrahedron(&firsttet);
11473  setvertices(firsttet, pa, pb, pc, pd);
11474  // Create four hull tetrahedra.
11475  maketetrahedron(&tetopa);
11476  setvertices(tetopa, pb, pc, pd, dummypoint);
11477  maketetrahedron(&tetopb);
11478  setvertices(tetopb, pc, pa, pd, dummypoint);
11479  maketetrahedron(&tetopc);
11480  setvertices(tetopc, pa, pb, pd, dummypoint);
11481  maketetrahedron(&tetopd);
11482  setvertices(tetopd, pb, pa, pc, dummypoint);
11483  hullsize += 4;
11484 
11485  // Connect hull tetrahedra to firsttet (at four faces of firsttet).
11486  bond(firsttet, tetopd);
11487  esym(firsttet, worktet);
11488  bond(worktet, tetopc); // ab
11489  enextesym(firsttet, worktet);
11490  bond(worktet, tetopa); // bc
11491  eprevesym(firsttet, worktet);
11492  bond(worktet, tetopb); // ca
11493 
11494  // Connect hull tetrahedra together (at six edges of firsttet).
11495  esym(tetopc, worktet);
11496  esym(tetopd, worktet1);
11497  bond(worktet, worktet1); // ab
11498  esym(tetopa, worktet);
11499  eprevesym(tetopd, worktet1);
11500  bond(worktet, worktet1); // bc
11501  esym(tetopb, worktet);
11502  enextesym(tetopd, worktet1);
11503  bond(worktet, worktet1); // ca
11504  eprevesym(tetopc, worktet);
11505  enextesym(tetopb, worktet1);
11506  bond(worktet, worktet1); // da
11507  eprevesym(tetopa, worktet);
11508  enextesym(tetopc, worktet1);
11509  bond(worktet, worktet1); // db
11510  eprevesym(tetopb, worktet);
11511  enextesym(tetopa, worktet1);
11512  bond(worktet, worktet1); // dc
11513 
11514  // Set the vertex type.
11515  if (pointtype(pa) == UNUSEDVERTEX) {
11516  setpointtype(pa, VOLVERTEX);
11517  }
11518  if (pointtype(pb) == UNUSEDVERTEX) {
11519  setpointtype(pb, VOLVERTEX);
11520  }
11521  if (pointtype(pc) == UNUSEDVERTEX) {
11522  setpointtype(pc, VOLVERTEX);
11523  }
11524  if (pointtype(pd) == UNUSEDVERTEX) {
11525  setpointtype(pd, VOLVERTEX);
11526  }
11527 
11528  setpoint2tet(pa, encode(firsttet));
11529  setpoint2tet(pb, encode(firsttet));
11530  setpoint2tet(pc, encode(firsttet));
11531  setpoint2tet(pd, encode(firsttet));
11532 
11533  // Remember the first tetrahedron.
11534  recenttet = firsttet;
11535 }
11536 
11538 // //
11539 // incrementaldelaunay() Create a Delaunay tetrahedralization by //
11540 // the incremental approach. //
11541 // //
11543 
11544 
11546 {
11547  triface searchtet;
11548  point *permutarray, swapvertex;
11549  REAL v1[3], v2[3], n[3];
11550  REAL bboxsize, bboxsize2, bboxsize3, ori;
11551  int randindex;
11552  int ngroup = 0;
11553  int i, j;
11554 
11555  if (!b->quiet) {
11556  printf("Delaunizing vertices...\n");
11557  }
11558 
11559  // Form a random permuation (uniformly at random) of the set of vertices.
11560  permutarray = new point[in->numberofpoints];
11561  points->traversalinit();
11562 
11563  if (b->no_sort) {
11564  if (b->verbose) {
11565  printf(" Using the input order.\n");
11566  }
11567  for (i = 0; i < in->numberofpoints; i++) {
11568  permutarray[i] = (point) points->traverse();
11569  }
11570  } else {
11571  if (b->verbose) {
11572  printf(" Permuting vertices.\n");
11573  }
11575  for (i = 0; i < in->numberofpoints; i++) {
11576  randindex = rand() % (i + 1); // randomnation(i + 1);
11577  permutarray[i] = permutarray[randindex];
11578  permutarray[randindex] = (point) points->traverse();
11579  }
11580  if (b->brio_hilbert) { // -b option
11581  if (b->verbose) {
11582  printf(" Sorting vertices.\n");
11583  }
11586  b->brio_ratio, &ngroup);
11587  }
11588  }
11589 
11590  tv = clock(); // Remember the time for sorting points.
11591 
11592  // Calculate the diagonal size of its bounding box.
11593  bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
11594  bboxsize2 = bboxsize * bboxsize;
11595  bboxsize3 = bboxsize2 * bboxsize;
11596 
11597  // Make sure the second vertex is not identical with the first one.
11598  i = 1;
11599  while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
11600  i++;
11601  if (i == in->numberofpoints - 1) {
11602  printf("Exception: All vertices are (nearly) identical (Tol = %g).\n",
11603  b->epsilon);
11604  terminatetetgen(this, 10);
11605  }
11606  }
11607  if (i > 1) {
11608  // Swap to move the non-identical vertex from index i to index 1.
11609  swapvertex = permutarray[i];
11610  permutarray[i] = permutarray[1];
11611  permutarray[1] = swapvertex;
11612  }
11613 
11614  // Make sure the third vertex is not collinear with the first two.
11615  // Acknowledgement: Thanks Jan Pomplun for his correction by using
11616  // epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
11617  i = 2;
11618  for (j = 0; j < 3; j++) {
11619  v1[j] = permutarray[1][j] - permutarray[0][j];
11620  v2[j] = permutarray[i][j] - permutarray[0][j];
11621  }
11622  cross(v1, v2, n);
11623  while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) <
11624  (b->epsilon * b->epsilon)) {
11625  i++;
11626  if (i == in->numberofpoints - 1) {
11627  printf("Exception: All vertices are (nearly) collinear (Tol = %g).\n",
11628  b->epsilon);
11629  terminatetetgen(this, 10);
11630  }
11631  for (j = 0; j < 3; j++) {
11632  v2[j] = permutarray[i][j] - permutarray[0][j];
11633  }
11634  cross(v1, v2, n);
11635  }
11636  if (i > 2) {
11637  // Swap to move the non-identical vertex from index i to index 1.
11638  swapvertex = permutarray[i];
11639  permutarray[i] = permutarray[2];
11640  permutarray[2] = swapvertex;
11641  }
11642 
11643  // Make sure the fourth vertex is not coplanar with the first three.
11644  i = 3;
11645  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11646  permutarray[i]);
11647  while ((fabs(ori) / bboxsize3) < (b->epsilon * b->epsilon * b->epsilon)) {
11648  i++;
11649  if (i == in->numberofpoints) {
11650  printf("Exception: All vertices are coplanar (Tol = %g).\n",
11651  b->epsilon);
11652  terminatetetgen(this, 10);
11653  }
11654  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11655  permutarray[i]);
11656  }
11657  if (i > 3) {
11658  // Swap to move the non-identical vertex from index i to index 1.
11659  swapvertex = permutarray[i];
11660  permutarray[i] = permutarray[3];
11661  permutarray[3] = swapvertex;
11662  }
11663 
11664  // Orient the first four vertices in permutarray so that they follow the
11665  // right-hand rule.
11666  if (ori > 0.0) {
11667  // Swap the first two vertices.
11668  swapvertex = permutarray[0];
11669  permutarray[0] = permutarray[1];
11670  permutarray[1] = swapvertex;
11671  }
11672 
11673  // Create the initial Delaunay tetrahedralization.
11674  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
11675  permutarray[3]);
11676 
11677  if (b->verbose) {
11678  printf(" Incrementally inserting vertices.\n");
11679  }
11680  insertvertexflags ivf;
11681  flipconstraints fc;
11682 
11683  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
11684  if (b->incrflip) {
11685  ivf.bowywat = 0;
11686  ivf.lawson = 1;
11687  fc.enqflag = 1;
11688  } else {
11689  ivf.bowywat = 1;
11690  ivf.lawson = 0;
11691  }
11692 
11693 
11694  for (i = 4; i < in->numberofpoints; i++) {
11695  if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
11696  setpointtype(permutarray[i], VOLVERTEX);
11697  }
11698  if (b->brio_hilbert || b->no_sort) { // -b or -b/1
11699  // Start the last updated tet.
11700  searchtet.tet = recenttet.tet;
11701  } else { // -b0
11702  // Randomly choose the starting tet for point location.
11703  searchtet.tet = NULL;
11704  }
11705  ivf.iloc = (int) OUTSIDE;
11706  // Insert the vertex.
11707  if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
11708  if (flipstack != NULL) {
11709  // Perform flip to recover Delaunayness.
11710  incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
11711  }
11712  } else {
11713  if (ivf.iloc == (int) ONVERTEX) {
11714  // The point already exists. Mark it and do nothing on it.
11715  swapvertex = org(searchtet);
11716  assert(swapvertex != permutarray[i]); // SELF_CHECK
11717  if (b->object != tetgenbehavior::STL) {
11718  if (!b->quiet) {
11719  printf("Warning: Point #%d is coincident with #%d. Ignored!\n",
11720  pointmark(permutarray[i]), pointmark(swapvertex));
11721  }
11722  }
11723  setpoint2ppt(permutarray[i], swapvertex);
11724  setpointtype(permutarray[i], DUPLICATEDVERTEX);
11725  dupverts++;
11726  } else if (ivf.iloc == (int) NEARVERTEX) {
11727  swapvertex = point2ppt(permutarray[i]);
11728  if (!b->quiet) {
11729  printf("Warning: Point %d is replaced by point %d.\n",
11730  pointmark(permutarray[i]), pointmark(swapvertex));
11731  printf(" Avoid creating a very short edge (len = %g) (< %g).\n",
11732  permutarray[i][3], b->minedgelength);
11733  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
11734  b->epsilon);
11735  printf(" or use the option -M0/1 to avoid such replacement.\n");
11736  }
11737  // Remember it is a duplicated point.
11738  setpointtype(permutarray[i], DUPLICATEDVERTEX);
11739  // Count the number of duplicated points.
11740  dupverts++;
11741  }
11742  }
11743  }
11744 
11745 
11746 
11747  delete [] permutarray;
11748 }
11749 
11753 
11757 
11759 // //
11760 // flipshpush() Push a facet edge into flip stack. //
11761 // //
11763 
11765 {
11766  badface *newflipface;
11767 
11768  newflipface = (badface *) flippool->alloc();
11769  newflipface->ss = *flipedge;
11770  newflipface->forg = sorg(*flipedge);
11771  newflipface->fdest = sdest(*flipedge);
11772  newflipface->nextitem = flipstack;
11773  flipstack = newflipface;
11774 }
11775 
11777 // //
11778 // flip22() Perform a 2-to-2 flip in surface mesh. //
11779 // //
11780 // 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and //
11781 // [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
11782 // is replaced by edge [c,d]. //
11783 // //
11785 
11786 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
11787 {
11788  face bdedges[4], outfaces[4], infaces[4];
11789  face bdsegs[4];
11790  face checkface;
11791  point pa, pb, pc, pd;
11792  int i;
11793 
11794  pa = sorg(flipfaces[0]);
11795  pb = sdest(flipfaces[0]);
11796  pc = sapex(flipfaces[0]);
11797  pd = sapex(flipfaces[1]);
11798 
11799  if (sorg(flipfaces[1]) != pb) {
11800  sesymself(flipfaces[1]);
11801  }
11802 
11803  flip22count++;
11804 
11805  // Collect the four boundary edges.
11806  senext(flipfaces[0], bdedges[0]);
11807  senext2(flipfaces[0], bdedges[1]);
11808  senext(flipfaces[1], bdedges[2]);
11809  senext2(flipfaces[1], bdedges[3]);
11810 
11811  // Collect outer boundary faces.
11812  for (i = 0; i < 4; i++) {
11813  spivot(bdedges[i], outfaces[i]);
11814  infaces[i] = outfaces[i];
11815  sspivot(bdedges[i], bdsegs[i]);
11816  if (outfaces[i].sh != NULL) {
11817  if (isshsubseg(bdedges[i])) {
11818  spivot(infaces[i], checkface);
11819  while (checkface.sh != bdedges[i].sh) {
11820  infaces[i] = checkface;
11821  spivot(infaces[i], checkface);
11822  }
11823  }
11824  }
11825  }
11826 
11827  // The flags set in these two subfaces do not change.
11828  // Shellmark does not change.
11829  // area constraint does not change.
11830 
11831  // Transform [a,b,c] -> [c,d,b].
11832  setshvertices(flipfaces[0], pc, pd, pb);
11833  // Transform [b,a,d] -> [d,c,a].
11834  setshvertices(flipfaces[1], pd, pc, pa);
11835 
11836  // Update the point-to-subface map.
11837  if (pointtype(pa) == FREEFACETVERTEX) {
11838  setpoint2sh(pa, sencode(flipfaces[1]));
11839  }
11840  if (pointtype(pb) == FREEFACETVERTEX) {
11841  setpoint2sh(pb, sencode(flipfaces[0]));
11842  }
11843  if (pointtype(pc) == FREEFACETVERTEX) {
11844  setpoint2sh(pc, sencode(flipfaces[0]));
11845  }
11846  if (pointtype(pd) == FREEFACETVERTEX) {
11847  setpoint2sh(pd, sencode(flipfaces[0]));
11848  }
11849 
11850  // Reconnect boundary edges to outer boundary faces.
11851  for (i = 0; i < 4; i++) {
11852  if (outfaces[(3 + i) % 4].sh != NULL) {
11853  // Make sure that the subface has the ori as the segment.
11854  if (bdsegs[(3 + i) % 4].sh != NULL) {
11855  bdsegs[(3 + i) % 4].shver = 0;
11856  if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
11857  sesymself(bdedges[i]);
11858  }
11859  }
11860  sbond1(bdedges[i], outfaces[(3 + i) % 4]);
11861  sbond1(infaces[(3 + i) % 4], bdedges[i]);
11862  } else {
11863  sdissolve(bdedges[i]);
11864  }
11865  if (bdsegs[(3 + i) % 4].sh != NULL) {
11866  ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
11867  if (chkencflag & 1) {
11868  // Queue this segment for encroaching check.
11869  enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
11870  }
11871  } else {
11872  ssdissolve(bdedges[i]);
11873  }
11874  }
11875 
11876  if (chkencflag & 2) {
11877  // Queue the flipped subfaces for quality/encroaching checks.
11878  for (i = 0; i < 2; i++) {
11879  enqueuesubface(badsubfacs, &(flipfaces[i]));
11880  }
11881  }
11882 
11883  recentsh = flipfaces[0];
11884 
11885  if (flipflag) {
11886  // Put the boundary edges into flip stack.
11887  for (i = 0; i < 4; i++) {
11888  flipshpush(&(bdedges[i]));
11889  }
11890  }
11891 }
11892 
11894 // //
11895 // flip31() Remove a vertex by transforming 3-to-1 subfaces. //
11896 // //
11897 // 'flipfaces' is an array of subfaces. Its length is at least 4. On input, //
11898 // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine //
11899 // replaces them by one face [a,b,c], it is returned in flipfaces[3]. //
11900 // //
11901 // NOTE: The three old subfaces are not deleted within this routine. They //
11902 // still hold pointers to their adjacent subfaces. These informations are //
11903 // needed by the routine 'sremovevertex()' for recovering a segment. //
11904 // The caller of this routine must delete the old subfaces after their uses. //
11905 // //
11907 
11908 void tetgenmesh::flip31(face* flipfaces, int flipflag)
11909 {
11910  face bdedges[3], outfaces[3], infaces[3];
11911  face bdsegs[3];
11912  face checkface;
11913  point pa, pb, pc;
11914  int i;
11915 
11916  pa = sdest(flipfaces[0]);
11917  pb = sdest(flipfaces[1]);
11918  pc = sdest(flipfaces[2]);
11919 
11920  flip31count++;
11921 
11922  // Collect all infos at the three boundary edges.
11923  for (i = 0; i < 3; i++) {
11924  senext(flipfaces[i], bdedges[i]);
11925  spivot(bdedges[i], outfaces[i]);
11926  infaces[i] = outfaces[i];
11927  sspivot(bdedges[i], bdsegs[i]);
11928  if (outfaces[i].sh != NULL) {
11929  if (isshsubseg(bdedges[i])) {
11930  spivot(infaces[i], checkface);
11931  while (checkface.sh != bdedges[i].sh) {
11932  infaces[i] = checkface;
11933  spivot(infaces[i], checkface);
11934  }
11935  }
11936  }
11937  } // i
11938 
11939  // Create a new subface.
11940  makeshellface(subfaces, &(flipfaces[3]));
11941  setshvertices(flipfaces[3], pa, pb,pc);
11942  setshellmark(flipfaces[3], shellmark(flipfaces[0]));
11943  if (checkconstraints) {
11944  //area = areabound(flipfaces[0]);
11945  setareabound(flipfaces[3], areabound(flipfaces[0]));
11946  }
11947  if (useinsertradius) {
11948  setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
11949  }
11950 
11951  // Update the point-to-subface map.
11952  if (pointtype(pa) == FREEFACETVERTEX) {
11953  setpoint2sh(pa, sencode(flipfaces[3]));
11954  }
11955  if (pointtype(pb) == FREEFACETVERTEX) {
11956  setpoint2sh(pb, sencode(flipfaces[3]));
11957  }
11958  if (pointtype(pc) == FREEFACETVERTEX) {
11959  setpoint2sh(pc, sencode(flipfaces[3]));
11960  }
11961 
11962  // Update the three new boundary edges.
11963  bdedges[0] = flipfaces[3]; // [a,b]
11964  senext(flipfaces[3], bdedges[1]); // [b,c]
11965  senext2(flipfaces[3], bdedges[2]); // [c,a]
11966 
11967  // Reconnect boundary edges to outer boundary faces.
11968  for (i = 0; i < 3; i++) {
11969  if (outfaces[i].sh != NULL) {
11970  // Make sure that the subface has the ori as the segment.
11971  if (bdsegs[i].sh != NULL) {
11972  bdsegs[i].shver = 0;
11973  if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
11974  sesymself(bdedges[i]);
11975  }
11976  }
11977  sbond1(bdedges[i], outfaces[i]);
11978  sbond1(infaces[i], bdedges[i]);
11979  }
11980  if (bdsegs[i].sh != NULL) {
11981  ssbond(bdedges[i], bdsegs[i]);
11982  }
11983  }
11984 
11985  recentsh = flipfaces[3];
11986 
11987  if (flipflag) {
11988  // Put the boundary edges into flip stack.
11989  for (i = 0; i < 3; i++) {
11990  flipshpush(&(bdedges[i]));
11991  }
11992  }
11993 }
11994 
11996 // //
11997 // lawsonflip() Flip non-locally Delaunay edges. //
11998 // //
12000 
12002 {
12003  badface *popface;
12004  face flipfaces[2];
12005  point pa, pb, pc, pd;
12006  REAL sign;
12007  long flipcount = 0;
12008 
12009  if (b->verbose > 2) {
12010  printf(" Lawson flip %ld edges.\n", flippool->items);
12011  }
12012 
12013  while (flipstack != (badface *) NULL) {
12014 
12015  // Pop an edge from the stack.
12016  popface = flipstack;
12017  flipfaces[0] = popface->ss;
12018  pa = popface->forg;
12019  pb = popface->fdest;
12020  flipstack = popface->nextitem; // The next top item in stack.
12021  flippool->dealloc((void *) popface);
12022 
12023  // Skip it if it is dead.
12024  if (flipfaces[0].sh[3] == NULL) continue;
12025  // Skip it if it is not the same edge as we saved.
12026  if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
12027  // Skip it if it is a subsegment.
12028  if (isshsubseg(flipfaces[0])) continue;
12029 
12030  // Get the adjacent face.
12031  spivot(flipfaces[0], flipfaces[1]);
12032  if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
12033  pc = sapex(flipfaces[0]);
12034  pd = sapex(flipfaces[1]);
12035 
12036  sign = incircle3d(pa, pb, pc, pd);
12037 
12038  if (sign < 0) {
12039  // It is non-locally Delaunay. Flip it.
12040  flip22(flipfaces, 1, 0);
12041  flipcount++;
12042  }
12043  }
12044 
12045  if (b->verbose > 2) {
12046  printf(" Performed %ld flips.\n", flipcount);
12047  }
12048 
12049  return flipcount;
12050 }
12051 
12053 // //
12054 // sinsertvertex() Insert a vertex into a triangulation of a facet. //
12055 // //
12056 // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
12057 // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p), //
12058 // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a //
12059 // segment, 'cavesegshlist' returns the two new subsegments. //
12060 // //
12061 // 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
12062 // will first locate the point. It starts searching from 'searchsh' or 'rec- //
12063 // entsh' if 'searchsh' is NULL. //
12064 // //
12065 // If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert //
12066 // the vertex. Otherwise, only insert the vertex in the initial cavity. //
12067 // //
12068 // If 'iloc' is 'INSTAR', this means the cavity of this vertex was already //
12069 // provided in the list 'caveshlist'. //
12070 // //
12071 // If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
12072 // be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'. //
12073 // //
12074 // 'rflag' (rounding) is a parameter passed to slocate() function. If it is //
12075 // set, after the location of the point is found, either ONEDGE or ONFACE, //
12076 // round the result using an epsilon. //
12077 // //
12078 // NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
12079 // want to remove the new point immediately. //
12080 // //
12082 
12083 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
12084  int iloc, int bowywat, int rflag)
12085 {
12086  face cavesh, neighsh, *parysh;
12087  face newsh, casout, casin;
12088  face checkseg;
12089  point pa, pb;
12090  enum locateresult loc = OUTSIDE;
12091  REAL sign, ori;
12092  int i, j;
12093 
12094  if (b->verbose > 2) {
12095  printf(" Insert facet point %d.\n", pointmark(insertpt));
12096  }
12097 
12098  if (bowywat == 3) {
12099  loc = INSTAR;
12100  }
12101 
12102  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12103  // A segment is going to be split, no point location.
12104  spivot(*splitseg, *searchsh);
12105  if (loc != INSTAR) loc = ONEDGE;
12106  } else {
12107  if (loc != INSTAR) loc = (enum locateresult) iloc;
12108  if (loc == OUTSIDE) {
12109  // Do point location in surface mesh.
12110  if (searchsh->sh == NULL) {
12111  *searchsh = recentsh;
12112  }
12113  // Search the vertex. An above point must be provided ('aflag' = 1).
12114  loc = slocate(insertpt, searchsh, 1, 1, rflag);
12115  }
12116  }
12117 
12118 
12119  // Form the initial sC(p).
12120  if (loc == ONFACE) {
12121  // Add the face into list (in B-W cavity).
12122  smarktest(*searchsh);
12123  caveshlist->newindex((void **) &parysh);
12124  *parysh = *searchsh;
12125  } else if (loc == ONEDGE) {
12126  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12127  splitseg->shver = 0;
12128  pa = sorg(*splitseg);
12129  } else {
12130  pa = sorg(*searchsh);
12131  }
12132  if (searchsh->sh != NULL) {
12133  // Collect all subfaces share at this edge.
12134  neighsh = *searchsh;
12135  while (1) {
12136  // Adjust the origin of its edge to be 'pa'.
12137  if (sorg(neighsh) != pa) sesymself(neighsh);
12138  // Add this face into list (in B-W cavity).
12139  smarktest(neighsh);
12140  caveshlist->newindex((void **) &parysh);
12141  *parysh = neighsh;
12142  // Add this face into face-at-splitedge list.
12143  cavesegshlist->newindex((void **) &parysh);
12144  *parysh = neighsh;
12145  // Go to the next face at the edge.
12146  spivotself(neighsh);
12147  // Stop if all faces at the edge have been visited.
12148  if (neighsh.sh == searchsh->sh) break;
12149  if (neighsh.sh == NULL) break;
12150  }
12151  } // If (not a non-dangling segment).
12152  } else if (loc == ONVERTEX) {
12153  return (int) loc;
12154  } else if (loc == OUTSIDE) {
12155  // Comment: This should only happen during the surface meshing step.
12156  // Enlarge the convex hull of the triangulation by including p.
12157  // An above point of the facet is set in 'dummypoint' to replace
12158  // orient2d tests by orient3d tests.
12159  // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
12160  // plane, and a->b is directed from left to right, p lies above a->b.
12161  // Find the right-most edge of the triangulation which is visible by p.
12162  neighsh = *searchsh;
12163  while (1) {
12164  senext2self(neighsh);
12165  spivot(neighsh, casout);
12166  if (casout.sh == NULL) {
12167  // A convex hull edge. Is it visible by p.
12168  ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
12169  if (ori < 0) {
12170  *searchsh = neighsh; // Visible, update 'searchsh'.
12171  } else {
12172  break; // 'searchsh' is the right-most visible edge.
12173  }
12174  } else {
12175  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12176  neighsh = casout;
12177  }
12178  }
12179  // Create new triangles for all visible edges of p (from right to left).
12180  casin.sh = NULL; // No adjacent face at right.
12181  pa = sorg(*searchsh);
12182  pb = sdest(*searchsh);
12183  while (1) {
12184  // Create a new subface on top of the (visible) edge.
12185  makeshellface(subfaces, &newsh);
12186  setshvertices(newsh, pb, pa, insertpt);
12187  setshellmark(newsh, shellmark(*searchsh));
12188  if (checkconstraints) {
12189  //area = areabound(*searchsh);
12190  setareabound(newsh, areabound(*searchsh));
12191  }
12192  if (useinsertradius) {
12193  setfacetindex(newsh, getfacetindex(*searchsh));
12194  }
12195  // Connect the new subface to the bottom subfaces.
12196  sbond1(newsh, *searchsh);
12197  sbond1(*searchsh, newsh);
12198  // Connect the new subface to its right-adjacent subface.
12199  if (casin.sh != NULL) {
12200  senext(newsh, casout);
12201  sbond1(casout, casin);
12202  sbond1(casin, casout);
12203  }
12204  // The left-adjacent subface has not been created yet.
12205  senext2(newsh, casin);
12206  // Add the new face into list (inside the B-W cavity).
12207  smarktest(newsh);
12208  caveshlist->newindex((void **) &parysh);
12209  *parysh = newsh;
12210  // Move to the convex hull edge at the left of 'searchsh'.
12211  neighsh = *searchsh;
12212  while (1) {
12213  senextself(neighsh);
12214  spivot(neighsh, casout);
12215  if (casout.sh == NULL) {
12216  *searchsh = neighsh;
12217  break;
12218  }
12219  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12220  neighsh = casout;
12221  }
12222  // A convex hull edge. Is it visible by p.
12223  pa = sorg(*searchsh);
12224  pb = sdest(*searchsh);
12225  ori = orient3d(pa, pb, dummypoint, insertpt);
12226  // Finish the process if p is not visible by the hull edge.
12227  if (ori >= 0) break;
12228  }
12229  } else if (loc == INSTAR) {
12230  // Under this case, the sub-cavity sC(p) has already been formed in
12231  // insertvertex().
12232  }
12233 
12234  // Form the Bowyer-Watson cavity sC(p).
12235  for (i = 0; i < caveshlist->objects; i++) {
12236  cavesh = * (face *) fastlookup(caveshlist, i);
12237  for (j = 0; j < 3; j++) {
12238  if (!isshsubseg(cavesh)) {
12239  spivot(cavesh, neighsh);
12240  if (neighsh.sh != NULL) {
12241  // The adjacent face exists.
12242  if (!smarktested(neighsh)) {
12243  if (bowywat) {
12244  if (loc == INSTAR) { // if (bowywat > 2) {
12245  // It must be a boundary edge.
12246  sign = 1;
12247  } else {
12248  // Check if this subface is connected to adjacent tet(s).
12249  if (!isshtet(neighsh)) {
12250  // Check if the subface is non-Delaunay wrt. the new pt.
12251  sign = incircle3d(sorg(neighsh), sdest(neighsh),
12252  sapex(neighsh), insertpt);
12253  } else {
12254  // It is connected to an adjacent tet. A boundary edge.
12255  sign = 1;
12256  }
12257  }
12258  if (sign < 0) {
12259  // Add the adjacent face in list (in B-W cavity).
12260  smarktest(neighsh);
12261  caveshlist->newindex((void **) &parysh);
12262  *parysh = neighsh;
12263  }
12264  } else {
12265  sign = 1; // A boundary edge.
12266  }
12267  } else {
12268  sign = -1; // Not a boundary edge.
12269  }
12270  } else {
12271  // No adjacent face. It is a hull edge.
12272  if (loc == OUTSIDE) {
12273  // It is a boundary edge if it does not contain p.
12274  if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
12275  sign = -1; // Not a boundary edge.
12276  } else {
12277  sign = 1; // A boundary edge.
12278  }
12279  } else {
12280  sign = 1; // A boundary edge.
12281  }
12282  }
12283  } else {
12284  // Do not across a segment. It is a boundary edge.
12285  sign = 1;
12286  }
12287  if (sign >= 0) {
12288  // Add a boundary edge.
12289  caveshbdlist->newindex((void **) &parysh);
12290  *parysh = cavesh;
12291  }
12292  senextself(cavesh);
12293  } // j
12294  } // i
12295 
12296 
12297  // Creating new subfaces.
12298  for (i = 0; i < caveshbdlist->objects; i++) {
12299  parysh = (face *) fastlookup(caveshbdlist, i);
12300  sspivot(*parysh, checkseg);
12301  if ((parysh->shver & 01) != 0) sesymself(*parysh);
12302  pa = sorg(*parysh);
12303  pb = sdest(*parysh);
12304  // Create a new subface.
12305  makeshellface(subfaces, &newsh);
12306  setshvertices(newsh, pa, pb, insertpt);
12307  setshellmark(newsh, shellmark(*parysh));
12308  if (checkconstraints) {
12309  //area = areabound(*parysh);
12310  setareabound(newsh, areabound(*parysh));
12311  }
12312  if (useinsertradius) {
12313  setfacetindex(newsh, getfacetindex(*parysh));
12314  }
12315  // Update the point-to-subface map.
12316  if (pointtype(pa) == FREEFACETVERTEX) {
12317  setpoint2sh(pa, sencode(newsh));
12318  }
12319  if (pointtype(pb) == FREEFACETVERTEX) {
12320  setpoint2sh(pb, sencode(newsh));
12321  }
12322  // Connect newsh to outer subfaces.
12323  spivot(*parysh, casout);
12324  if (casout.sh != NULL) {
12325  casin = casout;
12326  if (checkseg.sh != NULL) {
12327  // Make sure that newsh has the right ori at this segment.
12328  checkseg.shver = 0;
12329  if (sorg(newsh) != sorg(checkseg)) {
12330  sesymself(newsh);
12331  sesymself(*parysh); // This side should also be inverse.
12332  }
12333  spivot(casin, neighsh);
12334  while (neighsh.sh != parysh->sh) {
12335  casin = neighsh;
12336  spivot(casin, neighsh);
12337  }
12338  }
12339  sbond1(newsh, casout);
12340  sbond1(casin, newsh);
12341  }
12342  if (checkseg.sh != NULL) {
12343  ssbond(newsh, checkseg);
12344  }
12345  // Connect oldsh <== newsh (for connecting adjacent new subfaces).
12346  // *parysh and newsh point to the same edge and the same ori.
12347  sbond1(*parysh, newsh);
12348  }
12349 
12350  if (newsh.sh != NULL) {
12351  // Set a handle for searching.
12352  recentsh = newsh;
12353  }
12354 
12355  // Update the point-to-subface map.
12356  if (pointtype(insertpt) == FREEFACETVERTEX) {
12357  setpoint2sh(insertpt, sencode(newsh));
12358  }
12359 
12360  // Connect adjacent new subfaces together.
12361  for (i = 0; i < caveshbdlist->objects; i++) {
12362  // Get an old subface at edge [a, b].
12363  parysh = (face *) fastlookup(caveshbdlist, i);
12364  spivot(*parysh, newsh); // The new subface [a, b, p].
12365  senextself(newsh); // At edge [b, p].
12366  spivot(newsh, neighsh);
12367  if (neighsh.sh == NULL) {
12368  // Find the adjacent new subface at edge [b, p].
12369  pb = sdest(*parysh);
12370  neighsh = *parysh;
12371  while (1) {
12372  senextself(neighsh);
12373  spivotself(neighsh);
12374  if (neighsh.sh == NULL) break;
12375  if (!smarktested(neighsh)) break;
12376  if (sdest(neighsh) != pb) sesymself(neighsh);
12377  }
12378  if (neighsh.sh != NULL) {
12379  // Now 'neighsh' is a new subface at edge [b, #].
12380  if (sorg(neighsh) != pb) sesymself(neighsh);
12381  senext2self(neighsh); // Go to the open edge [p, b].
12382  sbond(newsh, neighsh);
12383  } else {
12384  // There is no adjacent new face at this side.
12385  assert(loc == OUTSIDE); // SELF_CHECK
12386  }
12387  }
12388  spivot(*parysh, newsh); // The new subface [a, b, p].
12389  senext2self(newsh); // At edge [p, a].
12390  spivot(newsh, neighsh);
12391  if (neighsh.sh == NULL) {
12392  // Find the adjacent new subface at edge [p, a].
12393  pa = sorg(*parysh);
12394  neighsh = *parysh;
12395  while (1) {
12396  senext2self(neighsh);
12397  spivotself(neighsh);
12398  if (neighsh.sh == NULL) break;
12399  if (!smarktested(neighsh)) break;
12400  if (sorg(neighsh) != pa) sesymself(neighsh);
12401  }
12402  if (neighsh.sh != NULL) {
12403  // Now 'neighsh' is a new subface at edge [#, a].
12404  if (sdest(neighsh) != pa) sesymself(neighsh);
12405  senextself(neighsh); // Go to the open edge [a, p].
12406  sbond(newsh, neighsh);
12407  } else {
12408  // There is no adjacent new face at this side.
12409  assert(loc == OUTSIDE); // SELF_CHECK
12410  }
12411  }
12412  }
12413 
12414  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
12415  || (cavesegshlist->objects > 0l)) {
12416  // An edge is being split. We distinguish two cases:
12417  // (1) the edge is not on the boundary of the cavity;
12418  // (2) the edge is on the boundary of the cavity.
12419  // In case (2), the edge is either a segment or a hull edge. There are
12420  // degenerated new faces in the cavity. They must be removed.
12421  face aseg, bseg, aoutseg, boutseg;
12422 
12423  for (i = 0; i < cavesegshlist->objects; i++) {
12424  // Get the saved old subface.
12425  parysh = (face *) fastlookup(cavesegshlist, i);
12426  // Get a possible new degenerated subface.
12427  spivot(*parysh, cavesh);
12428  if (sapex(cavesh) == insertpt) {
12429  // Found a degenerated new subface, i.e., case (2).
12430  if (cavesegshlist->objects > 1) {
12431  // There are more than one subface share at this edge.
12432  j = (i + 1) % (int) cavesegshlist->objects;
12433  parysh = (face *) fastlookup(cavesegshlist, j);
12434  spivot(*parysh, neighsh);
12435  // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
12436  if (sorg(neighsh) != sorg(cavesh)) {
12437  sesymself(neighsh);
12438  assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK
12439  }
12440  assert(sapex(neighsh) == insertpt); // SELF_CHECK
12441  // Connect adjacent faces at two other edges of cavesh and neighsh.
12442  // As a result, the two degenerated new faces are squeezed from the
12443  // new triangulation of the cavity. Note that the squeezed faces
12444  // still hold the adjacent informations which will be used in
12445  // re-connecting subsegments (if they exist).
12446  for (j = 0; j < 2; j++) {
12447  senextself(cavesh);
12448  senextself(neighsh);
12449  spivot(cavesh, newsh);
12450  spivot(neighsh, casout);
12451  sbond1(newsh, casout); // newsh <- casout.
12452  }
12453  } else {
12454  // There is only one subface containing this edge [a,b]. Squeeze the
12455  // degenerated new face [a,b,c] by disconnecting it from its two
12456  // adjacent subfaces at edges [b,c] and [c,a]. Note that the face
12457  // [a,b,c] still hold the connection to them.
12458  for (j = 0; j < 2; j++) {
12459  senextself(cavesh);
12460  spivot(cavesh, newsh);
12461  sdissolve(newsh);
12462  }
12463  }
12464  //recentsh = newsh;
12465  // Update the point-to-subface map.
12466  if (pointtype(insertpt) == FREEFACETVERTEX) {
12467  setpoint2sh(insertpt, sencode(newsh));
12468  }
12469  }
12470  }
12471 
12472  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12473  if (loc != INSTAR) { // if (bowywat < 3) {
12474  smarktest(*splitseg); // Mark it as being processed.
12475  }
12476 
12477  aseg = *splitseg;
12478  pa = sorg(*splitseg);
12479  pb = sdest(*splitseg);
12480 
12481  // Insert the new point p.
12482  makeshellface(subsegs, &aseg);
12483  makeshellface(subsegs, &bseg);
12484 
12485  setshvertices(aseg, pa, insertpt, NULL);
12486  setshvertices(bseg, insertpt, pb, NULL);
12487  setshellmark(aseg, shellmark(*splitseg));
12488  setshellmark(bseg, shellmark(*splitseg));
12489  if (checkconstraints) {
12490  setareabound(aseg, areabound(*splitseg));
12491  setareabound(bseg, areabound(*splitseg));
12492  }
12493  if (useinsertradius) {
12494  setfacetindex(aseg, getfacetindex(*splitseg));
12495  setfacetindex(bseg, getfacetindex(*splitseg));
12496  }
12497 
12498  // Connect [#, a]<->[a, p].
12499  senext2(*splitseg, boutseg); // Temporarily use boutseg.
12500  spivotself(boutseg);
12501  if (boutseg.sh != NULL) {
12502  senext2(aseg, aoutseg);
12503  sbond(boutseg, aoutseg);
12504  }
12505  // Connect [p, b]<->[b, #].
12506  senext(*splitseg, aoutseg);
12507  spivotself(aoutseg);
12508  if (aoutseg.sh != NULL) {
12509  senext(bseg, boutseg);
12510  sbond(boutseg, aoutseg);
12511  }
12512  // Connect [a, p] <-> [p, b].
12513  senext(aseg, aoutseg);
12514  senext2(bseg, boutseg);
12515  sbond(aoutseg, boutseg);
12516 
12517  // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
12518  // Although the degenerated new faces have been squeezed. They still
12519  // hold the connections to the actual new faces.
12520  for (i = 0; i < cavesegshlist->objects; i++) {
12521  parysh = (face *) fastlookup(cavesegshlist, i);
12522  spivot(*parysh, neighsh);
12523  // neighsh is a degenerated new face.
12524  if (sorg(neighsh) != pa) {
12525  sesymself(neighsh);
12526  }
12527  senext2(neighsh, newsh);
12528  spivotself(newsh); // The edge [p, a] in newsh
12529  ssbond(newsh, aseg);
12530  senext(neighsh, newsh);
12531  spivotself(newsh); // The edge [b, p] in newsh
12532  ssbond(newsh, bseg);
12533  }
12534 
12535 
12536  // Let the point remember the segment it lies on.
12537  if (pointtype(insertpt) == FREESEGVERTEX) {
12538  setpoint2sh(insertpt, sencode(aseg));
12539  }
12540  // Update the point-to-seg map.
12541  if (pointtype(pa) == FREESEGVERTEX) {
12542  setpoint2sh(pa, sencode(aseg));
12543  }
12544  if (pointtype(pb) == FREESEGVERTEX) {
12545  setpoint2sh(pb, sencode(bseg));
12546  }
12547  } // if ((splitseg != NULL) && (splitseg->sh != NULL))
12548 
12549  // Delete all degenerated new faces.
12550  for (i = 0; i < cavesegshlist->objects; i++) {
12551  parysh = (face *) fastlookup(cavesegshlist, i);
12552  spivotself(*parysh);
12553  if (sapex(*parysh) == insertpt) {
12554  shellfacedealloc(subfaces, parysh->sh);
12555  }
12556  }
12558 
12559  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12560  // Return the two new subsegments (for further process).
12561  // Re-use 'cavesegshlist'.
12562  cavesegshlist->newindex((void **) &parysh);
12563  *parysh = aseg;
12564  cavesegshlist->newindex((void **) &parysh);
12565  *parysh = bseg;
12566  }
12567  } // if (loc == ONEDGE)
12568 
12569 
12570  return (int) loc;
12571 }
12572 
12574 // //
12575 // sremovevertex() Remove a vertex from the surface mesh. //
12576 // //
12577 // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
12578 // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a //
12579 // facet vertex, and the origin of 'parentsh' is p. //
12580 // //
12581 // Within each facet, we first use a sequence of 2-to-2 flips to flip any //
12582 // edge at p, finally use a 3-to-1 flip to remove p. //
12583 // //
12584 // All new created subfaces are returned in the global array 'caveshbdlist'. //
12585 // The new segment (when p is on segment) is returned in 'parentseg'. //
12586 // //
12587 // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay- //
12588 // ness after p is removed. //
12589 // //
12591 
12592 int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
12593  int lawson)
12594 {
12595  face flipfaces[4], spinsh, *parysh;
12596  point pa, pb, pc, pd;
12597  REAL ori1, ori2;
12598  int it, i, j;
12599 
12600  if (parentseg != NULL) {
12601  // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
12602  // where 'parentseg' should be [p,b]. Find the segment [a,p].
12603  face startsh, neighsh, nextsh;
12604  face abseg, prevseg, checkseg;
12605  face adjseg1, adjseg2;
12606  face fakesh;
12607  senext2(*parentseg, prevseg);
12608  spivotself(prevseg);
12609  prevseg.shver = 0;
12610  assert(sdest(prevseg) == delpt);
12611  // Restore the original segment [a,b].
12612  pa = sorg(prevseg);
12613  pb = sdest(*parentseg);
12614  if (b->verbose > 2) {
12615  printf(" Remove vertex %d from segment [%d, %d].\n",
12616  pointmark(delpt), pointmark(pa), pointmark(pb));
12617  }
12618  makeshellface(subsegs, &abseg);
12619  setshvertices(abseg, pa, pb, NULL);
12620  setshellmark(abseg, shellmark(*parentseg));
12621  if (checkconstraints) {
12622  setareabound(abseg, areabound(*parentseg));
12623  }
12624  if (useinsertradius) {
12625  setfacetindex(abseg, getfacetindex(*parentseg));
12626  }
12627  // Connect [#, a]<->[a, b].
12628  senext2(prevseg, adjseg1);
12629  spivotself(adjseg1);
12630  if (adjseg1.sh != NULL) {
12631  adjseg1.shver = 0;
12632  assert(sdest(adjseg1) == pa);
12633  senextself(adjseg1);
12634  senext2(abseg, adjseg2);
12635  sbond(adjseg1, adjseg2);
12636  }
12637  // Connect [a, b]<->[b, #].
12638  senext(*parentseg, adjseg1);
12639  spivotself(adjseg1);
12640  if (adjseg1.sh != NULL) {
12641  adjseg1.shver = 0;
12642  assert(sorg(adjseg1) == pb);
12643  senext2self(adjseg1);
12644  senext(abseg, adjseg2);
12645  sbond(adjseg1, adjseg2);
12646  }
12647  // Update the point-to-segment map.
12648  setpoint2sh(pa, sencode(abseg));
12649  setpoint2sh(pb, sencode(abseg));
12650 
12651  // Get the faces in face ring at segment [p, b].
12652  // Re-use array 'caveshlist'.
12653  spivot(*parentseg, *parentsh);
12654  if (parentsh->sh != NULL) {
12655  spinsh = *parentsh;
12656  while (1) {
12657  // Save this face in list.
12658  caveshlist->newindex((void **) &parysh);
12659  *parysh = spinsh;
12660  // Go to the next face in the ring.
12661  spivotself(spinsh);
12662  if (spinsh.sh == parentsh->sh) break;
12663  }
12664  }
12665 
12666  // Create the face ring of the new segment [a,b]. Each face in the ring
12667  // is [a,b,p] (degenerated!). It will be removed (automatically).
12668  for (i = 0; i < caveshlist->objects; i++) {
12669  parysh = (face *) fastlookup(caveshlist, i);
12670  startsh = *parysh;
12671  if (sorg(startsh) != delpt) {
12672  sesymself(startsh);
12673  assert(sorg(startsh) == delpt);
12674  }
12675  // startsh is [p, b, #1], find the subface [a, p, #2].
12676  neighsh = startsh;
12677  while (1) {
12678  senext2self(neighsh);
12679  sspivot(neighsh, checkseg);
12680  if (checkseg.sh != NULL) {
12681  // It must be the segment [a, p].
12682  assert(checkseg.sh == prevseg.sh);
12683  break;
12684  }
12685  spivotself(neighsh);
12686  assert(neighsh.sh != NULL);
12687  if (sorg(neighsh) != delpt) sesymself(neighsh);
12688  }
12689  // Now neighsh is [a, p, #2].
12690  if (neighsh.sh != startsh.sh) {
12691  // Detach the two subsegments [a,p] and [p,b] from subfaces.
12692  ssdissolve(startsh);
12693  ssdissolve(neighsh);
12694  // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
12695  // new segment [a,b]; (2) connect to the two adjacent subfaces
12696  // [p,b,#] and [a,p,#].
12697  makeshellface(subfaces, &fakesh);
12698  setshvertices(fakesh, pa, pb, delpt);
12699  setshellmark(fakesh, shellmark(startsh));
12700  // Connect fakesh to the segment [a,b].
12701  ssbond(fakesh, abseg);
12702  // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
12703  senext(fakesh, nextsh);
12704  sbond(nextsh, startsh);
12705  senext2(fakesh, nextsh);
12706  sbond(nextsh, neighsh);
12707  smarktest(fakesh); // Mark it as faked.
12708  } else {
12709  // Special case. There exists already a degenerated face [a,b,p]!
12710  // There is no need to create a faked subface here.
12711  senext2self(neighsh); // [a,b,p]
12712  assert(sapex(neighsh) == delpt);
12713  // Since we will re-connect the face ring using the faked subfaces.
12714  // We put the adjacent face of [a,b,p] to the list.
12715  spivot(neighsh, startsh); // The original adjacent subface.
12716  if (sorg(startsh) != pa) sesymself(startsh);
12717  sdissolve(startsh);
12718  // Connect fakesh to the segment [a,b].
12719  ssbond(startsh, abseg);
12720  fakesh = startsh; // Do not mark it!
12721  // Delete the degenerated subface.
12722  shellfacedealloc(subfaces, neighsh.sh);
12723  }
12724  // Save the fakesh in list (for re-creating the face ring).
12725  cavesegshlist->newindex((void **) &parysh);
12726  *parysh = fakesh;
12727  } // i
12728  caveshlist->restart();
12729 
12730  // Re-create the face ring.
12731  if (cavesegshlist->objects > 1) {
12732  for (i = 0; i < cavesegshlist->objects; i++) {
12733  parysh = (face *) fastlookup(cavesegshlist, i);
12734  fakesh = *parysh;
12735  // Get the next face in the ring.
12736  j = (i + 1) % cavesegshlist->objects;
12737  parysh = (face *) fastlookup(cavesegshlist, j);
12738  nextsh = *parysh;
12739  sbond1(fakesh, nextsh);
12740  }
12741  }
12742 
12743  // Delete the two subsegments containing p.
12744  shellfacedealloc(subsegs, parentseg->sh);
12745  shellfacedealloc(subsegs, prevseg.sh);
12746  // Return the new segment.
12747  *parentseg = abseg;
12748  } else {
12749  // p is inside the surface.
12750  if (b->verbose > 2) {
12751  printf(" Remove vertex %d from surface.\n", pointmark(delpt));
12752  }
12753  assert(sorg(*parentsh) == delpt);
12754  // Let 'delpt' be its apex.
12755  senextself(*parentsh);
12756  // For unifying the code, we add parentsh to list.
12757  cavesegshlist->newindex((void **) &parysh);
12758  *parysh = *parentsh;
12759  }
12760 
12761  // Remove the point (p).
12762 
12763  for (it = 0; it < cavesegshlist->objects; it++) {
12764  parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
12765  senextself(*parentsh); // [b,p,a].
12766  spivotself(*parentsh);
12767  if (sorg(*parentsh) != delpt) sesymself(*parentsh);
12768  // now parentsh is [p,b,#].
12769  if (sorg(*parentsh) != delpt) {
12770  // The vertex has already been removed in above special case.
12771  assert(!smarktested(*parentsh));
12772  continue;
12773  }
12774 
12775  while (1) {
12776  // Initialize the flip edge list. Re-use 'caveshlist'.
12777  spinsh = *parentsh; // [p, b, #]
12778  while (1) {
12779  caveshlist->newindex((void **) &parysh);
12780  *parysh = spinsh;
12781  senext2self(spinsh);
12782  spivotself(spinsh);
12783  assert(spinsh.sh != NULL);
12784  if (spinsh.sh == parentsh->sh) break;
12785  if (sorg(spinsh) != delpt) sesymself(spinsh);
12786  assert(sorg(spinsh) == delpt);
12787  } // while (1)
12788 
12789  if (caveshlist->objects == 3) {
12790  // Delete the point by a 3-to-1 flip.
12791  for (i = 0; i < 3; i++) {
12792  parysh = (face *) fastlookup(caveshlist, i);
12793  flipfaces[i] = *parysh;
12794  }
12795  flip31(flipfaces, lawson);
12796  for (i = 0; i < 3; i++) {
12797  shellfacedealloc(subfaces, flipfaces[i].sh);
12798  }
12799  caveshlist->restart();
12800  // Save the new subface.
12801  caveshbdlist->newindex((void **) &parysh);
12802  *parysh = flipfaces[3];
12803  // The vertex is removed.
12804  break;
12805  }
12806 
12807  // Search an edge to flip.
12808  for (i = 0; i < caveshlist->objects; i++) {
12809  parysh = (face *) fastlookup(caveshlist, i);
12810  flipfaces[0] = *parysh;
12811  spivot(flipfaces[0], flipfaces[1]);
12812  if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
12813  sesymself(flipfaces[1]);
12814  // Skip this edge if it belongs to a faked subface.
12815  if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
12816  pa = sorg(flipfaces[0]);
12817  pb = sdest(flipfaces[0]);
12818  pc = sapex(flipfaces[0]);
12819  pd = sapex(flipfaces[1]);
12820  calculateabovepoint4(pa, pb, pc, pd);
12821  // Check if a 2-to-2 flip is possible.
12822  ori1 = orient3d(pc, pd, dummypoint, pa);
12823  ori2 = orient3d(pc, pd, dummypoint, pb);
12824  if (ori1 * ori2 < 0) {
12825  // A 2-to-2 flip is found.
12826  flip22(flipfaces, lawson, 0);
12827  // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
12828  // changed. The 'flipfaces[1]' contains p as its apex.
12829  senext2(flipfaces[1], *parentsh);
12830  // Save the new subface.
12831  caveshbdlist->newindex((void **) &parysh);
12832  *parysh = flipfaces[0];
12833  break;
12834  }
12835  } //
12836  } // i
12837 
12838  if (i == caveshlist->objects) {
12839  // This can happen only if there are 4 edges at p, and they are
12840  // orthogonal to each other, see Fig. 2010-11-01.
12841  assert(caveshlist->objects == 4);
12842  // Do a flip22 and a flip31 to remove p.
12843  parysh = (face *) fastlookup(caveshlist, 0);
12844  flipfaces[0] = *parysh;
12845  spivot(flipfaces[0], flipfaces[1]);
12846  if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
12847  sesymself(flipfaces[1]);
12848  }
12849  flip22(flipfaces, lawson, 0);
12850  senext2(flipfaces[1], *parentsh);
12851  // Save the new subface.
12852  caveshbdlist->newindex((void **) &parysh);
12853  *parysh = flipfaces[0];
12854  }
12855 
12856  // The edge list at p are changed.
12857  caveshlist->restart();
12858  } // while (1)
12859 
12860  } // it
12861 
12863 
12864  if (b->verbose > 2) {
12865  printf(" Created %ld new subfaces.\n", caveshbdlist->objects);
12866  }
12867 
12868 
12869  if (lawson) {
12870  lawsonflip();
12871  }
12872 
12873  return 0;
12874 }
12875 
12877 // //
12878 // slocate() Locate a point in a surface triangulation. //
12879 // //
12880 // Staring the search from 'searchsh'(it should not be NULL). Perform a line //
12881 // walk search for a subface containing the point (p). //
12882 // //
12883 // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies //
12884 // above the 'searchsh' in its current orientation. The test if c is CCW to //
12885 // the line a->b can be done by the test if c is below the oriented plane //
12886 // a->b->dummypoint. //
12887 // //
12888 // If 'cflag' is not TRUE, the triangulation may not be convex. Stop search //
12889 // when a segment is met and return OUTSIDE. //
12890 // //
12891 // If 'rflag' (rounding) is set, after the location of the point is found, //
12892 // either ONEDGE or ONFACE, round the result using an epsilon. //
12893 // //
12894 // The returned value indicates the following cases: //
12895 // - ONVERTEX, p is the origin of 'searchsh'. //
12896 // - ONEDGE, p lies on the edge of 'searchsh'. //
12897 // - ONFACE, p lies in the interior of 'searchsh'. //
12898 // - OUTSIDE, p lies outside of the triangulation, p is on the left-hand //
12899 // side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW. //
12900 // //
12902 
12904  face* searchsh, int aflag, int cflag, int rflag)
12905 {
12906  face neighsh;
12907  point pa, pb, pc;
12908  enum locateresult loc;
12909  enum {MOVE_BC, MOVE_CA} nextmove;
12910  REAL ori, ori_bc, ori_ca;
12911  int i;
12912 
12913  pa = sorg(*searchsh);
12914  pb = sdest(*searchsh);
12915  pc = sapex(*searchsh);
12916 
12917  if (!aflag) {
12918  // No above point is given. Calculate an above point for this facet.
12919  calculateabovepoint4(pa, pb, pc, searchpt);
12920  }
12921 
12922  // 'dummypoint' is given. Make sure it is above [a,b,c]
12923  ori = orient3d(pa, pb, pc, dummypoint);
12924  assert(ori != 0); // SELF_CHECK
12925  if (ori > 0) {
12926  sesymself(*searchsh); // Reverse the face orientation.
12927  }
12928 
12929  // Find an edge of the face s.t. p lies on its right-hand side (CCW).
12930  for (i = 0; i < 3; i++) {
12931  pa = sorg(*searchsh);
12932  pb = sdest(*searchsh);
12933  ori = orient3d(pa, pb, dummypoint, searchpt);
12934  if (ori > 0) break;
12935  senextself(*searchsh);
12936  }
12937  assert(i < 3); // SELF_CHECK
12938 
12939  pc = sapex(*searchsh);
12940 
12941  if (pc == searchpt) {
12942  senext2self(*searchsh);
12943  return ONVERTEX;
12944  }
12945 
12946  while (1) {
12947 
12948  ori_bc = orient3d(pb, pc, dummypoint, searchpt);
12949  ori_ca = orient3d(pc, pa, dummypoint, searchpt);
12950 
12951  if (ori_bc < 0) {
12952  if (ori_ca < 0) { // (--)
12953  // Any of the edges is a viable move.
12954  if (randomnation(2)) {
12955  nextmove = MOVE_CA;
12956  } else {
12957  nextmove = MOVE_BC;
12958  }
12959  } else { // (-#)
12960  // Edge [b, c] is viable.
12961  nextmove = MOVE_BC;
12962  }
12963  } else {
12964  if (ori_ca < 0) { // (#-)
12965  // Edge [c, a] is viable.
12966  nextmove = MOVE_CA;
12967  } else {
12968  if (ori_bc > 0) {
12969  if (ori_ca > 0) { // (++)
12970  loc = ONFACE; // Inside [a, b, c].
12971  break;
12972  } else { // (+0)
12973  senext2self(*searchsh); // On edge [c, a].
12974  loc = ONEDGE;
12975  break;
12976  }
12977  } else { // ori_bc == 0
12978  if (ori_ca > 0) { // (0+)
12979  senextself(*searchsh); // On edge [b, c].
12980  loc = ONEDGE;
12981  break;
12982  } else { // (00)
12983  // p is coincident with vertex c.
12984  senext2self(*searchsh);
12985  return ONVERTEX;
12986  }
12987  }
12988  }
12989  }
12990 
12991  // Move to the next face.
12992  if (nextmove == MOVE_BC) {
12993  senextself(*searchsh);
12994  } else {
12995  senext2self(*searchsh);
12996  }
12997  if (!cflag) {
12998  // NON-convex case. Check if we will cross a boundary.
12999  if (isshsubseg(*searchsh)) {
13000  return ENCSEGMENT;
13001  }
13002  }
13003  spivot(*searchsh, neighsh);
13004  if (neighsh.sh == NULL) {
13005  return OUTSIDE; // A hull edge.
13006  }
13007  // Adjust the edge orientation.
13008  if (sorg(neighsh) != sdest(*searchsh)) {
13009  sesymself(neighsh);
13010  }
13011  assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK
13012 
13013  // Update the newly discovered face and its endpoints.
13014  *searchsh = neighsh;
13015  pa = sorg(*searchsh);
13016  pb = sdest(*searchsh);
13017  pc = sapex(*searchsh);
13018 
13019  if (pc == searchpt) {
13020  senext2self(*searchsh);
13021  return ONVERTEX;
13022  }
13023 
13024  } // while (1)
13025 
13026  // assert(loc == ONFACE || loc == ONEDGE);
13027 
13028 
13029  if (rflag) {
13030  // Round the locate result before return.
13031  REAL n[3], area_abc, area_abp, area_bcp, area_cap;
13032 
13033  pa = sorg(*searchsh);
13034  pb = sdest(*searchsh);
13035  pc = sapex(*searchsh);
13036 
13037  facenormal(pa, pb, pc, n, 1, NULL);
13038  area_abc = sqrt(dot(n, n));
13039 
13040  facenormal(pb, pc, searchpt, n, 1, NULL);
13041  area_bcp = sqrt(dot(n, n));
13042  if ((area_bcp / area_abc) < b->epsilon) {
13043  area_bcp = 0; // Rounding.
13044  }
13045 
13046  facenormal(pc, pa, searchpt, n, 1, NULL);
13047  area_cap = sqrt(dot(n, n));
13048  if ((area_cap / area_abc) < b->epsilon) {
13049  area_cap = 0; // Rounding
13050  }
13051 
13052  if ((loc == ONFACE) || (loc == OUTSIDE)) {
13053  facenormal(pa, pb, searchpt, n, 1, NULL);
13054  area_abp = sqrt(dot(n, n));
13055  if ((area_abp / area_abc) < b->epsilon) {
13056  area_abp = 0; // Rounding
13057  }
13058  } else { // loc == ONEDGE
13059  area_abp = 0;
13060  }
13061 
13062  if (area_abp == 0) {
13063  if (area_bcp == 0) {
13064  assert(area_cap != 0);
13065  senextself(*searchsh);
13066  loc = ONVERTEX; // p is close to b.
13067  } else {
13068  if (area_cap == 0) {
13069  loc = ONVERTEX; // p is close to a.
13070  } else {
13071  loc = ONEDGE; // p is on edge [a,b].
13072  }
13073  }
13074  } else if (area_bcp == 0) {
13075  if (area_cap == 0) {
13076  senext2self(*searchsh);
13077  loc = ONVERTEX; // p is close to c.
13078  } else {
13079  senextself(*searchsh);
13080  loc = ONEDGE; // p is on edge [b,c].
13081  }
13082  } else if (area_cap == 0) {
13083  senext2self(*searchsh);
13084  loc = ONEDGE; // p is on edge [c,a].
13085  } else {
13086  loc = ONFACE; // p is on face [a,b,c].
13087  }
13088  } // if (rflag)
13089 
13090  return loc;
13091 }
13092 
13094 // //
13095 // sscoutsegment() Look for a segment in surface triangulation. //
13096 // //
13097 // The segment is given by the origin of 'searchsh' and 'endpt'. Assume the //
13098 // orientation of 'searchsh' is CCW w.r.t. the above point. //
13099 // //
13100 // If an edge in T is found matching this segment, the segment is "locked" //
13101 // in T at the edge. Otherwise, flip the first edge in T that the segment //
13102 // crosses. Continue the search from the flipped face. //
13103 // //
13105 
13107  point endpt)
13108 {
13109  face flipshs[2], neighsh;
13110  face newseg;
13111  point startpt, pa, pb, pc, pd;
13112  enum interresult dir;
13113  enum {MOVE_AB, MOVE_CA} nextmove;
13114  REAL ori_ab, ori_ca, len;
13115 
13116  // The origin of 'searchsh' is fixed.
13117  startpt = sorg(*searchsh); // pa = startpt;
13118  nextmove = MOVE_AB; // Avoid compiler warning.
13119 
13120  if (b->verbose > 2) {
13121  printf(" Scout segment (%d, %d).\n", pointmark(startpt),
13122  pointmark(endpt));
13123  }
13124  len = distance(startpt, endpt);
13125 
13126  // Search an edge in 'searchsh' on the path of this segment.
13127  while (1) {
13128 
13129  pb = sdest(*searchsh);
13130  if (pb == endpt) {
13131  dir = SHAREEDGE; // Found!
13132  break;
13133  }
13134 
13135  pc = sapex(*searchsh);
13136  if (pc == endpt) {
13137  senext2self(*searchsh);
13138  sesymself(*searchsh);
13139  dir = SHAREEDGE; // Found!
13140  break;
13141  }
13142 
13143  // Round the results.
13144  if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
13145  ori_ab = 0.0;
13146  } else {
13147  ori_ab = orient3d(startpt, pb, dummypoint, endpt);
13148  }
13149  if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
13150  ori_ca = 0.0;
13151  } else {
13152  ori_ca = orient3d(pc, startpt, dummypoint, endpt);
13153  }
13154 
13155  if (ori_ab < 0) {
13156  if (ori_ca < 0) { // (--)
13157  // Both sides are viable moves.
13158  if (randomnation(2)) {
13159  nextmove = MOVE_CA;
13160  } else {
13161  nextmove = MOVE_AB;
13162  }
13163  } else { // (-#)
13164  nextmove = MOVE_AB;
13165  }
13166  } else {
13167  if (ori_ca < 0) { // (#-)
13168  nextmove = MOVE_CA;
13169  } else {
13170  if (ori_ab > 0) {
13171  if (ori_ca > 0) { // (++)
13172  // The segment intersects with edge [b, c].
13173  dir = ACROSSEDGE;
13174  break;
13175  } else { // (+0)
13176  // The segment collinear with edge [c, a].
13177  senext2self(*searchsh);
13178  sesymself(*searchsh);
13179  dir = ACROSSVERT;
13180  break;
13181  }
13182  } else {
13183  if (ori_ca > 0) { // (0+)
13184  // The segment collinear with edge [a, b].
13185  dir = ACROSSVERT;
13186  break;
13187  } else { // (00)
13188  // startpt == endpt. Not possible.
13189  assert(0); // SELF_CHECK
13190  }
13191  }
13192  }
13193  }
13194 
13195  // Move 'searchsh' to the next face, keep the origin unchanged.
13196  if (nextmove == MOVE_AB) {
13197  spivot(*searchsh, neighsh);
13198  if (neighsh.sh != NULL) {
13199  if (sorg(neighsh) != pb) sesymself(neighsh);
13200  senext(neighsh, *searchsh);
13201  } else {
13202  // This side (startpt->pb) is outside. It is caused by rounding error.
13203  // Try the next side, i.e., (pc->startpt).
13204  senext2(*searchsh, neighsh);
13205  spivotself(neighsh);
13206  assert(neighsh.sh != NULL);
13207  if (sdest(neighsh) != pc) sesymself(neighsh);
13208  *searchsh = neighsh;
13209  }
13210  } else {
13211  senext2(*searchsh, neighsh);
13212  spivotself(neighsh);
13213  if (neighsh.sh != NULL) {
13214  if (sdest(neighsh) != pc) sesymself(neighsh);
13215  *searchsh = neighsh;
13216  } else {
13217  // The same reason as above.
13218  // Try the next side, i.e., (startpt->pb).
13219  spivot(*searchsh, neighsh);
13220  assert(neighsh.sh != NULL);
13221  if (sorg(neighsh) != pb) sesymself(neighsh);
13222  senext(neighsh, *searchsh);
13223  }
13224  }
13225  assert(sorg(*searchsh) == startpt); // SELF_CHECK
13226 
13227  } // while
13228 
13229  if (dir == SHAREEDGE) {
13230  // Insert the segment into the triangulation.
13231  makeshellface(subsegs, &newseg);
13232  setshvertices(newseg, startpt, endpt, NULL);
13233  // Set the default segment marker.
13234  setshellmark(newseg, 1);
13235  ssbond(*searchsh, newseg);
13236  spivot(*searchsh, neighsh);
13237  if (neighsh.sh != NULL) {
13238  ssbond(neighsh, newseg);
13239  }
13240  return dir;
13241  }
13242 
13243  if (dir == ACROSSVERT) {
13244  // A point is found collinear with this segment.
13245  return dir;
13246  }
13247 
13248  if (dir == ACROSSEDGE) {
13249  // Edge [b, c] intersects with the segment.
13250  senext(*searchsh, flipshs[0]);
13251  if (isshsubseg(flipshs[0])) {
13252  printf("Error: Invalid PLC.\n");
13253  pb = sorg(flipshs[0]);
13254  pc = sdest(flipshs[0]);
13255  printf(" Two segments (%d, %d) and (%d, %d) intersect.\n",
13256  pointmark(startpt), pointmark(endpt), pointmark(pb), pointmark(pc));
13257  terminatetetgen(this, 3);
13258  }
13259  // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
13260  spivot(flipshs[0], flipshs[1]);
13261  assert(flipshs[1].sh != NULL); // SELF_CHECK
13262  if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
13263  flip22(flipshs, 1, 0);
13264  // The flip may create an inverted triangle, check it.
13265  pa = sapex(flipshs[1]);
13266  pb = sapex(flipshs[0]);
13267  pc = sorg(flipshs[0]);
13268  pd = sdest(flipshs[0]);
13269  // Check if pa and pb are on the different sides of [pc, pd].
13270  // Re-use ori_ab, ori_ca for the tests.
13271  ori_ab = orient3d(pc, pd, dummypoint, pb);
13272  ori_ca = orient3d(pd, pc, dummypoint, pa);
13273  //assert(ori_ab * ori_ca != 0); // SELF_CHECK
13274  if (ori_ab < 0) {
13275  flipshpush(&(flipshs[0])); // push it to 'flipstack'
13276  } else if (ori_ca < 0) {
13277  flipshpush(&(flipshs[1])); // // push it to 'flipstack'
13278  }
13279  // Set 'searchsh' s.t. its origin is 'startpt'.
13280  *searchsh = flipshs[0];
13281  assert(sorg(*searchsh) == startpt);
13282  }
13283 
13284  return sscoutsegment(searchsh, endpt);
13285 }
13286 
13288 // //
13289 // scarveholes() Remove triangles not in the facet. //
13290 // //
13291 // This routine re-uses the two global arrays: caveshlist and caveshbdlist. //
13292 // //
13294 
13295 void tetgenmesh::scarveholes(int holes, REAL* holelist)
13296 {
13297  face *parysh, searchsh, neighsh;
13298  enum locateresult loc;
13299  int i, j;
13300 
13301  // Get all triangles. Infect unprotected convex hull triangles.
13303  caveshlist->newindex((void **) &parysh);
13304  *parysh = recentsh;
13305  for (i = 0; i < caveshlist->objects; i++) {
13306  parysh = (face *) fastlookup(caveshlist, i);
13307  searchsh = *parysh;
13308  searchsh.shver = 0;
13309  for (j = 0; j < 3; j++) {
13310  spivot(searchsh, neighsh);
13311  // Is this side on the convex hull?
13312  if (neighsh.sh != NULL) {
13313  if (!smarktested(neighsh)) {
13314  smarktest(neighsh);
13315  caveshlist->newindex((void **) &parysh);
13316  *parysh = neighsh;
13317  }
13318  } else {
13319  // A hull side. Check if it is protected by a segment.
13320  if (!isshsubseg(searchsh)) {
13321  // Not protected. Save this face.
13322  if (!sinfected(searchsh)) {
13323  sinfect(searchsh);
13324  caveshbdlist->newindex((void **) &parysh);
13325  *parysh = searchsh;
13326  }
13327  }
13328  }
13329  senextself(searchsh);
13330  }
13331  }
13332 
13333  // Infect the triangles in the holes.
13334  for (i = 0; i < 3 * holes; i += 3) {
13335  searchsh = recentsh;
13336  loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
13337  if (loc != OUTSIDE) {
13338  sinfect(searchsh);
13339  caveshbdlist->newindex((void **) &parysh);
13340  *parysh = searchsh;
13341  }
13342  }
13343 
13344  // Find and infect all exterior triangles.
13345  for (i = 0; i < caveshbdlist->objects; i++) {
13346  parysh = (face *) fastlookup(caveshbdlist, i);
13347  searchsh = *parysh;
13348  searchsh.shver = 0;
13349  for (j = 0; j < 3; j++) {
13350  spivot(searchsh, neighsh);
13351  if (neighsh.sh != NULL) {
13352  if (!isshsubseg(searchsh)) {
13353  if (!sinfected(neighsh)) {
13354  sinfect(neighsh);
13355  caveshbdlist->newindex((void **) &parysh);
13356  *parysh = neighsh;
13357  }
13358  } else {
13359  sdissolve(neighsh); // Disconnect a protected face.
13360  }
13361  }
13362  senextself(searchsh);
13363  }
13364  }
13365 
13366  // Delete exterior triangles, unmark interior triangles.
13367  for (i = 0; i < caveshlist->objects; i++) {
13368  parysh = (face *) fastlookup(caveshlist, i);
13369  if (sinfected(*parysh)) {
13370  shellfacedealloc(subfaces, parysh->sh);
13371  } else {
13372  sunmarktest(*parysh);
13373  }
13374  }
13375 
13376  caveshlist->restart();
13377  caveshbdlist->restart();
13378 }
13379 
13381 // //
13382 // triangulate() Create a CDT for the facet. //
13383 // //
13384 // All vertices of the triangulation have type FACETVERTEX. The actual type //
13385 // of boundary vertices are set by the routine unifysements(). //
13386 // //
13388 
13389 void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
13390  int holes, REAL* holelist)
13391 {
13392  face searchsh, newsh, *parysh;
13393  face newseg;
13394  point pa, pb, pc, *ppt, *cons;
13395  int iloc;
13396  int i, j;
13397 
13398  if (b->verbose > 2) {
13399  printf(" f%d: %ld vertices, %ld segments", shmark, ptlist->objects,
13400  conlist->objects);
13401  if (holes > 0) {
13402  printf(", %d holes", holes);
13403  }
13404  printf(".\n");
13405  }
13406 
13407  if (ptlist->objects < 2l) {
13408  // Not a segment or a facet.
13409  return;
13410  }
13411 
13412  if (ptlist->objects == 2l) {
13413  pa = * (point *) fastlookup(ptlist, 0);
13414  pb = * (point *) fastlookup(ptlist, 1);
13415  if (distance(pa, pb) > 0) {
13416  // It is a single segment.
13417  makeshellface(subsegs, &newseg);
13418  setshvertices(newseg, pa, pb, NULL);
13419  // Set the default segment marker '1'.
13420  setshellmark(newseg, 1);
13421  }
13422  if (pointtype(pa) == VOLVERTEX) {
13424  }
13425  if (pointtype(pb) == VOLVERTEX) {
13427  }
13428  return;
13429  }
13430 
13431 
13432  if (ptlist->objects == 3) {
13433  pa = * (point *) fastlookup(ptlist, 0);
13434  pb = * (point *) fastlookup(ptlist, 1);
13435  pc = * (point *) fastlookup(ptlist, 2);
13436  } else {
13437  // Calculate an above point of this facet.
13438  if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
13439  return; // The point set is degenerate.
13440  }
13441  }
13442 
13443  // Create an initial triangulation.
13444  makeshellface(subfaces, &newsh);
13445  setshvertices(newsh, pa, pb, pc);
13446  setshellmark(newsh, shmark);
13447  recentsh = newsh;
13448 
13449  if (pointtype(pa) == VOLVERTEX) {
13451  }
13452  if (pointtype(pb) == VOLVERTEX) {
13454  }
13455  if (pointtype(pc) == VOLVERTEX) {
13457  }
13458 
13459  // Are there area constraints?
13460  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
13461  int idx, fmarker;
13462  REAL area;
13463  idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
13464  for (i = 0; i < in->numberoffacetconstraints; i++) {
13465  fmarker = (int) in->facetconstraintlist[i * 2];
13466  if (fmarker == idx) {
13467  area = in->facetconstraintlist[i * 2 + 1];
13468  setareabound(newsh, area);
13469  break;
13470  }
13471  }
13472  }
13473 
13474  if (ptlist->objects == 3) {
13475  // The triangulation only has one element.
13476  for (i = 0; i < 3; i++) {
13477  makeshellface(subsegs, &newseg);
13478  setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
13479  // Set the default segment marker '1'.
13480  setshellmark(newseg, 1);
13481  ssbond(newsh, newseg);
13482  senextself(newsh);
13483  }
13484  return;
13485  }
13486 
13487  // Incrementally build the triangulation.
13488  pinfect(pa);
13489  pinfect(pb);
13490  pinfect(pc);
13491  for (i = 0; i < ptlist->objects; i++) {
13492  ppt = (point *) fastlookup(ptlist, i);
13493  if (!pinfected(*ppt)) {
13494  searchsh = recentsh; // Start from 'recentsh'.
13495  iloc = (int) OUTSIDE;
13496  // Insert the vertex. Use Bowyer-Watson algo. Round the location.
13497  iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
13498  if (pointtype(*ppt) == VOLVERTEX) {
13499  setpointtype(*ppt, FACETVERTEX);
13500  }
13501  // Delete all removed subfaces.
13502  for (j = 0; j < caveshlist->objects; j++) {
13503  parysh = (face *) fastlookup(caveshlist, j);
13504  shellfacedealloc(subfaces, parysh->sh);
13505  }
13506  // Clear the global lists.
13507  caveshbdlist->restart();
13508  caveshlist->restart();
13510  } else {
13511  puninfect(*ppt); // This point has inserted.
13512  }
13513  }
13514 
13515  // Insert the segments.
13516  for (i = 0; i < conlist->objects; i++) {
13517  cons = (point *) fastlookup(conlist, i);
13518  searchsh = recentsh;
13519  iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
13520  if (iloc != (enum locateresult) ONVERTEX) {
13521  // Not found due to roundoff errors. Do a brute-force search.
13523  searchsh.sh = shellfacetraverse(subfaces);
13524  while (searchsh.sh != NULL) {
13525  // Only search the subface in the same facet.
13526  if (shellmark(searchsh) == shmark) {
13527  if ((point) searchsh.sh[3] == cons[0]) {
13528  searchsh.shver = 0; break;
13529  } else if ((point) searchsh.sh[4] == cons[0]) {
13530  searchsh.shver = 2; break;
13531  } else if ((point) searchsh.sh[5] == cons[0]) {
13532  searchsh.shver = 4; break;
13533  }
13534  }
13535  searchsh.sh = shellfacetraverse(subfaces);
13536  }
13537  assert(searchsh.sh != NULL);
13538  }
13539  // Recover the segment. Some edges may be flipped.
13540  sscoutsegment(&searchsh, cons[1]);
13541  if (flipstack != NULL) {
13542  // Recover locally Delaunay edges.
13543  lawsonflip();
13544  }
13545  }
13546 
13547  // Remove exterior and hole triangles.
13548  scarveholes(holes, holelist);
13549 }
13550 
13552 // //
13553 // unifysubfaces() Unify two identical subfaces. //
13554 // //
13555 // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b]. //
13556 // If c = d, then f1 and f2 are identical. Otherwise, these two subfaces //
13557 // intersect, and the mesher is stopped. //
13558 // //
13559 // If the two subfaces are identical, we try to replace f2 by f1, i.e, all //
13560 // neighbors of f2 are re-connected to f1. //
13561 // //
13563 
13565 {
13566  if (b->psc) {
13567  // In this case, it is possible that two subfaces are identical.
13568  // While they must belong to two different surfaces.
13569  return;
13570  }
13571 
13572  point pa, pb, pc, pd;
13573 
13574  pa = sorg(*f1);
13575  pb = sdest(*f1);
13576  pc = sapex(*f1);
13577  pd = sapex(*f2);
13578 
13579 #if 1//_BACK_
13580  if (pc != pd) {
13581  printf("Found two facets intersect each other.\n");
13582  printf(" 1st: [%d, %d, %d] #%d\n",
13583  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13584  printf(" 2nd: [%d, %d, %d] #%d\n",
13585  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13586  terminatetetgen(this, 3);
13587  } else {
13588  printf("Found two duplicated facets.\n");
13589  printf(" 1st: [%d, %d, %d] #%d\n",
13590  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13591  printf(" 2nd: [%d, %d, %d] #%d\n",
13592  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13593  terminatetetgen(this, 3);
13594  }
13595 #endif
13596 }
13597 
13599 // //
13600 // unifysegments() Remove redundant segments and create face links. //
13601 // //
13602 // After this routine, although segments are unique, but some of them may be //
13603 // removed later by mergefacet(). All vertices still have type FACETVERTEX. //
13604 // //
13606 
13608 {
13609  badface *facelink = NULL, *newlinkitem, *f1, *f2;
13610  face *facperverlist, sface;
13611  face subsegloop, testseg;
13612  point torg, tdest;
13613  REAL ori1, ori2, ori3;
13614  REAL n1[3], n2[3];
13615  int *idx2faclist;
13616  int idx, k, m;
13617 
13618  if (b->verbose > 1) {
13619  printf(" Unifying segments.\n");
13620  }
13621 
13622  // Create a mapping from vertices to subfaces.
13623  makepoint2submap(subfaces, idx2faclist, facperverlist);
13624 
13625  if (b->psc) {
13626  face sface1;
13627  face seg, seg1;
13628  int fmarker, fmarker1;
13629  // First only connect subfaces which belong to the same surfaces.
13630  subsegloop.shver = 0;
13632  subsegloop.sh = shellfacetraverse(subsegs);
13633  while (subsegloop.sh != (shellface *) NULL) {
13634  torg = sorg(subsegloop);
13635  tdest = sdest(subsegloop);
13636 
13637  idx = pointmark(torg) - in->firstnumber;
13638  for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13639  sface = facperverlist[k];
13640  // The face may be deleted if it is a duplicated face.
13641  if (sface.sh[3] == NULL) continue;
13642  // Search the edge torg->tdest.
13643  assert(sorg(sface) == torg); // SELF_CHECK
13644  if (sdest(sface) != tdest) {
13645  senext2self(sface);
13646  sesymself(sface);
13647  }
13648  if (sdest(sface) != tdest) continue;
13649 
13650  sspivot(sface, seg);
13651  if (seg.sh == NULL) continue;
13652  // assert(seg.sh != NULL); It may or may not be subsegloop.
13653 
13654  // Find the adjacent subface on the same facet.
13655  fmarker = in->facetmarkerlist[shellmark(sface) - 1];
13656  sface1.sh = NULL;
13657  k++;
13658  for (; k < idx2faclist[idx + 1]; k++) {
13659  sface1 = facperverlist[k];
13660  // The face may be deleted if it is a duplicated face.
13661  if (sface1.sh[3] == NULL) continue;
13662  // Search the edge torg->tdest.
13663  assert(sorg(sface1) == torg); // SELF_CHECK
13664  if (sdest(sface1) != tdest) {
13665  senext2self(sface1);
13666  sesymself(sface1);
13667  }
13668  if (sdest(sface1) != tdest) continue;
13669  // Found a subface sharing at the same edge.
13670  fmarker1 = in->facetmarkerlist[shellmark(sface1) - 1];
13671  if (fmarker1 == fmarker) {
13672  // Found a pair of adjacent subfaces. Connect them.
13673  // Delete a redundent segment.
13674  sspivot(sface1, seg1);
13675  assert(seg1.sh != NULL); // SELF_CHECK
13676  shellfacedealloc(subsegs, seg.sh);
13677  shellfacedealloc(subsegs, seg1.sh);
13678  ssdissolve(sface);
13679  ssdissolve(sface1);
13680  // Connect them.
13681  sbond(sface, sface1);
13682  // Set Steiner point -to- subface map.
13683  if (pointtype(torg) == FREEFACETVERTEX) {
13684  setpoint2sh(torg, sencode(sface));
13685  }
13686  if (pointtype(tdest) == FREEFACETVERTEX) {
13687  setpoint2sh(tdest, sencode(sface));
13688  }
13689  break;
13690  }
13691  }
13692  break;
13693  }
13694  subsegloop.sh = shellfacetraverse(subsegs);
13695  }
13696  } // if (b->psc)
13697 
13698  subsegloop.shver = 0;
13700  subsegloop.sh = shellfacetraverse(subsegs);
13701  while (subsegloop.sh != (shellface *) NULL) {
13702  torg = sorg(subsegloop);
13703  tdest = sdest(subsegloop);
13704 
13705  idx = pointmark(torg) - in->firstnumber;
13706  // Loop through the set of subfaces containing 'torg'. Get all the
13707  // subfaces containing the edge (torg, tdest). Save and order them
13708  // in 'sfacelist', the ordering is defined by the right-hand rule
13709  // with thumb points from torg to tdest.
13710  for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13711  sface = facperverlist[k];
13712  // The face may be deleted if it is a duplicated face.
13713  if (sface.sh[3] == NULL) continue;
13714  // Search the edge torg->tdest.
13715  assert(sorg(sface) == torg); // SELF_CHECK
13716  if (sdest(sface) != tdest) {
13717  senext2self(sface);
13718  sesymself(sface);
13719  }
13720  if (sdest(sface) != tdest) continue;
13721 
13722  // Save the face f in facelink.
13723  if (flippool->items >= 2) {
13724  f1 = facelink;
13725  for (m = 0; m < flippool->items - 1; m++) {
13726  f2 = f1->nextitem;
13727  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
13728  ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13729  if (ori1 > 0) {
13730  // apex(f2) is below f1.
13731  if (ori2 > 0) {
13732  // apex(f) is below f1 (see Fig.1).
13733  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13734  if (ori3 > 0) {
13735  // apex(f) is below f2, insert it.
13736  break;
13737  } else if (ori3 < 0) {
13738  // apex(f) is above f2, continue.
13739  } else { // ori3 == 0;
13740  // f is coplanar and codirection with f2.
13741  unifysubfaces(&(f2->ss), &sface);
13742  break;
13743  }
13744  } else if (ori2 < 0) {
13745  // apex(f) is above f1 below f2, inset it (see Fig. 2).
13746  break;
13747  } else { // ori2 == 0;
13748  // apex(f) is coplanar with f1 (see Fig. 5).
13749  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13750  if (ori3 > 0) {
13751  // apex(f) is below f2, insert it.
13752  break;
13753  } else {
13754  // f is coplanar and codirection with f1.
13755  unifysubfaces(&(f1->ss), &sface);
13756  break;
13757  }
13758  }
13759  } else if (ori1 < 0) {
13760  // apex(f2) is above f1.
13761  if (ori2 > 0) {
13762  // apex(f) is below f1, continue (see Fig. 3).
13763  } else if (ori2 < 0) {
13764  // apex(f) is above f1 (see Fig.4).
13765  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13766  if (ori3 > 0) {
13767  // apex(f) is below f2, insert it.
13768  break;
13769  } else if (ori3 < 0) {
13770  // apex(f) is above f2, continue.
13771  } else { // ori3 == 0;
13772  // f is coplanar and codirection with f2.
13773  unifysubfaces(&(f2->ss), &sface);
13774  break;
13775  }
13776  } else { // ori2 == 0;
13777  // f is coplanar and with f1 (see Fig. 6).
13778  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13779  if (ori3 > 0) {
13780  // f is also codirection with f1.
13781  unifysubfaces(&(f1->ss), &sface);
13782  break;
13783  } else {
13784  // f is above f2, continue.
13785  }
13786  }
13787  } else { // ori1 == 0;
13788  // apex(f2) is coplanar with f1. By assumption, f1 is not
13789  // coplanar and codirection with f2.
13790  if (ori2 > 0) {
13791  // apex(f) is below f1, continue (see Fig. 7).
13792  } else if (ori2 < 0) {
13793  // apex(f) is above f1, insert it (see Fig. 7).
13794  break;
13795  } else { // ori2 == 0.
13796  // apex(f) is coplanar with f1 (see Fig. 8).
13797  // f is either codirection with f1 or is codirection with f2.
13798  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
13799  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
13800  if (dot(n1, n2) > 0) {
13801  unifysubfaces(&(f1->ss), &sface);
13802  } else {
13803  unifysubfaces(&(f2->ss), &sface);
13804  }
13805  break;
13806  }
13807  }
13808  // Go to the next item;
13809  f1 = f2;
13810  } // for (m = 0; ...)
13811  if (sface.sh[3] != NULL) {
13812  // Insert sface between f1 and f2.
13813  newlinkitem = (badface *) flippool->alloc();
13814  newlinkitem->ss = sface;
13815  newlinkitem->nextitem = f1->nextitem;
13816  f1->nextitem = newlinkitem;
13817  }
13818  } else if (flippool->items == 1) {
13819  f1 = facelink;
13820  // Make sure that f is not coplanar and codirection with f1.
13821  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13822  if (ori1 == 0) {
13823  // f is coplanar with f1 (see Fig. 8).
13824  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
13825  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
13826  if (dot(n1, n2) > 0) {
13827  // The two faces are codirectional as well.
13828  unifysubfaces(&(f1->ss), &sface);
13829  }
13830  }
13831  // Add this face to link if it is not deleted.
13832  if (sface.sh[3] != NULL) {
13833  // Add this face into link.
13834  newlinkitem = (badface *) flippool->alloc();
13835  newlinkitem->ss = sface;
13836  newlinkitem->nextitem = NULL;
13837  f1->nextitem = newlinkitem;
13838  }
13839  } else {
13840  // The first face.
13841  newlinkitem = (badface *) flippool->alloc();
13842  newlinkitem->ss = sface;
13843  newlinkitem->nextitem = NULL;
13844  facelink = newlinkitem;
13845  }
13846  } // for (k = idx2faclist[idx]; ...)
13847 
13848  if (b->psc) {
13849  // Set Steiner point -to- segment map.
13850  if (pointtype(torg) == FREESEGVERTEX) {
13851  setpoint2sh(torg, sencode(subsegloop));
13852  }
13853  if (pointtype(tdest) == FREESEGVERTEX) {
13854  setpoint2sh(tdest, sencode(subsegloop));
13855  }
13856  }
13857 
13858  // Set the connection between this segment and faces containing it,
13859  // at the same time, remove redundant segments.
13860  f1 = facelink;
13861  for (k = 0; k < flippool->items; k++) {
13862  sspivot(f1->ss, testseg);
13863  // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
13864  if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
13865  shellfacedealloc(subsegs, testseg.sh);
13866  }
13867  // Bonds the subface and the segment together.
13868  ssbond(f1->ss, subsegloop);
13869  f1 = f1->nextitem;
13870  }
13871 
13872  // Create the face ring at the segment.
13873  if (flippool->items > 1) {
13874  f1 = facelink;
13875  for (k = 1; k <= flippool->items; k++) {
13876  k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
13877  sbond1(f1->ss, f2->ss);
13878  f1 = f2;
13879  }
13880  }
13881 
13882  // All identified segments has an init marker "0".
13883  flippool->restart();
13884 
13885  // Are there length constraints?
13886  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
13887  int e1, e2;
13888  REAL len;
13889  for (k = 0; k < in->numberofsegmentconstraints; k++) {
13890  e1 = (int) in->segmentconstraintlist[k * 3];
13891  e2 = (int) in->segmentconstraintlist[k * 3 + 1];
13892  if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
13893  ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
13894  len = in->segmentconstraintlist[k * 3 + 2];
13895  setareabound(subsegloop, len);
13896  break;
13897  }
13898  }
13899  }
13900 
13901  subsegloop.sh = shellfacetraverse(subsegs);
13902  }
13903 
13904  delete [] idx2faclist;
13905  delete [] facperverlist;
13906 }
13907 
13909 // //
13910 // mergefacets() Merge adjacent facets. //
13911 // //
13913 
13915 {
13916  face parentsh, neighsh, neineish;
13917  face segloop;
13918  point pa, pb, pc, pd;
13919  REAL ang_tol, ang;
13920  int remsegcount;
13921  int fidx1, fidx2;
13922  int fmrk1, fmrk2;
13923 
13924  if (b->verbose > 1) {
13925  printf(" Merging adjacent facets.\n");
13926  }
13927 
13928  // The dihedral angle bound for two different facets.
13929  // Set by -p option. Default is 179 degree.
13930  ang_tol = b->facet_ang_tol / 180.0 * PI;
13931  remsegcount = 0;
13932 
13933  // Loop all segments, merge adjacent coplanar facets.
13935  segloop.sh = shellfacetraverse(subsegs);
13936  while (segloop.sh != (shellface *) NULL) {
13937  spivot(segloop, parentsh);
13938  if (parentsh.sh != NULL) {
13939  spivot(parentsh, neighsh);
13940  if (neighsh.sh != NULL) {
13941  spivot(neighsh, neineish);
13942  if (neineish.sh == parentsh.sh) {
13943  // Exactly two subfaces at this segment.
13944  fidx1 = shellmark(parentsh) - 1;
13945  fidx2 = shellmark(neighsh) - 1;
13946  // Only merge them if they are in different facet.
13947  if (fidx1 != fidx2) {
13948  // The two subfaces are not in the same facet.
13949  if (in->facetmarkerlist != NULL) {
13950  fmrk1 = in->facetmarkerlist[fidx1];
13951  fmrk2 = in->facetmarkerlist[fidx2];
13952  } else {
13953  fmrk1 = fmrk2 = 0;
13954  }
13955  // Only merge them if they have the same boundary marker.
13956  if (fmrk1 == fmrk2) {
13957  pa = sorg(segloop);
13958  pb = sdest(segloop);
13959  pc = sapex(parentsh);
13960  pd = sapex(neighsh);
13961  // Calculate the dihedral angle at the segment [a,b].
13962  ang = facedihedral(pa, pb, pc, pd);
13963  if (ang > PI) ang = (2 * PI - ang);
13964  if (ang > ang_tol) {
13965  remsegcount++;
13966  ssdissolve(parentsh);
13967  ssdissolve(neighsh);
13968  shellfacedealloc(subsegs, segloop.sh);
13969  // Add the edge to flip stack.
13970  flipshpush(&parentsh);
13971  } // if (ang > ang_tol)
13972  } // if (fmrk1 == fmrk2)
13973  } // if (fidx1 != fidx2)
13974  } // if (neineish.sh == parentsh.sh)
13975  }
13976  }
13977  segloop.sh = shellfacetraverse(subsegs);
13978  }
13979 
13980  if (flipstack != NULL) {
13981  lawsonflip(); // Recover Delaunayness.
13982  }
13983 
13984  if (b->verbose > 1) {
13985  printf(" %d segments are removed.\n", remsegcount);
13986  }
13987 }
13988 
13990 // //
13991 // identifypscedges() Identify PSC edges. //
13992 // //
13993 // The set of PSC edges are provided in the 'in->edgelist'. Each edge should //
13994 // also be an edge in the surface mesh. We find the corresponding edges in //
13995 // the surface mesh and make them segments of the mesh. //
13996 // //
13997 // It is possible to give an edge which is not in any facet, i.e., it is a //
13998 // dangling edge inside the volume. //
13999 // //
14001 
14003 {
14004  face* shperverlist;
14005  int* idx2shlist;
14006  face searchsh, neighsh;
14007  face segloop, checkseg, newseg;
14008  point checkpt, pa = NULL, pb = NULL;
14009  int *endpts;
14010  int edgemarker;
14011  int idx, i, j;
14012 
14013  int e1, e2;
14014  REAL len;
14015 
14016  if (!b->quiet) {
14017  printf("Inserting edges ...\n");
14018  }
14019 
14020  // All identified segments have the initial marker '1'.
14021  // All segments inserted here should have a marker 'k >= 0'.
14022 
14023  if (b->psc) {
14024  // First mark all segments of the mesh with a marker '-1'.
14026  segloop.sh = shellfacetraverse(subsegs);
14027  while (segloop.sh != NULL) {
14028  setshellmark(segloop, -1);
14029  segloop.sh = shellfacetraverse(subsegs);
14030  }
14031  }
14032 
14033  // Construct a map from points to subfaces.
14034  makepoint2submap(subfaces, idx2shlist, shperverlist);
14035 
14036  // Process the set of PSC edges.
14037  for (i = 0; i < in->numberofedges; i++) {
14038  endpts = &(in->edgelist[(i << 1)]);
14039  edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : 0;
14040 
14041  // Find a face contains the edge.
14042  newseg.sh = NULL;
14043  searchsh.sh = NULL;
14044  idx = endpts[0] - in->firstnumber;
14045  for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
14046  checkpt = sdest(shperverlist[j]);
14047  if (pointmark(checkpt) == endpts[1]) {
14048  searchsh = shperverlist[j];
14049  break; // Found.
14050  } else {
14051  checkpt = sapex(shperverlist[j]);
14052  if (pointmark(checkpt) == endpts[1]) {
14053  senext2(shperverlist[j], searchsh);
14054  sesymself(searchsh);
14055  break;
14056  }
14057  }
14058  } // j
14059 
14060  if (searchsh.sh != NULL) {
14061  // Check if this edge is already a segment of the mesh.
14062  sspivot(searchsh, checkseg);
14063  if (checkseg.sh != NULL) {
14064  // This segment already exist.
14065  newseg = checkseg;
14066  } else {
14067  // Create a new segment at this edge.
14068  pa = sorg(searchsh);
14069  pb = sdest(searchsh);
14070  makeshellface(subsegs, &newseg);
14071  setshvertices(newseg, pa, pb, NULL);
14072  ssbond(searchsh, newseg);
14073  spivot(searchsh, neighsh);
14074  if (neighsh.sh != NULL) {
14075  ssbond(neighsh, newseg);
14076  }
14077  if (b->psc) {
14078  if (pointtype(pa) == FREESEGVERTEX) {
14079  setpoint2sh(pa, sencode(newseg));
14080  }
14081  if (pointtype(pb) == FREESEGVERTEX) {
14082  setpoint2sh(pb, sencode(newseg));
14083  }
14084  }
14085  }
14086  } else {
14087  // It is a dangling segment (not belong to any facets).
14088  // Get the two endpoints of this segment.
14089  pa = idx2verlist[endpts[0]];
14090  pb = idx2verlist[endpts[1]];
14091  // Check if segment [a,b] already exists.
14092  // TODO: Change the brute-force search. Slow!
14093  point *ppt;
14095  segloop.sh = shellfacetraverse(subsegs);
14096  while (segloop.sh != NULL) {
14097  ppt = (point *) &(segloop.sh[3]);
14098  if (((ppt[0] == pa) && (ppt[1] == pb)) ||
14099  ((ppt[0] == pb) && (ppt[1] == pa))) {
14100  // Found!
14101  newseg = segloop;
14102  break;
14103  }
14104  segloop.sh = shellfacetraverse(subsegs);
14105  }
14106  if (newseg.sh == NULL) {
14107  makeshellface(subsegs, &newseg);
14108  setshvertices(newseg, pa, pb, NULL);
14109  if (b->psc) {
14110  if (pointtype(pa) == FREESEGVERTEX) {
14111  setpoint2sh(pa, sencode(newseg));
14112  }
14113  if (pointtype(pb) == FREESEGVERTEX) {
14114  setpoint2sh(pb, sencode(newseg));
14115  }
14116  }
14117  }
14118  }
14119 
14120  setshellmark(newseg, edgemarker);
14121 
14122  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14123  for (i = 0; i < in->numberofsegmentconstraints; i++) {
14124  e1 = (int) in->segmentconstraintlist[i * 3];
14125  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
14126  if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
14127  ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
14128  len = in->segmentconstraintlist[i * 3 + 2];
14129  setareabound(newseg, len);
14130  break;
14131  }
14132  }
14133  }
14134  } // i
14135 
14136 
14137  delete [] shperverlist;
14138  delete [] idx2shlist;
14139 
14140  if (b->psc) {
14141  // Removing all segments with a marker '-1'.
14143  segloop.sh = shellfacetraverse(subsegs);
14144  while (segloop.sh != NULL) {
14145  if (shellmark(segloop) == -1) {
14146  shellfacedealloc(subsegs, segloop.sh);
14147  }
14148  segloop.sh = shellfacetraverse(subsegs);
14149  }
14150 
14151  // Connecting subsegments at Steiner points.
14152  face seg1, seg2;
14153  // Re-use 'idx2shlist' and 'shperverlist'.
14154  makepoint2submap(subsegs, idx2shlist, shperverlist);
14155 
14156  points->traversalinit();
14157  pa = pointtraverse();
14158  while (pa != NULL) {
14159  if (pointtype(pa) == FREESEGVERTEX) {
14160  idx = pointmark(pa) - in->firstnumber;
14161  // There must be only two segments containing this vertex.
14162  assert((idx2shlist[idx + 1] - idx2shlist[idx]) == 2);
14163  i = idx2shlist[idx];
14164  seg1 = shperverlist[i];
14165  seg2 = shperverlist[i+1];
14166  senextself(seg1);
14167  senextself(seg2);
14168  sbond(seg1, seg2);
14169  }
14170  pa = pointtraverse();
14171  }
14172 
14173  delete [] shperverlist;
14174  delete [] idx2shlist;
14175  }
14176 }
14177 
14179 // //
14180 // meshsurface() Create a surface mesh of the input PLC. //
14181 // //
14183 
14185 {
14186  arraypool *ptlist, *conlist;
14187  point *idx2verlist;
14188  point tstart, tend, *pnewpt, *cons;
14189  tetgenio::facet *f;
14191  int end1, end2;
14192  int shmark, i, j;
14193 
14194  if (!b->quiet) {
14195  printf("Creating surface mesh ...\n");
14196  }
14197 
14198  // Create a map from indices to points.
14199  makeindex2pointmap(idx2verlist);
14200 
14201  // Initialize arrays (block size: 2^8 = 256).
14202  ptlist = new arraypool(sizeof(point *), 8);
14203  conlist = new arraypool(2 * sizeof(point *), 8);
14204 
14205  // Loop the facet list, triangulate each facet.
14206  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
14207 
14208  // Get a facet F.
14209  f = &in->facetlist[shmark - 1];
14210 
14211  // Process the duplicated points first, they are marked with type
14212  // DUPLICATEDVERTEX. If p and q are duplicated, and p'index > q's,
14213  // then p is substituted by q.
14214  if (dupverts > 0l) {
14215  // Loop all polygons of this facet.
14216  for (i = 0; i < f->numberofpolygons; i++) {
14217  p = &(f->polygonlist[i]);
14218  // Loop other vertices of this polygon.
14219  for (j = 0; j < p->numberofvertices; j++) {
14220  end1 = p->vertexlist[j];
14221  tstart = idx2verlist[end1];
14222  if (pointtype(tstart) == DUPLICATEDVERTEX) {
14223  // Reset the index of vertex-j.
14224  tend = point2ppt(tstart);
14225  end2 = pointmark(tend);
14226  p->vertexlist[j] = end2;
14227  }
14228  }
14229  }
14230  }
14231 
14232  // Loop polygons of F, get the set of vertices and segments.
14233  for (i = 0; i < f->numberofpolygons; i++) {
14234  // Get a polygon.
14235  p = &(f->polygonlist[i]);
14236  // Get the first vertex.
14237  end1 = p->vertexlist[0];
14238  if ((end1 < in->firstnumber) ||
14239  (end1 >= in->firstnumber + in->numberofpoints)) {
14240  if (!b->quiet) {
14241  printf("Warning: Invalid the 1st vertex %d of polygon", end1);
14242  printf(" %d in facet %d.\n", i + 1, shmark);
14243  }
14244  continue; // Skip this polygon.
14245  }
14246  tstart = idx2verlist[end1];
14247  // Add tstart to V if it haven't been added yet.
14248  if (!pinfected(tstart)) {
14249  pinfect(tstart);
14250  ptlist->newindex((void **) &pnewpt);
14251  *pnewpt = tstart;
14252  }
14253  // Loop other vertices of this polygon.
14254  for (j = 1; j <= p->numberofvertices; j++) {
14255  // get a vertex.
14256  if (j < p->numberofvertices) {
14257  end2 = p->vertexlist[j];
14258  } else {
14259  end2 = p->vertexlist[0]; // Form a loop from last to first.
14260  }
14261  if ((end2 < in->firstnumber) ||
14262  (end2 >= in->firstnumber + in->numberofpoints)) {
14263  if (!b->quiet) {
14264  printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
14265  printf(" in facet %d.\n", shmark);
14266  }
14267  } else {
14268  if (end1 != end2) {
14269  // 'end1' and 'end2' form a segment.
14270  tend = idx2verlist[end2];
14271  // Add tstart to V if it haven't been added yet.
14272  if (!pinfected(tend)) {
14273  pinfect(tend);
14274  ptlist->newindex((void **) &pnewpt);
14275  *pnewpt = tend;
14276  }
14277  // Save the segment in S (conlist).
14278  conlist->newindex((void **) &cons);
14279  cons[0] = tstart;
14280  cons[1] = tend;
14281  // Set the start for next continuous segment.
14282  end1 = end2;
14283  tstart = tend;
14284  } else {
14285  // Two identical vertices mean an isolated vertex of F.
14286  if (p->numberofvertices > 2) {
14287  // This may be an error in the input, anyway, we can continue
14288  // by simply skipping this segment.
14289  if (!b->quiet) {
14290  printf("Warning: Polygon %d has two identical verts", i + 1);
14291  printf(" in facet %d.\n", shmark);
14292  }
14293  }
14294  // Ignore this vertex.
14295  }
14296  }
14297  // Is the polygon degenerate (a segment or a vertex)?
14298  if (p->numberofvertices == 2) break;
14299  }
14300  }
14301  // Unmark vertices.
14302  for (i = 0; i < ptlist->objects; i++) {
14303  pnewpt = (point *) fastlookup(ptlist, i);
14304  puninfect(*pnewpt);
14305  }
14306 
14307  // Triangulate F into a CDT.
14308  triangulate(shmark, ptlist, conlist, f->numberofholes, f->holelist);
14309 
14310  // Clear working lists.
14311  ptlist->restart();
14312  conlist->restart();
14313  }
14314 
14315  if (!b->diagnose) {
14316  // Remove redundant segments and build the face links.
14317  unifysegments();
14318  if (!b->psc && !b->nomergefacet && !b->nobisect) {
14319  // Merge adjacent coplanar facets.
14320  mergefacets();
14321  }
14322  if (in->numberofedges > 0) { // if (b->psc)
14323  // There are segments specified by the user. Read and create them.
14324  identifypscedges(idx2verlist);
14325  }
14326  if (!b->psc) {
14327  // Mark all segment vertices to be RIDGEVERTEX.
14328  face segloop;
14329  point *ppt;
14331  segloop.sh = shellfacetraverse(subsegs);
14332  while (segloop.sh != NULL) {
14333  ppt = (point *) &(segloop.sh[3]);
14334  setpointtype(ppt[0], RIDGEVERTEX);
14335  setpointtype(ppt[1], RIDGEVERTEX);
14336  segloop.sh = shellfacetraverse(subsegs);
14337  }
14338  }
14339  }
14340 
14341  if (b->object == tetgenbehavior::STL) {
14342  // Remove redundant vertices (for .stl input mesh).
14343  jettisonnodes();
14344  }
14345 
14346  if (b->verbose) {
14347  printf(" %ld (%ld) subfaces (segments).\n", subfaces->items,
14348  subsegs->items);
14349  }
14350 
14351  // The total number of iunput segments.
14353 
14354  delete [] idx2verlist;
14355  delete ptlist;
14356  delete conlist;
14357 }
14358 
14360 // //
14361 // interecursive() Recursively do intersection test on a set of triangles.//
14362 // //
14363 // Recursively split the set 'subfacearray' of subfaces into two sets using //
14364 // a cut plane parallel to x-, or, y-, or z-axis. The split criteria are //
14365 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
14366 // H, and H- denotes the right halfspace of H; and s be a subface: //
14367 // //
14368 // (1) If all points of s lie at H+, put it into left array; //
14369 // (2) If all points of s lie at H-, put it into right array; //
14370 // (3) If some points of s lie at H+ and some of lie at H-, or some //
14371 // points lie on H, put it into both arraies. //
14372 // //
14373 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
14374 // if axis == '2'. If current cut plane is parallel to the x-axis, the next //
14375 // one will be parallel to y-axis, and the next one after the next is z-axis,//
14376 // and then alternately return back to x-axis. //
14377 // //
14378 // Stop splitting when the number of triangles of the input array is not //
14379 // decreased anymore. Do tests on the current set. //
14380 // //
14382 
14383 void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
14384  int axis, REAL bxmin, REAL bxmax, REAL bymin,
14385  REAL bymax, REAL bzmin, REAL bzmax,
14386  int* internum)
14387 {
14388  shellface **leftarray, **rightarray;
14389  face sface1, sface2;
14390  point p1, p2, p3;
14391  point p4, p5, p6;
14392  enum interresult intersect;
14393  REAL split;
14394  bool toleft, toright;
14395  int leftsize, rightsize;
14396  int i, j;
14397 
14398  if (b->verbose > 2) {
14399  printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
14400  arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
14401  axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
14402  }
14403 
14404  leftarray = new shellface*[arraysize];
14405  if (leftarray == NULL) {
14406  terminatetetgen(this, 1);
14407  }
14408  rightarray = new shellface*[arraysize];
14409  if (rightarray == NULL) {
14410  terminatetetgen(this, 1);
14411  }
14412  leftsize = rightsize = 0;
14413 
14414  if (axis == 0) {
14415  // Split along x-axis.
14416  split = 0.5 * (bxmin + bxmax);
14417  } else if (axis == 1) {
14418  // Split along y-axis.
14419  split = 0.5 * (bymin + bymax);
14420  } else {
14421  // Split along z-axis.
14422  split = 0.5 * (bzmin + bzmax);
14423  }
14424 
14425  for (i = 0; i < arraysize; i++) {
14426  sface1.sh = subfacearray[i];
14427  p1 = (point) sface1.sh[3];
14428  p2 = (point) sface1.sh[4];
14429  p3 = (point) sface1.sh[5];
14430  toleft = toright = false;
14431  if (p1[axis] < split) {
14432  toleft = true;
14433  if (p2[axis] >= split || p3[axis] >= split) {
14434  toright = true;
14435  }
14436  } else if (p1[axis] > split) {
14437  toright = true;
14438  if (p2[axis] <= split || p3[axis] <= split) {
14439  toleft = true;
14440  }
14441  } else {
14442  // p1[axis] == split;
14443  toleft = true;
14444  toright = true;
14445  }
14446  // At least one is true;
14447  assert(!(toleft == false && toright == false));
14448  if (toleft) {
14449  leftarray[leftsize] = sface1.sh;
14450  leftsize++;
14451  }
14452  if (toright) {
14453  rightarray[rightsize] = sface1.sh;
14454  rightsize++;
14455  }
14456  }
14457 
14458  if (leftsize < arraysize && rightsize < arraysize) {
14459  // Continue to partition the input set. Now 'subfacearray' has been
14460  // split into two sets, it's memory can be freed. 'leftarray' and
14461  // 'rightarray' will be freed in the next recursive (after they're
14462  // partitioned again or performing tests).
14463  delete [] subfacearray;
14464  // Continue to split these two sets.
14465  if (axis == 0) {
14466  interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
14467  bzmin, bzmax, internum);
14468  interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
14469  bzmin, bzmax, internum);
14470  } else if (axis == 1) {
14471  interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
14472  bzmin, bzmax, internum);
14473  interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
14474  bzmin, bzmax, internum);
14475  } else {
14476  interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
14477  bzmin, split, internum);
14478  interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
14479  split, bzmax, internum);
14480  }
14481  } else {
14482  if (b->verbose > 1) {
14483  printf(" Checking intersecting faces.\n");
14484  }
14485  // Perform a brute-force compare on the set.
14486  for (i = 0; i < arraysize; i++) {
14487  sface1.sh = subfacearray[i];
14488  p1 = (point) sface1.sh[3];
14489  p2 = (point) sface1.sh[4];
14490  p3 = (point) sface1.sh[5];
14491  for (j = i + 1; j < arraysize; j++) {
14492  sface2.sh = subfacearray[j];
14493  p4 = (point) sface2.sh[3];
14494  p5 = (point) sface2.sh[4];
14495  p6 = (point) sface2.sh[5];
14496  intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
14497  if (intersect == INTERSECT || intersect == SHAREFACE) {
14498  if (!b->quiet) {
14499  if (intersect == INTERSECT) {
14500  printf(" Facet #%d intersects facet #%d at triangles:\n",
14501  shellmark(sface1), shellmark(sface2));
14502  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14503  pointmark(p1), pointmark(p2), pointmark(p3),
14504  pointmark(p4), pointmark(p5), pointmark(p6));
14505  } else {
14506  printf(" Facet #%d duplicates facet #%d at triangle:\n",
14507  shellmark(sface1), shellmark(sface2));
14508  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14509  pointmark(p1), pointmark(p2), pointmark(p3),
14510  pointmark(p4), pointmark(p5), pointmark(p6));
14511  }
14512  }
14513  // Increase the number of intersecting pairs.
14514  (*internum)++;
14515  // Infect these two faces (although they may already be infected).
14516  sinfect(sface1);
14517  sinfect(sface2);
14518  }
14519  }
14520  }
14521  // Don't forget to free all three arrays. No further partition.
14522  delete [] leftarray;
14523  delete [] rightarray;
14524  delete [] subfacearray;
14525  }
14526 }
14527 
14529 // //
14530 // detectinterfaces() Detect intersecting triangles. //
14531 // //
14532 // Given a set of triangles, find the pairs of intersecting triangles from //
14533 // them. Here the set of triangles is in 'subfaces' which is a surface mesh //
14534 // of a PLC (.poly or .smesh). //
14535 // //
14536 // To detect whether two triangles are intersecting is done by the routine //
14537 // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
14538 // It is based on geometric orientation test which uses exact arithmetics. //
14539 // //
14540 // Use divide-and-conquer algorithm for reducing the number of intersection //
14541 // tests. Start from the bounding box of the input point set, recursively //
14542 // partition the box into smaller boxes, until the number of triangles in a //
14543 // box is not decreased anymore. Then perform triangle-triangle tests on the //
14544 // remaining set of triangles. The memory allocated in the input set is //
14545 // freed immediately after it has been partitioned into two arrays. So it //
14546 // can be re-used for the consequent partitions. //
14547 // //
14548 // On return, the pool 'subfaces' will be cleared, and only the intersecting //
14549 // triangles remain for output (to a .face file). //
14550 // //
14552 
14554 {
14555  shellface **subfacearray;
14556  face shloop;
14557  int internum;
14558  int i;
14559 
14560  if (!b->quiet) {
14561  printf("Detecting self-intersecting facets...\n");
14562  }
14563 
14564  // Construct a map from indices to subfaces;
14565  subfacearray = new shellface*[subfaces->items];
14567  shloop.sh = shellfacetraverse(subfaces);
14568  i = 0;
14569  while (shloop.sh != (shellface *) NULL) {
14570  subfacearray[i] = shloop.sh;
14571  shloop.sh = shellfacetraverse(subfaces);
14572  i++;
14573  }
14574 
14575  internum = 0;
14576  // Recursively split the set of triangles into two sets using a cut plane
14577  // parallel to x-, or, y-, or z-axis. Stop splitting when the number
14578  // of subfaces is not decreasing anymore. Do tests on the current set.
14579  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
14580  zmin, zmax, &internum);
14581 
14582  if (!b->quiet) {
14583  if (internum > 0) {
14584  printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
14585  } else {
14586  printf("\nNo faces are intersecting.\n\n");
14587  }
14588  }
14589 
14590  if (internum > 0) {
14591  // Traverse all subfaces, deallocate those have not been infected (they
14592  // are not intersecting faces). Uninfect those have been infected.
14593  // After this loop, only intersecting faces remain.
14595  shloop.sh = shellfacetraverse(subfaces);
14596  while (shloop.sh != (shellface *) NULL) {
14597  if (sinfected(shloop)) {
14598  suninfect(shloop);
14599  } else {
14600  shellfacedealloc(subfaces, shloop.sh);
14601  }
14602  shloop.sh = shellfacetraverse(subfaces);
14603  }
14604  } else {
14605  // Deallocate all subfaces.
14606  subfaces->restart();
14607  }
14608 }
14609 
14613 
14617 
14619 // //
14620 // makesegmentendpointsmap() Create a map from a segment to its endpoints.//
14621 // //
14622 // The map is saved in the array 'segmentendpointslist'. The length of this //
14623 // array is twice the number of segments. Each segment is assigned a unique //
14624 // index (starting from 0). //
14625 // //
14627 
14629 {
14630  arraypool *segptlist;
14631  face segloop, prevseg, nextseg;
14632  point eorg, edest, *parypt;
14633  int segindex = 0, idx = 0;
14634  int i;
14635 
14636  if (b->verbose > 0) {
14637  printf(" Creating the segment-endpoints map.\n");
14638  }
14639 
14640  segptlist = new arraypool(2 * sizeof(point), 10);
14641 
14642  // A segment s may have been split into many subsegments. Operate the one
14643  // which contains the origin of s. Then mark the rest of subsegments.
14645  segloop.sh = shellfacetraverse(subsegs);
14646  segloop.shver = 0;
14647  while (segloop.sh != NULL) {
14648  senext2(segloop, prevseg);
14649  spivotself(prevseg);
14650  if (prevseg.sh == NULL) {
14651  eorg = sorg(segloop);
14652  edest = sdest(segloop);
14653  setfacetindex(segloop, segindex);
14654  senext(segloop, nextseg);
14655  spivotself(nextseg);
14656  while (nextseg.sh != NULL) {
14657  setfacetindex(nextseg, segindex);
14658  nextseg.shver = 0;
14659  if (sorg(nextseg) != edest) sesymself(nextseg);
14660  assert(sorg(nextseg) == edest);
14661  edest = sdest(nextseg);
14662  // Go the next connected subsegment at edest.
14663  senextself(nextseg);
14664  spivotself(nextseg);
14665  }
14666  segptlist->newindex((void **) &parypt);
14667  parypt[0] = eorg;
14668  parypt[1] = edest;
14669  segindex++;
14670  }
14671  segloop.sh = shellfacetraverse(subsegs);
14672  }
14673 
14674  if (b->verbose) {
14675  printf(" Found %ld segments.\n", segptlist->objects);
14676  }
14677 
14678  segmentendpointslist = new point[segptlist->objects * 2];
14679 
14680  totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
14681 
14682  for (i = 0; i < segptlist->objects; i++) {
14683  parypt = (point *) fastlookup(segptlist, i);
14684  segmentendpointslist[idx++] = parypt[0];
14685  segmentendpointslist[idx++] = parypt[1];
14686  }
14687 
14688  delete segptlist;
14689 }
14690 
14691 
14693 // //
14694 // finddirection() Find the tet on the path from one point to another. //
14695 // //
14696 // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
14697 // 'searchtet' contains a tet on the path, its origin does not change. //
14698 // //
14699 // The return value indicates one of the following cases (let 'searchtet' be //
14700 // abcd, a is the origin of the path): //
14701 // - ACROSSVERT, edge ab is collinear with the path; //
14702 // - ACROSSEDGE, edge bc intersects with the path; //
14703 // - ACROSSFACE, face bcd intersects with the path. //
14704 // //
14705 // WARNING: This routine is designed for convex triangulations, and will not //
14706 // generally work after the holes and concavities have been carved. //
14707 // //
14709 
14712 {
14713  triface neightet;
14714  point pa, pb, pc, pd;
14715  enum {HMOVE, RMOVE, LMOVE} nextmove;
14716  REAL hori, rori, lori;
14717  int t1ver;
14718  int s;
14719 
14720  // The origin is fixed.
14721  pa = org(*searchtet);
14722  if ((point) searchtet->tet[7] == dummypoint) {
14723  // A hull tet. Choose the neighbor of its base face.
14724  decode(searchtet->tet[3], *searchtet);
14725  // Reset the origin to be pa.
14726  if ((point) searchtet->tet[4] == pa) {
14727  searchtet->ver = 11;
14728  } else if ((point) searchtet->tet[5] == pa) {
14729  searchtet->ver = 3;
14730  } else if ((point) searchtet->tet[6] == pa) {
14731  searchtet->ver = 7;
14732  } else {
14733  assert((point) searchtet->tet[7] == pa);
14734  searchtet->ver = 0;
14735  }
14736  }
14737 
14738  pb = dest(*searchtet);
14739  // Check whether the destination or apex is 'endpt'.
14740  if (pb == endpt) {
14741  // pa->pb is the search edge.
14742  return ACROSSVERT;
14743  }
14744 
14745  pc = apex(*searchtet);
14746  if (pc == endpt) {
14747  // pa->pc is the search edge.
14748  eprevesymself(*searchtet);
14749  return ACROSSVERT;
14750  }
14751 
14752  // Walk through tets around pa until the right one is found.
14753  while (1) {
14754 
14755  pd = oppo(*searchtet);
14756  // Check whether the opposite vertex is 'endpt'.
14757  if (pd == endpt) {
14758  // pa->pd is the search edge.
14759  esymself(*searchtet);
14760  enextself(*searchtet);
14761  return ACROSSVERT;
14762  }
14763  // Check if we have entered outside of the domain.
14764  if (pd == dummypoint) {
14765  // This is possible when the mesh is non-convex.
14766  assert(nonconvex);
14767  return ACROSSSUB; // Hit a bounday.
14768  }
14769 
14770  // Now assume that the base face abc coincides with the horizon plane,
14771  // and d lies above the horizon. The search point 'endpt' may lie
14772  // above or below the horizon. We test the orientations of 'endpt'
14773  // with respect to three planes: abc (horizon), bad (right plane),
14774  // and acd (left plane).
14775  hori = orient3d(pa, pb, pc, endpt);
14776  rori = orient3d(pb, pa, pd, endpt);
14777  lori = orient3d(pa, pc, pd, endpt);
14778 
14779  // Now decide the tet to move. It is possible there are more than one
14780  // tets are viable moves. Is so, randomly choose one.
14781  if (hori > 0) {
14782  if (rori > 0) {
14783  if (lori > 0) {
14784  // Any of the three neighbors is a viable move.
14785  s = randomnation(3);
14786  if (s == 0) {
14787  nextmove = HMOVE;
14788  } else if (s == 1) {
14789  nextmove = RMOVE;
14790  } else {
14791  nextmove = LMOVE;
14792  }
14793  } else {
14794  // Two tets, below horizon and below right, are viable.
14795  //s = randomnation(2);
14796  if (randomnation(2)) {
14797  nextmove = HMOVE;
14798  } else {
14799  nextmove = RMOVE;
14800  }
14801  }
14802  } else {
14803  if (lori > 0) {
14804  // Two tets, below horizon and below left, are viable.
14805  //s = randomnation(2);
14806  if (randomnation(2)) {
14807  nextmove = HMOVE;
14808  } else {
14809  nextmove = LMOVE;
14810  }
14811  } else {
14812  // The tet below horizon is chosen.
14813  nextmove = HMOVE;
14814  }
14815  }
14816  } else {
14817  if (rori > 0) {
14818  if (lori > 0) {
14819  // Two tets, below right and below left, are viable.
14820  //s = randomnation(2);
14821  if (randomnation(2)) {
14822  nextmove = RMOVE;
14823  } else {
14824  nextmove = LMOVE;
14825  }
14826  } else {
14827  // The tet below right is chosen.
14828  nextmove = RMOVE;
14829  }
14830  } else {
14831  if (lori > 0) {
14832  // The tet below left is chosen.
14833  nextmove = LMOVE;
14834  } else {
14835  // 'endpt' lies either on the plane(s) or across face bcd.
14836  if (hori == 0) {
14837  if (rori == 0) {
14838  // pa->'endpt' is COLLINEAR with pa->pb.
14839  return ACROSSVERT;
14840  }
14841  if (lori == 0) {
14842  // pa->'endpt' is COLLINEAR with pa->pc.
14843  eprevesymself(*searchtet); // // [a,c,d]
14844  return ACROSSVERT;
14845  }
14846  // pa->'endpt' crosses the edge pb->pc.
14847  return ACROSSEDGE;
14848  }
14849  if (rori == 0) {
14850  if (lori == 0) {
14851  // pa->'endpt' is COLLINEAR with pa->pd.
14852  esymself(*searchtet); // face bad.
14853  enextself(*searchtet); // face [a,d,b]
14854  return ACROSSVERT;
14855  }
14856  // pa->'endpt' crosses the edge pb->pd.
14857  esymself(*searchtet); // face bad.
14858  enextself(*searchtet); // face adb
14859  return ACROSSEDGE;
14860  }
14861  if (lori == 0) {
14862  // pa->'endpt' crosses the edge pc->pd.
14863  eprevesymself(*searchtet); // [a,c,d]
14864  return ACROSSEDGE;
14865  }
14866  // pa->'endpt' crosses the face bcd.
14867  return ACROSSFACE;
14868  }
14869  }
14870  }
14871 
14872  // Move to the next tet, fix pa as its origin.
14873  if (nextmove == RMOVE) {
14874  fnextself(*searchtet);
14875  } else if (nextmove == LMOVE) {
14876  eprevself(*searchtet);
14877  fnextself(*searchtet);
14878  enextself(*searchtet);
14879  } else { // HMOVE
14880  fsymself(*searchtet);
14881  enextself(*searchtet);
14882  }
14883  assert(org(*searchtet) == pa);
14884  pb = dest(*searchtet);
14885  pc = apex(*searchtet);
14886 
14887  } // while (1)
14888 
14889 }
14890 
14892 // //
14893 // scoutsegment() Search an edge in the tetrahedralization. //
14894 // //
14895 // If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the //
14896 // edge from startpt to endpt. //
14897 // //
14898 // If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
14899 // indicates that the edge intersects an edge or a face. If 'refpt' is NULL,//
14900 // 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns //
14901 // a vertex which encroaches upon this edge, and 'searchtet' returns a tet //
14902 // which containing 'refpt'. //
14903 // //
14904 // The following cases can happen when the input PLC is not valid. //
14905 // - ACROSSVERT, the edge intersects a vertex return by the origin of //
14906 // 'searchtet'. //
14907 // - ACROSSSEG, the edge intersects a segment returned by 'searchtet'. //
14908 // - ACROSSSUB, the edge intersects a subface returned by 'searchtet'. //
14909 // //
14911 
14913  tetgenmesh::scoutsegment(point startpt, point endpt, triface* searchtet,
14914  point* refpt, arraypool* intfacelist)
14915 {
14916  point pd;
14917  enum interresult dir;
14918  int t1ver;
14919 
14920  if (b->verbose > 2) {
14921  printf(" Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
14922  }
14923 
14924  point2tetorg(startpt, *searchtet);
14925  dir = finddirection(searchtet, endpt);
14926 
14927  if (dir == ACROSSVERT) {
14928  pd = dest(*searchtet);
14929  if (pd == endpt) {
14930  // The job is done.
14931  return SHAREEDGE;
14932  } else {
14933  // A point is on the path.
14934  // Let the origin of the searchtet be the vertex.
14935  enextself(*searchtet);
14936  if (refpt) *refpt = pd;
14937  return ACROSSVERT;
14938  }
14939  } // if (dir == ACROSSVERT)
14940 
14941  // dir is either ACROSSEDGE or ACROSSFACE.
14942 
14943  enextesymself(*searchtet); // Go to the opposite face.
14944  fsymself(*searchtet); // Enter the adjacent tet.
14945 
14946  if (dir == ACROSSEDGE) {
14947  // Check whether two segments are intersecting.
14948  if (issubseg(*searchtet)) {
14949  return ACROSSSEG;
14950  }
14951  } else if (dir == ACROSSFACE) {
14952  if (checksubfaceflag) {
14953  // Check whether a segment and a subface are intersecting.
14954  if (issubface(*searchtet)) {
14955  return ACROSSSUB;
14956  }
14957  }
14958  }
14959 
14960  if (refpt == NULL) {
14961  // Do not need a reference point. Return.
14962  return dir;
14963  }
14964 
14965  triface neightet, reftet;
14966  point pa, pb, pc;
14967  REAL angmax, ang;
14968  int types[2], poss[4];
14969  int pos = 0, i, j;
14970 
14971  pa = org(*searchtet);
14972  angmax = interiorangle(pa, startpt, endpt, NULL);
14973  *refpt = pa;
14974  pb = dest(*searchtet);
14975  ang = interiorangle(pb, startpt, endpt, NULL);
14976  if (ang > angmax) {
14977  angmax = ang;
14978  *refpt = pb;
14979  }
14980  pc = apex(*searchtet);
14981  ang = interiorangle(pc, startpt, endpt, NULL);
14982  if (ang > angmax) {
14983  angmax = ang;
14984  *refpt = pc;
14985  }
14986  reftet = *searchtet; // Save the tet containing the refpt.
14987 
14988  // Search intersecting faces along the segment.
14989  while (1) {
14990 
14991 
14992  pd = oppo(*searchtet);
14993  assert(pd != dummypoint); // SELF_CHECK
14994 
14995 
14996  // Stop if we meet 'endpt'.
14997  if (pd == endpt) break;
14998 
14999  ang = interiorangle(pd, startpt, endpt, NULL);
15000  if (ang > angmax) {
15001  angmax = ang;
15002  *refpt = pd;
15003  reftet = *searchtet;
15004  }
15005 
15006  // Find a face intersecting the segment.
15007  if (dir == ACROSSFACE) {
15008  // One of the three oppo faces in 'searchtet' intersects the segment.
15009  neightet = *searchtet;
15010  j = (neightet.ver & 3); // j is the current face number.
15011  for (i = j + 1; i < j + 4; i++) {
15012  neightet.ver = (i % 4);
15013  pa = org(neightet);
15014  pb = dest(neightet);
15015  pc = apex(neightet);
15016  pd = oppo(neightet); // The above point.
15017  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15018  dir = (enum interresult) types[0];
15019  pos = poss[0];
15020  break;
15021  } else {
15022  dir = DISJOINT;
15023  pos = 0;
15024  }
15025  }
15026  assert(dir != DISJOINT); // SELF_CHECK
15027  } else { // dir == ACROSSEDGE
15028  // Check the two opposite faces (of the edge) in 'searchtet'.
15029  for (i = 0; i < 2; i++) {
15030  if (i == 0) {
15031  enextesym(*searchtet, neightet);
15032  } else {
15033  eprevesym(*searchtet, neightet);
15034  }
15035  pa = org(neightet);
15036  pb = dest(neightet);
15037  pc = apex(neightet);
15038  pd = oppo(neightet); // The above point.
15039  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15040  dir = (enum interresult) types[0];
15041  pos = poss[0];
15042  break;
15043  } else {
15044  dir = DISJOINT;
15045  pos = 0;
15046  }
15047  }
15048  if (dir == DISJOINT) {
15049  // No intersection. Rotate to the next tet at the edge.
15050  dir = ACROSSEDGE;
15051  fnextself(*searchtet);
15052  continue;
15053  }
15054  }
15055 
15056  if (dir == ACROSSVERT) {
15057  // This segment passing a vertex. Choose it and return.
15058  for (i = 0; i < pos; i++) {
15059  enextself(neightet);
15060  }
15061  pd = org(neightet);
15062  *refpt = pd;
15063  // break;
15064  return ACROSSVERT;
15065  } else if (dir == ACROSSEDGE) {
15066  // Get the edge intersects with the segment.
15067  for (i = 0; i < pos; i++) {
15068  enextself(neightet);
15069  }
15070  }
15071  // Go to the next tet.
15072  fsym(neightet, *searchtet);
15073 
15074  if (dir == ACROSSEDGE) {
15075  // Check whether two segments are intersecting.
15076  if (issubseg(*searchtet)) {
15077  return ACROSSSEG;
15078  }
15079  } else if (dir == ACROSSFACE) {
15080  if (checksubfaceflag) {
15081  // Check whether a segment and a subface are intersecting.
15082  if (issubface(*searchtet)) {
15083  return ACROSSSUB;
15084  }
15085  }
15086  }
15087 
15088  } // while (1)
15089 
15090  // A valid reference point should inside the diametrial circumsphere of
15091  // the missing segment, i.e., it encroaches upon it.
15092  if (2.0 * angmax < PI) {
15093  *refpt = NULL;
15094  }
15095 
15096 
15097  *searchtet = reftet;
15098  return dir;
15099 }
15100 
15102 // //
15103 // getsteinerpointonsegment() Get a Steiner point on a segment. //
15104 // //
15105 // Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
15106 // wise, return '0'. //
15107 // //
15109 
15111 {
15112  point ei = sorg(*seg);
15113  point ej = sdest(*seg);
15114  int adjflag = 0, i;
15115 
15116  if (refpt != NULL) {
15117  REAL L, L1, t;
15118 
15119  if (pointtype(refpt) == FREESEGVERTEX) {
15120  face parentseg;
15121  sdecode(point2sh(refpt), parentseg);
15122  int sidx1 = getfacetindex(parentseg);
15123  point far_pi = segmentendpointslist[sidx1 * 2];
15124  point far_pj = segmentendpointslist[sidx1 * 2 + 1];
15125  int sidx2 = getfacetindex(*seg);
15126  point far_ei = segmentendpointslist[sidx2 * 2];
15127  point far_ej = segmentendpointslist[sidx2 * 2 + 1];
15128  if ((far_pi == far_ei) || (far_pj == far_ei)) {
15129  // Create a Steiner point at the intersection of the segment
15130  // [far_ei, far_ej] and the sphere centered at far_ei with
15131  // radius |far_ei - refpt|.
15132  L = distance(far_ei, far_ej);
15133  L1 = distance(far_ei, refpt);
15134  t = L1 / L;
15135  for (i = 0; i < 3; i++) {
15136  steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
15137  }
15138  adjflag = 1;
15139  } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
15140  L = distance(far_ei, far_ej);
15141  L1 = distance(far_ej, refpt);
15142  t = L1 / L;
15143  for (i = 0; i < 3; i++) {
15144  steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
15145  }
15146  adjflag = 1;
15147  } else {
15148  // Cut the segment by the projection point of refpt.
15149  projpt2edge(refpt, ei, ej, steinpt);
15150  }
15151  } else {
15152  // Cut the segment by the projection point of refpt.
15153  projpt2edge(refpt, ei, ej, steinpt);
15154  }
15155 
15156  // Make sure that steinpt is not too close to ei and ej.
15157  L = distance(ei, ej);
15158  L1 = distance(steinpt, ei);
15159  t = L1 / L;
15160  if ((t < 0.2) || (t > 0.8)) {
15161  // Split the point at the middle.
15162  for (i = 0; i < 3; i++) {
15163  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15164  }
15165  }
15166  } else {
15167  // Split the point at the middle.
15168  for (i = 0; i < 3; i++) {
15169  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15170  }
15171  }
15172 
15173 
15174  return adjflag;
15175 }
15176 
15177 
15178 
15180 // //
15181 // delaunizesegments() Recover segments in a DT. //
15182 // //
15183 // All segments need to be recovered are in 'subsegstack' (Q). They will be //
15184 // be recovered one by one (in a random order). //
15185 // //
15186 // Given a segment s in the Q, this routine first queries s in the DT, if s //
15187 // matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split //
15188 // by inserting a new point p in both the DT and itself. The two new subseg- //
15189 // ments of s are queued in Q. The process continues until Q is empty. //
15190 // //
15192 
15194 {
15195  triface searchtet, spintet;
15196  face searchsh;
15197  face sseg, *psseg;
15198  point refpt, newpt;
15199  enum interresult dir;
15200  insertvertexflags ivf;
15201  int t1ver;
15202 
15203 
15204  ivf.bowywat = 1; // Use Bowyer-Watson insertion.
15205  ivf.assignmeshsize = b->metric;
15206  ivf.sloc = (int) ONEDGE; // on 'sseg'.
15207  ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
15208 
15209  // Loop until 'subsegstack' is empty.
15210  while (subsegstack->objects > 0l) {
15211  // seglist is used as a stack.
15212  subsegstack->objects--;
15214  sseg = *psseg;
15215 
15216  // Check if this segment has been recovered.
15217  sstpivot1(sseg, searchtet);
15218  if (searchtet.tet != NULL) {
15219  continue; // Not a missing segment.
15220  }
15221 
15222  // Search the segment.
15223  dir = scoutsegment(sorg(sseg), sdest(sseg), &searchtet, &refpt, NULL);
15224 
15225  if (dir == SHAREEDGE) {
15226  // Found this segment, insert it.
15227  if (!issubseg(searchtet)) {
15228  // Let the segment remember an adjacent tet.
15229  sstbond1(sseg, searchtet);
15230  // Bond the segment to all tets containing it.
15231  spintet = searchtet;
15232  do {
15233  tssbond1(spintet, sseg);
15234  fnextself(spintet);
15235  } while (spintet.tet != searchtet.tet);
15236  } else {
15237  // Collision! Maybe a bug.
15238  assert(0);
15239  }
15240  } else {
15241  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15242  // The segment is missing. Split it.
15243  // Create a new point.
15244  makepoint(&newpt, FREESEGVERTEX);
15245  //setpointtype(newpt, FREESEGVERTEX);
15246  getsteinerptonsegment(&sseg, refpt, newpt);
15247 
15248  // Start searching from 'searchtet'.
15249  ivf.iloc = (int) OUTSIDE;
15250  // Insert the new point into the tetrahedralization T.
15251  // Missing segments and subfaces are queued for recovery.
15252  // Note that T is convex (nonconvex = 0).
15253  if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
15254  // The new point has been inserted.
15255  st_segref_count++;
15256  if (steinerleft > 0) steinerleft--;
15257  } else {
15258  assert (ivf.iloc == (enum locateresult) NEARVERTEX);
15259  terminatetetgen(this, 4);
15260  }
15261  } else {
15262  // Indicate it is an input problem.
15263  terminatetetgen(this, 3);
15264  }
15265  }
15266  } // while
15267 }
15268 
15270 // //
15271 // scoutsubface() Search subface in the tetrahedralization. //
15272 // //
15273 // 'searchsh' is searched in T. If it exists, it is 'locked' at the face in //
15274 // T. 'searchtet' refers to the face. Otherwise, it is missing. //
15275 // //
15276 // The return value indicates one of the following cases: //
15277 // - SHAREFACE, 'searchsh' exists and is inserted in T. //
15278 // - COLLISIONFACE, 'searchsh' exists in T, but it conflicts with another //
15279 // subface which was inserted earlier. It is not inserted. //
15280 // //
15282 
15284  tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
15285 {
15286  triface spintet;
15287  point pa, pb, pc;
15288  enum interresult dir;
15289  int t1ver;
15290 
15291  pa = sorg(*searchsh);
15292  pb = sdest(*searchsh);
15293 
15294 
15295  // Get a tet whose origin is a.
15296  point2tetorg(pa, *searchtet);
15297  // Search the edge [a,b].
15298  dir = finddirection(searchtet, pb);
15299  if (dir == ACROSSVERT) {
15300  // Check validity of a PLC.
15301  if (dest(*searchtet) != pb) {
15302  // A vertex lies on the search edge.
15303  enextself(*searchtet);
15304  // It is possible a PLC self-intersection problem.
15305  terminatetetgen(this, 3);
15306  return TOUCHEDGE;
15307  }
15308  // The edge exists. Check if the face exists.
15309  pc = sapex(*searchsh);
15310  // Searchtet holds edge [a,b]. Search a face with apex c.
15311  spintet = *searchtet;
15312  while (1) {
15313  if (apex(spintet) == pc) {
15314  // Found a face matching to 'searchsh'!
15315  if (!issubface(spintet)) {
15316  // Insert 'searchsh'.
15317  tsbond(spintet, *searchsh);
15318  fsymself(spintet);
15319  sesymself(*searchsh);
15320  tsbond(spintet, *searchsh);
15321  *searchtet = spintet;
15322  return SHAREFACE;
15323  } else {
15324  // Another subface is already inserted.
15325  face checksh;
15326  tspivot(spintet, checksh);
15327  assert(checksh.sh != searchsh->sh); // SELF_CHECK
15328  // This is possibly an input problem, i.e., two facets overlap.
15329  // Report this problem and exit.
15330  printf("Warning: Found two facets nearly overlap.\n");
15331  terminatetetgen(this, 5);
15332  // unifysubfaces(&checksh, searchsh);
15333  *searchtet = spintet;
15334  return COLLISIONFACE;
15335  }
15336  }
15337  fnextself(spintet);
15338  if (spintet.tet == searchtet->tet) break;
15339  }
15340  }
15341 
15342  // dir is either ACROSSEDGE or ACROSSFACE.
15343  return dir;
15344 }
15345 
15347 // //
15348 // formregion() Form the missing region of a missing subface. //
15349 // //
15350 // 'missh' is a missing subface. From it we form a missing region R which is //
15351 // a connected region formed by a set of missing subfaces of a facet. //
15352 // Comment: There should be no segment inside R. //
15353 // //
15354 // 'missingshs' returns the list of subfaces in R. All subfaces in this list //
15355 // are oriented as the 'missh'. 'missingshbds' returns the list of boundary //
15356 // edges (tetrahedral handles) of R. 'missingshverts' returns all vertices //
15357 // of R. They are all pmarktested. //
15358 // //
15359 // Except the first one (which is 'missh') in 'missingshs', each subface in //
15360 // this list represents an internal edge of R, i.e., it is missing in the //
15361 // tetrahedralization. Since R may contain interior vertices, not all miss- //
15362 // ing edges can be found by this way. //
15364 
15365 void tetgenmesh::formregion(face* missh, arraypool* missingshs,
15366  arraypool* missingshbds, arraypool* missingshverts)
15367 {
15368  triface searchtet, spintet;
15369  face neighsh, *parysh;
15370  face neighseg, fakeseg;
15371  point pa, pb, *parypt;
15372  enum interresult dir;
15373  int t1ver;
15374  int i, j;
15375 
15376  smarktest(*missh);
15377  missingshs->newindex((void **) &parysh);
15378  *parysh = *missh;
15379 
15380  // Incrementally find other missing subfaces.
15381  for (i = 0; i < missingshs->objects; i++) {
15382  missh = (face *) fastlookup(missingshs, i);
15383  for (j = 0; j < 3; j++) {
15384  pa = sorg(*missh);
15385  pb = sdest(*missh);
15386  point2tetorg(pa, searchtet);
15387  dir = finddirection(&searchtet, pb);
15388  if (dir != ACROSSVERT) {
15389  // This edge is missing. Its neighbor is a missing subface.
15390  spivot(*missh, neighsh);
15391  if (!smarktested(neighsh)) {
15392  // Adjust the face orientation.
15393  if (sorg(neighsh) != pb) sesymself(neighsh);
15394  smarktest(neighsh);
15395  missingshs->newindex((void **) &parysh);
15396  *parysh = neighsh;
15397  }
15398  } else {
15399  if (dest(searchtet) != pb) {
15400  // This might be a self-intersection problem.
15401  terminatetetgen(this, 3);
15402  }
15403  }
15404  // Collect the vertices of R.
15405  if (!pmarktested(pa)) {
15406  pmarktest(pa);
15407  missingshverts->newindex((void **) &parypt);
15408  *parypt = pa;
15409  }
15410  senextself(*missh);
15411  } // j
15412  } // i
15413 
15414  // Get the boundary edges of R.
15415  for (i = 0; i < missingshs->objects; i++) {
15416  missh = (face *) fastlookup(missingshs, i);
15417  for (j = 0; j < 3; j++) {
15418  spivot(*missh, neighsh);
15419  if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
15420  // A boundary edge of R.
15421  // Let the segment point to the adjacent tet.
15422  point2tetorg(sorg(*missh), searchtet);
15423  finddirection(&searchtet, sdest(*missh));
15424  missingshbds->newindex((void **) &parysh);
15425  *parysh = *missh;
15426  // Check if this edge is a segment.
15427  sspivot(*missh, neighseg);
15428  if (neighseg.sh == NULL) {
15429  // Temporarily create a segment at this edge.
15430  makeshellface(subsegs, &fakeseg);
15431  setsorg(fakeseg, sorg(*missh));
15432  setsdest(fakeseg, sdest(*missh));
15433  sinfect(fakeseg); // Mark it as faked.
15434  // Connect it to all tets at this edge.
15435  spintet = searchtet;
15436  while (1) {
15437  tssbond1(spintet, fakeseg);
15438  fnextself(spintet);
15439  if (spintet.tet == searchtet.tet) break;
15440  }
15441  neighseg = fakeseg;
15442  }
15443  // Let the segment and the boundary edge point to each other.
15444  ssbond(*missh, neighseg);
15445  sstbond1(neighseg, searchtet);
15446  }
15447  senextself(*missh);
15448  } // j
15449  } // i
15450 
15451 
15452  // Unmarktest collected missing subfaces.
15453  for (i = 0; i < missingshs->objects; i++) {
15454  parysh = (face *) fastlookup(missingshs, i);
15455  sunmarktest(*parysh);
15456  }
15457 }
15458 
15460 // //
15461 // scoutcrossedge() Search an edge that crosses the missing region. //
15462 // //
15463 // Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
15464 // over, the edge is oriented such that its origin lies below R. Return 0 //
15465 // if no such edge is found. //
15466 // //
15467 // Assumption: All vertices of the missing region are marktested. //
15468 // //
15470 
15471 int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds,
15472  arraypool* missingshs)
15473 {
15474  triface searchtet, spintet;
15475  face *parysh;
15476  face neighseg;
15477  point pa, pb, pc, pd, pe;
15478  enum interresult dir;
15479  REAL ori;
15480  int types[2], poss[4];
15481  int searchflag, interflag;
15482  int t1ver;
15483  int i, j;
15484 
15485  searchflag = 0;
15486 
15487  for (j = 0; j < missingshbds->objects && !searchflag; j++) {
15488  parysh = (face *) fastlookup(missingshbds, j);
15489  sspivot(*parysh, neighseg);
15490  sstpivot1(neighseg, searchtet);
15491  interflag = 0;
15492  // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
15493  spintet = searchtet;
15494  while (1) {
15495  pd = apex(spintet);
15496  pe = oppo(spintet);
15497  // Skip a hull edge.
15498  if ((pd != dummypoint) && (pe != dummypoint)) {
15499  // Skip an edge containing a vertex of R.
15500  if (!pmarktested(pd) && !pmarktested(pe)) {
15501  // Check if [d,e] intersects R.
15502  for (i = 0; i < missingshs->objects && !interflag; i++) {
15503  parysh = (face *) fastlookup(missingshs, i);
15504  pa = sorg(*parysh);
15505  pb = sdest(*parysh);
15506  pc = sapex(*parysh);
15507  interflag=tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
15508  if (interflag > 0) {
15509  if (interflag == 2) {
15510  // They intersect at a single point.
15511  dir = (enum interresult) types[0];
15512  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15513  //pos = poss[0];
15514  // Go to the crossing edge [d,e,#,#].
15515  edestoppo(spintet, crosstet); // // [d,e,#,#].
15516  // Check if it is a segment.
15517  if (issubseg(crosstet)) {
15518  //face checkseg;
15519  //tsspivot1(crosstet, checkseg);
15520  //reportselfintersect(&checkseg, parysh);
15521  terminatetetgen(this, 3);
15522  }
15523  // Adjust the edge such that d lies below [a,b,c].
15524  ori = orient3d(pa, pb, pc, pd);
15525  assert(ori != 0);
15526  if (ori < 0) {
15527  esymself(crosstet);
15528  }
15529  searchflag = 1;
15530  }
15531  }
15532  break;
15533  } // if (interflag > 0)
15534  }
15535  }
15536  }
15537  // Leave search at this bdry edge if an intersection is found.
15538  if (interflag > 0) break;
15539  // Go to the next tetrahedron.
15540  fnextself(spintet);
15541  if (spintet.tet == searchtet.tet) break;
15542  } // while (1)
15543  } // j
15544 
15545  return searchflag;
15546 }
15547 
15549 // //
15550 // formcavity() Form the cavity of a missing region. //
15551 // //
15552 // The missing region R is formed by a set of missing subfaces 'missingshs'. //
15553 // In the following, we assume R is horizontal and oriented. (All subfaces //
15554 // of R are oriented in the same way.) 'searchtet' is a tetrahedron [d,e,#, //
15555 // #] which intersects R in its interior, where the edge [d,e] intersects R, //
15556 // and d lies below R. //
15557 // //
15558 // 'crosstets' returns the set of crossing tets. Every tet in it has the //
15559 // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R. The //
15560 // set of tets form the cavity C, which is divided into two parts by R, one //
15561 // at top and one at bottom. 'topfaces' and 'botfaces' return the upper and //
15562 // lower boundary faces of C. 'toppoints' contains vertices of 'crosstets' //
15563 // in the top part of C, and so does 'botpoints'. Both 'toppoints' and //
15564 // 'botpoints' contain vertices of R. //
15565 // //
15566 // Important: This routine assumes all vertices of the facet containing this //
15567 // subface are marked, i.e., pmarktested(p) returns true. //
15568 // //
15570 
15571 bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
15572  arraypool* crosstets, arraypool* topfaces,
15573  arraypool* botfaces, arraypool* toppoints,
15574  arraypool* botpoints)
15575 {
15576  arraypool *crossedges;
15577  triface spintet, neightet, *parytet;
15578  face *parysh = NULL;
15579  point pa, pd, pe, *parypt;
15580  enum interresult dir;
15581  bool testflag, invalidflag;
15582  int types[2], poss[4];
15583  int t1ver;
15584  int i, j, k;
15585 
15586  // Temporarily re-use 'topfaces' for all crossing edges.
15587  crossedges = topfaces;
15588 
15589  if (b->verbose > 2) {
15590  printf(" Form the cavity of a missing region.\n");
15591  }
15592  // Mark this edge to avoid testing it later.
15593  markedge(*searchtet);
15594  crossedges->newindex((void **) &parytet);
15595  *parytet = *searchtet;
15596 
15597  invalidflag = 0;
15598 
15599  // Collect all crossing tets. Each cross tet is saved in the standard
15600  // form [d,e,#,#], where [d,e] is a crossing edge, d lies below R.
15601  // NEITHER d NOR e is a vertex of R (!pmarktested).
15602  for (i = 0; i < crossedges->objects; i++) {
15603  // Get a crossing edge [d,e,#,#].
15604  searchtet = (triface *) fastlookup(crossedges, i);
15605 
15606  // Sort vertices into the bottom and top arrays.
15607  pd = org(*searchtet);
15608  if (!pinfected(pd)) {
15609  pinfect(pd);
15610  botpoints->newindex((void **) &parypt);
15611  *parypt = pd;
15612  }
15613  pe = dest(*searchtet);
15614  if (!pinfected(pe)) {
15615  pinfect(pe);
15616  toppoints->newindex((void **) &parypt);
15617  *parypt = pe;
15618  }
15619 
15620  // All tets sharing this edge are crossing tets.
15621  spintet = *searchtet;
15622  while (1) {
15623  if (!infected(spintet)) {
15624  infect(spintet);
15625  crosstets->newindex((void **) &parytet);
15626  *parytet = spintet;
15627  }
15628  // Go to the next crossing tet.
15629  fnextself(spintet);
15630  if (spintet.tet == searchtet->tet) break;
15631  } // while (1)
15632 
15633  // Detect new crossing edges.
15634  spintet = *searchtet;
15635  while (1) {
15636  // spintet is [d,e,a,#], where d lies below R, and e lies above R.
15637  pa = apex(spintet);
15638  if (pa != dummypoint) {
15639  if (!pmarktested(pa)) {
15640  // There exists a crossing edge, either [e,a] or [a,d]. First check
15641  // if the crossing edge has already be added, i.e., check if a
15642  // tetrahedron at this edge is marked.
15643  testflag = true;
15644  for (j = 0; j < 2 && testflag; j++) {
15645  if (j == 0) {
15646  enext(spintet, neightet);
15647  } else {
15648  eprev(spintet, neightet);
15649  }
15650  while (1) {
15651  if (edgemarked(neightet)) {
15652  // This crossing edge has already been tested. Skip it.
15653  testflag = false;
15654  break;
15655  }
15656  fnextself(neightet);
15657  if (neightet.tet == spintet.tet) break;
15658  }
15659  } // j
15660  if (testflag) {
15661  // Test if [e,a] or [a,d] intersects R.
15662  // Do a brute-force search in the set of subfaces of R. Slow!
15663  // Need to be improved!
15664  pd = org(spintet);
15665  pe = dest(spintet);
15666  for (k = 0; k < missingshs->objects; k++) {
15667  parysh = (face *) fastlookup(missingshs, k);
15668  if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15669  pe, pa, NULL, 1, types, poss)) {
15670  // Found intersection. 'a' lies below R.
15671  enext(spintet, neightet);
15672  dir = (enum interresult) types[0];
15673  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15674  // A valid intersection.
15675  } else {
15676  // A non-valid intersection. Maybe a PLC problem.
15677  invalidflag = 1;
15678  }
15679  break;
15680  }
15681  if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15682  pa, pd, NULL, 1, types, poss)) {
15683  // Found intersection. 'a' lies above R.
15684  eprev(spintet, neightet);
15685  dir = (enum interresult) types[0];
15686  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15687  // A valid intersection.
15688  } else {
15689  // A non-valid intersection. Maybe a PLC problem.
15690  invalidflag = 1;
15691  }
15692  break;
15693  }
15694  } // k
15695  if (k < missingshs->objects) {
15696  // Found a pair of triangle - edge intersection.
15697  if (invalidflag) {
15698  if (!b->quiet) {
15699  printf("Warning: A non-valid facet - edge intersection\n");
15700  printf(" subface: (%d, %d, %d) edge: (%d, %d)\n",
15701  pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
15702  pointmark(sapex(*parysh)), pointmark(org(neightet)),
15703  pointmark(dest(neightet)));
15704  }
15705  // It may be a PLC problem.
15706  terminatetetgen(this, 3);
15707  }
15708  // Adjust the edge direction, so that its origin lies below R,
15709  // and its destination lies above R.
15710  esymself(neightet);
15711  // Check if this edge is a segment.
15712  if (issubseg(neightet)) {
15713  // Invalid PLC!
15714  //face checkseg;
15715  //tsspivot1(neightet, checkseg);
15716  //reportselfintersect(&checkseg, parysh);
15717  terminatetetgen(this, 3);
15718  }
15719  // Mark this edge to avoid testing it again.
15720  markedge(neightet);
15721  crossedges->newindex((void **) &parytet);
15722  *parytet = neightet;
15723  } else {
15724  // No intersection is found. It may be a PLC problem.
15725  invalidflag = 1;
15726  // Split the subface intersecting [d,e].
15727  for (k = 0; k < missingshs->objects; k++) {
15728  parysh = (face *) fastlookup(missingshs, k);
15729  // Test if this face intersects [e,a].
15730  if (tri_edge_test(sorg(*parysh),sdest(*parysh),sapex(*parysh),
15731  pd, pe, NULL, 1, types, poss)) {
15732  break;
15733  }
15734  } // k
15735  if (k == missingshs->objects) {
15736  // Not found such an edge.
15737  // Arbitrarily choose an edge (except the first) to split.
15738  k = randomnation(missingshs->objects - 1);
15739  parysh = (face *) fastlookup(missingshs, k + 1);
15740  }
15741  recentsh = *parysh;
15742  recenttet = spintet; // For point location.
15743  break; // the while (1) loop
15744  } // if (k == missingshs->objects)
15745  } // if (testflag)
15746  } // if (!pmarktested(pa) || b->psc)
15747  } // if (pa != dummypoint)
15748  // Go to the next crossing tet.
15749  fnextself(spintet);
15750  if (spintet.tet == searchtet->tet) break;
15751  } // while (1)
15752 
15753  //if (b->psc) {
15754  if (invalidflag) break;
15755  //}
15756  } // i
15757 
15758  if (b->verbose > 2) {
15759  printf(" Formed cavity: %ld (%ld) cross tets (edges).\n",
15760  crosstets->objects, crossedges->objects);
15761  }
15762 
15763  // Unmark all marked edges.
15764  for (i = 0; i < crossedges->objects; i++) {
15765  searchtet = (triface *) fastlookup(crossedges, i);
15766  assert(edgemarked(*searchtet)); // SELF_CHECK
15767  unmarkedge(*searchtet);
15768  }
15769  crossedges->restart();
15770 
15771 
15772  if (invalidflag) {
15773  // Unmark all collected tets.
15774  for (i = 0; i < crosstets->objects; i++) {
15775  searchtet = (triface *) fastlookup(crosstets, i);
15776  uninfect(*searchtet);
15777  }
15778  // Unmark all collected vertices.
15779  for (i = 0; i < botpoints->objects; i++) {
15780  parypt = (point *) fastlookup(botpoints, i);
15781  puninfect(*parypt);
15782  }
15783  for (i = 0; i < toppoints->objects; i++) {
15784  parypt = (point *) fastlookup(toppoints, i);
15785  puninfect(*parypt);
15786  }
15787  crosstets->restart();
15788  botpoints->restart();
15789  toppoints->restart();
15790 
15791  // Randomly split an interior edge of R.
15792  i = randomnation(missingshs->objects - 1);
15793  recentsh = * (face *) fastlookup(missingshs, i);
15794  return false;
15795  }
15796 
15797 
15798  // Collect the top and bottom faces and the middle vertices. Since all top
15799  // and bottom vertices have been infected. Uninfected vertices must be
15800  // middle vertices (i.e., the vertices of R).
15801  // NOTE 1: Hull tets may be collected. Process them as a normal one.
15802  // NOTE 2: Some previously recovered subfaces may be completely inside the
15803  // cavity. In such case, we remove these subfaces from the cavity and put
15804  // them into 'subfacstack'. They will be recovered later.
15805  // NOTE 3: Some segments may be completely inside the cavity, e.g., they
15806  // attached to a subface which is inside the cavity. Such segments are
15807  // put in 'subsegstack'. They will be recovered later.
15808  // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
15809  // are identified in the routine "carvecavity()".
15810 
15811  for (i = 0; i < crosstets->objects; i++) {
15812  searchtet = (triface *) fastlookup(crosstets, i);
15813  // searchtet is [d,e,a,b].
15814  eorgoppo(*searchtet, spintet);
15815  fsym(spintet, neightet); // neightet is [a,b,e,#]
15816  if (!infected(neightet)) {
15817  // A top face.
15818  topfaces->newindex((void **) &parytet);
15819  *parytet = neightet;
15820  }
15821  edestoppo(*searchtet, spintet);
15822  fsym(spintet, neightet); // neightet is [b,a,d,#]
15823  if (!infected(neightet)) {
15824  // A bottom face.
15825  botfaces->newindex((void **) &parytet);
15826  *parytet = neightet;
15827  }
15828  // Add middle vertices if there are (skip dummypoint).
15829  pa = org(neightet);
15830  if (!pinfected(pa)) {
15831  if (pa != dummypoint) {
15832  pinfect(pa);
15833  botpoints->newindex((void **) &parypt);
15834  *parypt = pa;
15835  toppoints->newindex((void **) &parypt);
15836  *parypt = pa;
15837  }
15838  }
15839  pa = dest(neightet);
15840  if (!pinfected(pa)) {
15841  if (pa != dummypoint) {
15842  pinfect(pa);
15843  botpoints->newindex((void **) &parypt);
15844  *parypt = pa;
15845  toppoints->newindex((void **) &parypt);
15846  *parypt = pa;
15847  }
15848  }
15849  } // i
15850 
15851  // Uninfect all collected top, bottom, and middle vertices.
15852  for (i = 0; i < toppoints->objects; i++) {
15853  parypt = (point *) fastlookup(toppoints, i);
15854  puninfect(*parypt);
15855  }
15856  for (i = 0; i < botpoints->objects; i++) {
15857  parypt = (point *) fastlookup(botpoints, i);
15858  puninfect(*parypt);
15859  }
15860  cavitycount++;
15861 
15862  return true;
15863 }
15864 
15866 // //
15867 // delaunizecavity() Fill a cavity by Delaunay tetrahedra. //
15868 // //
15869 // The cavity C to be tetrahedralized is the top or bottom part of a whole //
15870 // cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
15871 // faces' do not form a closed polyhedron. The "open" side are subfaces of //
15872 // the missing facet. These faces will be recovered later in fillcavity(). //
15873 // //
15874 // This routine first constructs the DT of the vertices. Then it identifies //
15875 // the half boundary faces of the cavity in DT. Possiblely the cavity C will //
15876 // be enlarged. //
15877 // //
15878 // The DT is returned in 'newtets'. //
15879 // //
15881 
15883  arraypool *cavshells, arraypool *newtets,
15884  arraypool *crosstets, arraypool *misfaces)
15885 {
15886  triface searchtet, neightet, *parytet, *parytet1;
15887  face tmpsh, *parysh;
15888  point pa, pb, pc, pd, pt[3], *parypt;
15889  enum interresult dir;
15890  insertvertexflags ivf;
15891  REAL ori;
15892  long baknum, bakhullsize;
15893  int bakchecksubsegflag, bakchecksubfaceflag;
15894  int t1ver;
15895  int i, j;
15896 
15897  if (b->verbose > 2) {
15898  printf(" Delaunizing cavity: %ld points, %ld faces.\n",
15899  cavpoints->objects, cavfaces->objects);
15900  }
15901  // Remember the current number of crossing tets. It may be enlarged later.
15902  baknum = crosstets->objects;
15903  bakhullsize = hullsize;
15904  bakchecksubsegflag = checksubsegflag;
15905  bakchecksubfaceflag = checksubfaceflag;
15906  hullsize = 0l;
15907  checksubsegflag = 0;
15908  checksubfaceflag = 0;
15909  b->verbose--; // Suppress informations for creating Delaunay tetra.
15910  b->plc = 0; // Do not check near vertices.
15911 
15912  ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
15913 
15914  // Get four non-coplanar points (no dummypoint).
15915  pa = pb = pc = NULL;
15916  for (i = 0; i < cavfaces->objects; i++) {
15917  parytet = (triface *) fastlookup(cavfaces, i);
15918  parytet->ver = epivot[parytet->ver];
15919  if (apex(*parytet) != dummypoint) {
15920  pa = org(*parytet);
15921  pb = dest(*parytet);
15922  pc = apex(*parytet);
15923  break;
15924  }
15925  }
15926  pd = NULL;
15927  for (; i < cavfaces->objects; i++) {
15928  parytet = (triface *) fastlookup(cavfaces, i);
15929  pt[0] = org(*parytet);
15930  pt[1] = dest(*parytet);
15931  pt[2] = apex(*parytet);
15932  for (j = 0; j < 3; j++) {
15933  if (pt[j] != dummypoint) { // Do not include a hull point.
15934  ori = orient3d(pa, pb, pc, pt[j]);
15935  if (ori != 0) {
15936  pd = pt[j];
15937  if (ori > 0) { // Swap pa and pb.
15938  pt[j] = pa; pa = pb; pb = pt[j];
15939  }
15940  break;
15941  }
15942  }
15943  }
15944  if (pd != NULL) break;
15945  }
15946  assert(i < cavfaces->objects); // SELF_CHECK
15947 
15948  // Create an init DT.
15949  initialdelaunay(pa, pb, pc, pd);
15950 
15951  // Incrementally insert the vertices (duplicated vertices are ignored).
15952  for (i = 0; i < cavpoints->objects; i++) {
15953  pt[0] = * (point *) fastlookup(cavpoints, i);
15954  searchtet = recenttet;
15955  ivf.iloc = (int) OUTSIDE;
15956  insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
15957  }
15958 
15959  if (b->verbose > 2) {
15960  printf(" Identifying %ld boundary faces of the cavity.\n",
15961  cavfaces->objects);
15962  }
15963 
15964  while (1) {
15965 
15966  // Identify boundary faces. Mark interior tets. Save missing faces.
15967  for (i = 0; i < cavfaces->objects; i++) {
15968  parytet = (triface *) fastlookup(cavfaces, i);
15969  // Skip an interior face (due to the enlargement of the cavity).
15970  if (infected(*parytet)) continue;
15971  parytet->ver = epivot[parytet->ver];
15972  pt[0] = org(*parytet);
15973  pt[1] = dest(*parytet);
15974  pt[2] = apex(*parytet);
15975  // Create a temp subface.
15976  makeshellface(subfaces, &tmpsh);
15977  setshvertices(tmpsh, pt[0], pt[1], pt[2]);
15978  // Insert tmpsh in DT.
15979  searchtet.tet = NULL;
15980  dir = scoutsubface(&tmpsh, &searchtet);
15981  if (dir == SHAREFACE) {
15982  // Inserted! 'tmpsh' must face toward the inside of the cavity.
15983  // Remember the boundary tet (outside the cavity) in tmpsh
15984  // (use the adjacent tet slot).
15985  tmpsh.sh[0] = (shellface) encode(*parytet);
15986  // Save this subface.
15987  cavshells->newindex((void **) &parysh);
15988  *parysh = tmpsh;
15989  }
15990  else {
15991  // This boundary face is missing.
15992  shellfacedealloc(subfaces, tmpsh.sh);
15993  // Save this face in list.
15994  misfaces->newindex((void **) &parytet1);
15995  *parytet1 = *parytet;
15996  }
15997  } // i
15998 
15999  if (misfaces->objects > 0) {
16000  if (b->verbose > 2) {
16001  printf(" Enlarging the cavity. %ld missing bdry faces\n",
16002  misfaces->objects);
16003  }
16004 
16005  // Removing all temporary subfaces.
16006  for (i = 0; i < cavshells->objects; i++) {
16007  parysh = (face *) fastlookup(cavshells, i);
16008  stpivot(*parysh, neightet);
16009  tsdissolve(neightet); // Detach it from adj. tets.
16010  fsymself(neightet);
16011  tsdissolve(neightet);
16012  shellfacedealloc(subfaces, parysh->sh);
16013  }
16014  cavshells->restart();
16015 
16016  // Infect the points which are of the cavity.
16017  for (i = 0; i < cavpoints->objects; i++) {
16018  pt[0] = * (point *) fastlookup(cavpoints, i);
16019  pinfect(pt[0]); // Mark it as inserted.
16020  }
16021 
16022  // Enlarge the cavity.
16023  for (i = 0; i < misfaces->objects; i++) {
16024  // Get a missing face.
16025  parytet = (triface *) fastlookup(misfaces, i);
16026  if (!infected(*parytet)) {
16027  // Put it into crossing tet list.
16028  infect(*parytet);
16029  crosstets->newindex((void **) &parytet1);
16030  *parytet1 = *parytet;
16031  // Insert the opposite point if it is not in DT.
16032  pd = oppo(*parytet);
16033  if (!pinfected(pd)) {
16034  searchtet = recenttet;
16035  ivf.iloc = (int) OUTSIDE;
16036  insertpoint(pd, &searchtet, NULL, NULL, &ivf);
16037  pinfect(pd);
16038  cavpoints->newindex((void **) &parypt);
16039  *parypt = pd;
16040  }
16041  // Add three opposite faces into the boundary list.
16042  for (j = 0; j < 3; j++) {
16043  esym(*parytet, neightet);
16044  fsymself(neightet);
16045  if (!infected(neightet)) {
16046  cavfaces->newindex((void **) &parytet1);
16047  *parytet1 = neightet;
16048  }
16049  enextself(*parytet);
16050  } // j
16051  } // if (!infected(parytet))
16052  } // i
16053 
16054  // Uninfect the points which are of the cavity.
16055  for (i = 0; i < cavpoints->objects; i++) {
16056  pt[0] = * (point *) fastlookup(cavpoints, i);
16057  puninfect(pt[0]);
16058  }
16059 
16060  misfaces->restart();
16061  continue;
16062  } // if (misfaces->objects > 0)
16063 
16064  break;
16065 
16066  } // while (1)
16067 
16068  // Collect all tets of the DT. All new tets are marktested.
16070  newtets->newindex((void **) &parytet);
16071  *parytet = recenttet;
16072  for (i = 0; i < newtets->objects; i++) {
16073  searchtet = * (triface *) fastlookup(newtets, i);
16074  for (j = 0; j < 4; j++) {
16075  decode(searchtet.tet[j], neightet);
16076  if (!marktested(neightet)) {
16077  marktest(neightet);
16078  newtets->newindex((void **) &parytet);
16079  *parytet = neightet;
16080  }
16081  }
16082  }
16083 
16084  cavpoints->restart();
16085  cavfaces->restart();
16086 
16087  if (crosstets->objects > baknum) {
16088  // The cavity has been enlarged.
16089  cavityexpcount++;
16090  }
16091 
16092  // Restore the original values.
16093  hullsize = bakhullsize;
16094  checksubsegflag = bakchecksubsegflag;
16095  checksubfaceflag = bakchecksubfaceflag;
16096  b->verbose++;
16097  b->plc = 1;
16098 }
16099 
16101 // //
16102 // fillcavity() Fill new tets into the cavity. //
16103 // //
16104 // The new tets are stored in two disjoint sets(which share the same facet). //
16105 // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect- //
16106 // ively. 'midfaces' is empty on input, and will store faces in the facet. //
16107 // //
16108 // Important: This routine assumes all vertices of the missing region R are //
16109 // marktested, i.e., pmarktested(p) returns true. //
16110 // //
16112 
16113 bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
16114  arraypool* midfaces, arraypool* missingshs,
16115  arraypool* topnewtets, arraypool* botnewtets,
16116  triface* crossedge)
16117 {
16118  arraypool *cavshells;
16119  triface bdrytet, neightet, *parytet;
16120  triface searchtet, spintet;
16121  face *parysh;
16122  face checkseg;
16123  point pa, pb, pc;
16124  bool mflag;
16125  int t1ver;
16126  int i, j;
16127 
16128  // Connect newtets to tets outside the cavity. These connections are needed
16129  // for identifying the middle faces (which belong to R).
16130  for (j = 0; j < 2; j++) {
16131  cavshells = (j == 0 ? topshells : botshells);
16132  if (cavshells != NULL) {
16133  for (i = 0; i < cavshells->objects; i++) {
16134  // Get a temp subface.
16135  parysh = (face *) fastlookup(cavshells, i);
16136  // Get the boundary tet outside the cavity (saved in sh[0]).
16137  decode(parysh->sh[0], bdrytet);
16138  pa = org(bdrytet);
16139  pb = dest(bdrytet);
16140  pc = apex(bdrytet);
16141  // Get the adjacent new tet inside the cavity.
16142  stpivot(*parysh, neightet);
16143  // Mark neightet as an interior tet of this cavity.
16144  infect(neightet);
16145  // Connect the two tets (the old connections are replaced).
16146  bond(bdrytet, neightet);
16147  tsdissolve(neightet); // Clear the pointer to tmpsh.
16148  // Update the point-to-tets map.
16149  setpoint2tet(pa, (tetrahedron) neightet.tet);
16150  setpoint2tet(pb, (tetrahedron) neightet.tet);
16151  setpoint2tet(pc, (tetrahedron) neightet.tet);
16152  } // i
16153  } // if (cavshells != NULL)
16154  } // j
16155 
16156  if (crossedge != NULL) {
16157  // Glue top and bottom tets at their common facet.
16158  triface toptet, bottet, spintet, *midface;
16159  point pd, pe;
16160  REAL ori;
16161  int types[2], poss[4];
16162  int interflag;
16163  int bflag;
16164 
16165  mflag = false;
16166  pd = org(*crossedge);
16167  pe = dest(*crossedge);
16168 
16169  // Search the first (middle) face in R.
16170  // Since R may be non-convex, we must make sure that the face is in the
16171  // interior of R. We search a face in 'topnewtets' whose three vertices
16172  // are on R and it intersects 'crossedge' in its interior. Then search
16173  // a matching face in 'botnewtets'.
16174  for (i = 0; i < topnewtets->objects && !mflag; i++) {
16175  searchtet = * (triface *) fastlookup(topnewtets, i);
16176  for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
16177  pa = org(searchtet);
16178  if (pmarktested(pa)) {
16179  pb = dest(searchtet);
16180  if (pmarktested(pb)) {
16181  pc = apex(searchtet);
16182  if (pmarktested(pc)) {
16183  // Check if this face intersects [d,e].
16184  interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
16185  if (interflag == 2) {
16186  // They intersect at a single point. Found.
16187  toptet = searchtet;
16188  // The face lies in the interior of R.
16189  // Get the tet (in topnewtets) which lies above R.
16190  ori = orient3d(pa, pb, pc, pd);
16191  assert(ori != 0);
16192  if (ori < 0) {
16193  fsymself(toptet);
16194  pa = org(toptet);
16195  pb = dest(toptet);
16196  }
16197  // Search the face [b,a,c] in 'botnewtets'.
16198  for (j = 0; j < botnewtets->objects; j++) {
16199  neightet = * (triface *) fastlookup(botnewtets, j);
16200  // Is neightet contains 'b'.
16201  if ((point) neightet.tet[4] == pb) {
16202  neightet.ver = 11;
16203  } else if ((point) neightet.tet[5] == pb) {
16204  neightet.ver = 3;
16205  } else if ((point) neightet.tet[6] == pb) {
16206  neightet.ver = 7;
16207  } else if ((point) neightet.tet[7] == pb) {
16208  neightet.ver = 0;
16209  } else {
16210  continue;
16211  }
16212  // Is the 'neightet' contains edge [b,a].
16213  if (dest(neightet) == pa) {
16214  // 'neightet' is just the edge.
16215  } else if (apex(neightet) == pa) {
16216  eprevesymself(neightet);
16217  } else if (oppo(neightet) == pa) {
16218  esymself(neightet);
16219  enextself(neightet);
16220  } else {
16221  continue;
16222  }
16223  // Is 'neightet' the face [b,a,c].
16224  if (apex(neightet) == pc) {
16225  bottet = neightet;
16226  mflag = true;
16227  break;
16228  }
16229  } // j
16230  } // if (interflag == 2)
16231  } // pc
16232  } // pb
16233  } // pa
16234  } // toptet.ver
16235  } // i
16236 
16237  if (mflag) {
16238  // Found a pair of matched faces in 'toptet' and 'bottet'.
16239  bond(toptet, bottet);
16240  // Both are interior tets.
16241  infect(toptet);
16242  infect(bottet);
16243  // Add this face into search list.
16244  markface(toptet);
16245  midfaces->newindex((void **) &parytet);
16246  *parytet = toptet;
16247  } else {
16248  // No pair of 'toptet' and 'bottet'.
16249  toptet.tet = NULL;
16250  // Randomly split an interior edge of R.
16251  i = randomnation(missingshs->objects - 1);
16252  recentsh = * (face *) fastlookup(missingshs, i);
16253  }
16254 
16255  // Find other middle faces, connect top and bottom tets.
16256  for (i = 0; i < midfaces->objects && mflag; i++) {
16257  // Get a matched middle face [a, b, c]
16258  midface = (triface *) fastlookup(midfaces, i);
16259  // The tet must be a new created tet (marktested).
16260  assert(marktested(*midface)); // SELF_CHECK
16261  // Check the neighbors at the edges of this face.
16262  for (j = 0; j < 3 && mflag; j++) {
16263  toptet = *midface;
16264  bflag = false;
16265  while (1) {
16266  // Go to the next face in the same tet.
16267  esymself(toptet);
16268  pc = apex(toptet);
16269  if (pmarktested(pc)) {
16270  break; // Find a subface.
16271  }
16272  if (pc == dummypoint) {
16273  assert(0); // Check this case.
16274  break; // Find a subface.
16275  }
16276  // Go to the adjacent tet.
16277  fsymself(toptet);
16278  // Do we walk outside the cavity?
16279  if (!marktested(toptet)) {
16280  // Yes, the adjacent face is not a middle face.
16281  bflag = true; break;
16282  }
16283  }
16284  if (!bflag) {
16285  // assert(marktested(toptet)); // SELF_CHECK
16286  if (!facemarked(toptet)) {
16287  fsym(*midface, bottet);
16288  spintet = bottet;
16289  while (1) {
16290  esymself(bottet);
16291  pd = apex(bottet);
16292  if (pd == pc) break; // Face matched.
16293  fsymself(bottet);
16294  if (bottet.tet == spintet.tet) {
16295  // Not found a matched bottom face.
16296  mflag = false;
16297  break;
16298  }
16299  } // while (1)
16300  if (mflag) {
16301  if (marktested(bottet)) {
16302  // Connect two tets together.
16303  bond(toptet, bottet);
16304  // Both are interior tets.
16305  infect(toptet);
16306  infect(bottet);
16307  // Add this face into list.
16308  markface(toptet);
16309  midfaces->newindex((void **) &parytet);
16310  *parytet = toptet;
16311  }
16312  } else { // mflag == false
16313  // Adjust 'toptet' and 'bottet' to be the crossing edges.
16314  fsym(*midface, bottet);
16315  spintet = bottet;
16316  while (1) {
16317  esymself(bottet);
16318  pd = apex(bottet);
16319  if (pmarktested(pd)) {
16320  // assert(pd != pc);
16321  // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
16322  // Adjust 'toptet' and 'bottet' to be the crossing edges.
16323  // Test orient3d(b,c,#,d).
16324  ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
16325  if (ori < 0) {
16326  // Edges [a,d] and [b,c] cross each other.
16327  enextself(toptet); // [b,c]
16328  enextself(bottet); // [a,d]
16329  } else if (ori > 0) {
16330  // Edges [a,c] and [b,d] cross each other.
16331  eprevself(toptet); // [c,a]
16332  eprevself(bottet); // [d,b]
16333  } else {
16334  // b,c,#,and d are coplanar!.
16335  assert(0);
16336  }
16337  break; // Not matched
16338  }
16339  fsymself(bottet);
16340  assert (bottet.tet != spintet.tet);
16341  }
16342  } // if (!mflag)
16343  } // if (!facemarked(toptet))
16344  } // if (!bflag)
16345  enextself(*midface);
16346  } // j
16347  } // i
16348 
16349  if (mflag) {
16350  if (b->verbose > 2) {
16351  printf(" Found %ld middle subfaces.\n", midfaces->objects);
16352  }
16353  face oldsh, newsh, casout, casin, neighsh;
16354 
16355  oldsh = * (face *) fastlookup(missingshs, 0);
16356 
16357  // Create new subfaces to fill the region R.
16358  for (i = 0; i < midfaces->objects; i++) {
16359  // Get a matched middle face [a, b, c]
16360  midface = (triface *) fastlookup(midfaces, i);
16361  unmarkface(*midface);
16362  makeshellface(subfaces, &newsh);
16363  setsorg(newsh, org(*midface));
16364  setsdest(newsh, dest(*midface));
16365  setsapex(newsh, apex(*midface));
16366  // The new subface gets its markers from the old one.
16367  setshellmark(newsh, shellmark(oldsh));
16368  if (checkconstraints) {
16369  setareabound(newsh, areabound(oldsh));
16370  }
16371  // Connect the new subface to adjacent tets.
16372  tsbond(*midface, newsh);
16373  fsym(*midface, neightet);
16374  sesymself(newsh);
16375  tsbond(neightet, newsh);
16376  }
16377 
16378  // Connect new subfaces together and to the bdry of R.
16379  // Delete faked segments.
16380  for (i = 0; i < midfaces->objects; i++) {
16381  // Get a matched middle face [a, b, c]
16382  midface = (triface *) fastlookup(midfaces, i);
16383  for (j = 0; j < 3; j++) {
16384  tspivot(*midface, newsh);
16385  spivot(newsh, casout);
16386  if (casout.sh == NULL) {
16387  // Search its neighbor.
16388  fnext(*midface, searchtet);
16389  while (1) {
16390  // (1) First check if this side is a bdry edge of R.
16391  tsspivot1(searchtet, checkseg);
16392  if (checkseg.sh != NULL) {
16393  // It's a bdry edge of R.
16394  assert(!infected(searchtet)); // It must not be a cavity tet.
16395  // Get the old subface.
16396  checkseg.shver = 0;
16397  spivot(checkseg, oldsh);
16398  if (sinfected(checkseg)) {
16399  // It's a faked segment. Delete it.
16400  spintet = searchtet;
16401  while (1) {
16402  tssdissolve1(spintet);
16403  fnextself(spintet);
16404  if (spintet.tet == searchtet.tet) break;
16405  }
16406  shellfacedealloc(subsegs, checkseg.sh);
16407  ssdissolve(oldsh);
16408  checkseg.sh = NULL;
16409  }
16410  spivot(oldsh, casout);
16411  if (casout.sh != NULL) {
16412  casin = casout;
16413  if (checkseg.sh != NULL) {
16414  // Make sure that the subface has the right ori at the
16415  // segment.
16416  checkseg.shver = 0;
16417  if (sorg(newsh) != sorg(checkseg)) {
16418  sesymself(newsh);
16419  }
16420  spivot(casin, neighsh);
16421  while (neighsh.sh != oldsh.sh) {
16422  casin = neighsh;
16423  spivot(casin, neighsh);
16424  }
16425  }
16426  sbond1(newsh, casout);
16427  sbond1(casin, newsh);
16428  }
16429  if (checkseg.sh != NULL) {
16430  ssbond(newsh, checkseg);
16431  }
16432  break;
16433  } // if (checkseg.sh != NULL)
16434  // (2) Second check if this side is an interior edge of R.
16435  tspivot(searchtet, neighsh);
16436  if (neighsh.sh != NULL) {
16437  // Found an adjacent subface of newsh (an interior edge).
16438  sbond(newsh, neighsh);
16439  break;
16440  }
16441  fnextself(searchtet);
16442  assert(searchtet.tet != midface->tet);
16443  } // while (1)
16444  } // if (casout.sh == NULL)
16445  enextself(*midface);
16446  } // j
16447  } // i
16448 
16449  // Delete old subfaces.
16450  for (i = 0; i < missingshs->objects; i++) {
16451  parysh = (face *) fastlookup(missingshs, i);
16452  shellfacedealloc(subfaces, parysh->sh);
16453  }
16454  } else {
16455  if (toptet.tet != NULL) {
16456  // Faces at top and bottom are not matched.
16457  // Choose a Steiner point in R.
16458  // Split one of the crossing edges.
16459  pa = org(toptet);
16460  pb = dest(toptet);
16461  pc = org(bottet);
16462  pd = dest(bottet);
16463  // Search an edge in R which is either [a,b] or [c,d].
16464  // Reminder: Subfaces in this list 'missingshs', except the first
16465  // one, represents an interior edge of R.
16466  for (i = 1; i < missingshs->objects; i++) {
16467  parysh = (face *) fastlookup(missingshs, i);
16468  if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
16469  ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
16470  if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
16471  ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
16472  }
16473  if (i < missingshs->objects) {
16474  // Found. Return it.
16475  recentsh = *parysh;
16476  } else {
16477  assert(0);
16478  }
16479  }
16480  }
16481 
16482  midfaces->restart();
16483  } else {
16484  mflag = true;
16485  }
16486 
16487  // Delete the temp subfaces.
16488  for (j = 0; j < 2; j++) {
16489  cavshells = (j == 0 ? topshells : botshells);
16490  if (cavshells != NULL) {
16491  for (i = 0; i < cavshells->objects; i++) {
16492  parysh = (face *) fastlookup(cavshells, i);
16493  shellfacedealloc(subfaces, parysh->sh);
16494  }
16495  }
16496  }
16497 
16498  topshells->restart();
16499  if (botshells != NULL) {
16500  botshells->restart();
16501  }
16502 
16503  return mflag;
16504 }
16505 
16507 // //
16508 // carvecavity() Delete old tets and outer new tets of the cavity. //
16509 // //
16511 
16512 void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
16513  arraypool *botnewtets)
16514 {
16515  arraypool *newtets;
16516  shellface *sptr, *ssptr;
16517  triface *parytet, *pnewtet, newtet, neightet, spintet;
16518  face checksh, *parysh;
16519  face checkseg, *paryseg;
16520  int t1ver;
16521  int i, j;
16522 
16523  if (b->verbose > 2) {
16524  printf(" Carve cavity: %ld old tets.\n", crosstets->objects);
16525  }
16526 
16527  // First process subfaces and segments which are adjacent to the cavity.
16528  // They must be re-connected to new tets in the cavity.
16529  // Comment: It is possible that some subfaces and segments are completely
16530  // inside the cavity. This can happen even if the cavity is not enlarged.
16531  // Before deleting the old tets, find and queue all interior subfaces
16532  // and segments. They will be recovered later. 2010-05-06.
16533 
16534  // Collect all subfaces and segments which attached to the old tets.
16535  for (i = 0; i < crosstets->objects; i++) {
16536  parytet = (triface *) fastlookup(crosstets, i);
16537  if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
16538  for (j = 0; j < 4; j++) {
16539  if (sptr[j]) {
16540  sdecode(sptr[j], checksh);
16541  if (!sinfected(checksh)) {
16542  sinfect(checksh);
16543  cavetetshlist->newindex((void **) &parysh);
16544  *parysh = checksh;
16545  }
16546  }
16547  } // j
16548  }
16549  if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
16550  for (j = 0; j < 6; j++) {
16551  if (ssptr[j]) {
16552  sdecode(ssptr[j], checkseg);
16553  // Skip a deleted segment (was a faked segment)
16554  if (checkseg.sh[3] != NULL) {
16555  if (!sinfected(checkseg)) {
16556  sinfect(checkseg);
16557  cavetetseglist->newindex((void **) &paryseg);
16558  *paryseg = checkseg;
16559  }
16560  }
16561  }
16562  } // j
16563  }
16564  } // i
16565 
16566  // Uninfect collected subfaces.
16567  for (i = 0; i < cavetetshlist->objects; i++) {
16568  parysh = (face *) fastlookup(cavetetshlist, i);
16569  suninfect(*parysh);
16570  }
16571  // Uninfect collected segments.
16572  for (i = 0; i < cavetetseglist->objects; i++) {
16573  paryseg = (face *) fastlookup(cavetetseglist, i);
16574  suninfect(*paryseg);
16575  }
16576 
16577  // Connect subfaces to new tets.
16578  for (i = 0; i < cavetetshlist->objects; i++) {
16579  parysh = (face *) fastlookup(cavetetshlist, i);
16580  // Get an adjacent tet at this subface.
16581  stpivot(*parysh, neightet);
16582  // Does this tet lie inside the cavity.
16583  if (infected(neightet)) {
16584  // Yes. Get the other adjacent tet at this subface.
16585  sesymself(*parysh);
16586  stpivot(*parysh, neightet);
16587  // Does this tet lie inside the cavity.
16588  if (infected(neightet)) {
16589  checksh = *parysh;
16590  stdissolve(checksh);
16591  caveencshlist->newindex((void **) &parysh);
16592  *parysh = checksh;
16593  }
16594  }
16595  if (!infected(neightet)) {
16596  // Found an outside tet. Re-connect this subface to a new tet.
16597  fsym(neightet, newtet);
16598  assert(marktested(newtet)); // It's a new tet.
16599  sesymself(*parysh);
16600  tsbond(newtet, *parysh);
16601  }
16602  } // i
16603 
16604 
16605  for (i = 0; i < cavetetseglist->objects; i++) {
16606  checkseg = * (face *) fastlookup(cavetetseglist, i);
16607  // Check if the segment is inside the cavity.
16608  sstpivot1(checkseg, neightet);
16609  spintet = neightet;
16610  while (1) {
16611  if (!infected(spintet)) {
16612  // This segment is on the boundary of the cavity.
16613  break;
16614  }
16615  fnextself(spintet);
16616  if (spintet.tet == neightet.tet) {
16617  sstdissolve1(checkseg);
16618  caveencseglist->newindex((void **) &paryseg);
16619  *paryseg = checkseg;
16620  break;
16621  }
16622  }
16623  if (!infected(spintet)) {
16624  // A boundary segment. Connect this segment to the new tets.
16625  sstbond1(checkseg, spintet);
16626  neightet = spintet;
16627  while (1) {
16628  tssbond1(spintet, checkseg);
16629  fnextself(spintet);
16630  if (spintet.tet == neightet.tet) break;
16631  }
16632  }
16633  } // i
16634 
16635 
16638 
16639  // Delete the old tets in cavity.
16640  for (i = 0; i < crosstets->objects; i++) {
16641  parytet = (triface *) fastlookup(crosstets, i);
16642  if (ishulltet(*parytet)) {
16643  hullsize--;
16644  }
16645  tetrahedrondealloc(parytet->tet);
16646  }
16647 
16648  crosstets->restart(); // crosstets will be re-used.
16649 
16650  // Collect new tets in cavity. Some new tets have already been found
16651  // (and infected) in the fillcavity(). We first collect them.
16652  for (j = 0; j < 2; j++) {
16653  newtets = (j == 0 ? topnewtets : botnewtets);
16654  if (newtets != NULL) {
16655  for (i = 0; i < newtets->objects; i++) {
16656  parytet = (triface *) fastlookup(newtets, i);
16657  if (infected(*parytet)) {
16658  crosstets->newindex((void **) &pnewtet);
16659  *pnewtet = *parytet;
16660  }
16661  } // i
16662  }
16663  } // j
16664 
16665  // Now we collect all new tets in cavity.
16666  for (i = 0; i < crosstets->objects; i++) {
16667  parytet = (triface *) fastlookup(crosstets, i);
16668  for (j = 0; j < 4; j++) {
16669  decode(parytet->tet[j], neightet);
16670  if (marktested(neightet)) { // Is it a new tet?
16671  if (!infected(neightet)) {
16672  // Find an interior tet.
16673  //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
16674  infect(neightet);
16675  crosstets->newindex((void **) &pnewtet);
16676  *pnewtet = neightet;
16677  }
16678  }
16679  } // j
16680  } // i
16681 
16682  parytet = (triface *) fastlookup(crosstets, 0);
16683  recenttet = *parytet; // Remember a live handle.
16684 
16685  // Delete outer new tets.
16686  for (j = 0; j < 2; j++) {
16687  newtets = (j == 0 ? topnewtets : botnewtets);
16688  if (newtets != NULL) {
16689  for (i = 0; i < newtets->objects; i++) {
16690  parytet = (triface *) fastlookup(newtets, i);
16691  if (infected(*parytet)) {
16692  // This is an interior tet.
16693  uninfect(*parytet);
16694  unmarktest(*parytet);
16695  if (ishulltet(*parytet)) {
16696  hullsize++;
16697  }
16698  } else {
16699  // An outer tet. Delete it.
16700  tetrahedrondealloc(parytet->tet);
16701  }
16702  }
16703  }
16704  }
16705 
16706  crosstets->restart();
16707  topnewtets->restart();
16708  if (botnewtets != NULL) {
16709  botnewtets->restart();
16710  }
16711 }
16712 
16714 // //
16715 // restorecavity() Reconnect old tets and delete new tets of the cavity. //
16716 // //
16718 
16719 void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
16720  arraypool *botnewtets, arraypool *missingshbds)
16721 {
16722  triface *parytet, neightet, spintet;
16723  face *parysh;
16724  face checkseg;
16725  point *ppt;
16726  int t1ver;
16727  int i, j;
16728 
16729  // Reconnect crossing tets to cavity boundary.
16730  for (i = 0; i < crosstets->objects; i++) {
16731  parytet = (triface *) fastlookup(crosstets, i);
16732  assert(infected(*parytet)); // SELF_CHECK
16733  parytet->ver = 0;
16734  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
16735  fsym(*parytet, neightet);
16736  if (!infected(neightet)) {
16737  // Restore the old connections of tets.
16738  bond(*parytet, neightet);
16739  }
16740  }
16741  // Update the point-to-tet map.
16742  parytet->ver = 0;
16743  ppt = (point *) &(parytet->tet[4]);
16744  for (j = 0; j < 4; j++) {
16745  setpoint2tet(ppt[j], encode(*parytet));
16746  }
16747  }
16748 
16749  // Uninfect all crossing tets.
16750  for (i = 0; i < crosstets->objects; i++) {
16751  parytet = (triface *) fastlookup(crosstets, i);
16752  uninfect(*parytet);
16753  }
16754 
16755  // Remember a live handle.
16756  recenttet = * (triface *) fastlookup(crosstets, 0);
16757 
16758  // Delete faked segments.
16759  for (i = 0; i < missingshbds->objects; i++) {
16760  parysh = (face *) fastlookup(missingshbds, i);
16761  sspivot(*parysh, checkseg);
16762  assert(checkseg.sh != NULL);
16763  if (checkseg.sh[3] != NULL) {
16764  if (sinfected(checkseg)) {
16765  // It's a faked segment. Delete it.
16766  sstpivot1(checkseg, neightet);
16767  spintet = neightet;
16768  while (1) {
16769  tssdissolve1(spintet);
16770  fnextself(spintet);
16771  if (spintet.tet == neightet.tet) break;
16772  }
16773  shellfacedealloc(subsegs, checkseg.sh);
16774  ssdissolve(*parysh);
16775  //checkseg.sh = NULL;
16776  }
16777  }
16778  } // i
16779 
16780  // Delete new tets.
16781  for (i = 0; i < topnewtets->objects; i++) {
16782  parytet = (triface *) fastlookup(topnewtets, i);
16783  tetrahedrondealloc(parytet->tet);
16784  }
16785 
16786  if (botnewtets != NULL) {
16787  for (i = 0; i < botnewtets->objects; i++) {
16788  parytet = (triface *) fastlookup(botnewtets, i);
16789  tetrahedrondealloc(parytet->tet);
16790  }
16791  }
16792 
16793  crosstets->restart();
16794  topnewtets->restart();
16795  if (botnewtets != NULL) {
16796  botnewtets->restart();
16797  }
16798 }
16799 
16801 // //
16802 // flipcertify() Insert a crossing face into priority queue. //
16803 // //
16804 // A crossing face of a facet must have at least one top and one bottom ver- //
16805 // tex of the facet. //
16806 // //
16808 
16809 void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
16810  point plane_pb, point plane_pc)
16811 {
16812  badface *parybf, *prevbf, *nextbf;
16813  triface neightet;
16814  face checksh;
16815  point p[5];
16816  REAL w[5];
16817  REAL insph, ori4;
16818  int topi, boti;
16819  int i;
16820 
16821  // Compute the flip time \tau.
16822  fsym(*chkface, neightet);
16823 
16824  p[0] = org(*chkface);
16825  p[1] = dest(*chkface);
16826  p[2] = apex(*chkface);
16827  p[3] = oppo(*chkface);
16828  p[4] = oppo(neightet);
16829 
16830  // Check if the face is a crossing face.
16831  topi = boti = 0;
16832  for (i = 0; i < 3; i++) {
16833  if (pmarktest2ed(p[i])) topi++;
16834  if (pmarktest3ed(p[i])) boti++;
16835  }
16836  if ((topi == 0) || (boti == 0)) {
16837  // It is not a crossing face.
16838  // return;
16839  for (i = 3; i < 5; i++) {
16840  if (pmarktest2ed(p[i])) topi++;
16841  if (pmarktest3ed(p[i])) boti++;
16842  }
16843  if ((topi == 0) || (boti == 0)) {
16844  // The two tets sharing at this face are on one side of the facet.
16845  // Check if this face is locally Delaunay (due to rounding error).
16846  if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
16847  // Do not check it if it is a subface.
16848  tspivot(*chkface, checksh);
16849  if (checksh.sh == NULL) {
16850  insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
16851  assert(insph != 0);
16852  if (insph > 0) {
16853  // Add the face into queue.
16854  if (b->verbose > 2) {
16855  printf(" A locally non-Delanay face (%d, %d, %d)-%d,%d\n",
16856  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
16857  pointmark(p[3]), pointmark(p[4]));
16858  }
16859  parybf = (badface *) flippool->alloc();
16860  parybf->key = 0.; // tau = 0, do immediately.
16861  parybf->tt = *chkface;
16862  parybf->forg = p[0];
16863  parybf->fdest = p[1];
16864  parybf->fapex = p[2];
16865  parybf->foppo = p[3];
16866  parybf->noppo = p[4];
16867  // Add it at the top of the priority queue.
16868  if (*pqueue == NULL) {
16869  *pqueue = parybf;
16870  parybf->nextitem = NULL;
16871  } else {
16872  parybf->nextitem = *pqueue;
16873  *pqueue = parybf;
16874  }
16875  } // if (insph > 0)
16876  } // if (checksh.sh == NULL)
16877  }
16878  //return;
16879  }
16880  return; // Test: omit this face.
16881  }
16882 
16883  // Decide the "height" for each point.
16884  for (i = 0; i < 5; i++) {
16885  if (pmarktest2ed(p[i])) {
16886  // A top point has a positive weight.
16887  w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);
16888  if (w[i] < 0) w[i] = -w[i];
16889  assert(w[i] != 0);
16890  } else {
16891  w[i] = 0;
16892  }
16893  }
16894 
16895  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
16896  // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
16897  // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
16898  // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
16899  // p[4] lies below the oriented hyperplane passing through
16900  // p[1], p[0], p[2], p[3].
16901 
16902  insph = insphere(p[1], p[0], p[2], p[3], p[4]);
16903  ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
16904 
16905  if (b->verbose > 2) {
16906  printf(" Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]);
16907  printf(" Insph: %g, ori4: %g, tau = %g\n", insph, ori4, -insph/ori4);
16908  }
16909 
16910  if (ori4 > 0) {
16911  // Add the face into queue.
16912  if (b->verbose > 2) {
16913  printf(" Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
16914  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
16915  }
16916 
16917  parybf = (badface *) flippool->alloc();
16918 
16919  parybf->key = -insph / ori4;
16920  parybf->tt = *chkface;
16921  parybf->forg = p[0];
16922  parybf->fdest = p[1];
16923  parybf->fapex = p[2];
16924  parybf->foppo = p[3];
16925  parybf->noppo = p[4];
16926 
16927  // Push the face into priority queue.
16928  //pq.push(bface);
16929  if (*pqueue == NULL) {
16930  *pqueue = parybf;
16931  parybf->nextitem = NULL;
16932  } else {
16933  // Search an item whose key is larger or equal to current key.
16934  prevbf = NULL;
16935  nextbf = *pqueue;
16936  //if (!b->flipinsert_random) { // Default use a priority queue.
16937  // Insert the item into priority queue.
16938  while (nextbf != NULL) {
16939  if (nextbf->key < parybf->key) {
16940  prevbf = nextbf;
16941  nextbf = nextbf->nextitem;
16942  } else {
16943  break;
16944  }
16945  }
16946  //} // if (!b->flipinsert_random)
16947  // Insert the new item between prev and next items.
16948  if (prevbf == NULL) {
16949  *pqueue = parybf;
16950  } else {
16951  prevbf->nextitem = parybf;
16952  }
16953  parybf->nextitem = nextbf;
16954  }
16955  } else if (ori4 == 0) {
16956 
16957  }
16958 }
16959 
16961 // //
16962 // flipinsertfacet() Insert a facet into a CDT by flips. //
16963 // //
16964 // The algorithm is described in Shewchuk's paper "Updating and Constructing //
16965 // Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
16966 // Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003. //
16967 // //
16968 // 'crosstets' contains the set of crossing tetrahedra (infected) of the //
16969 // facet. 'toppoints' and 'botpoints' are points lies above and below the //
16970 // facet, not on the facet. //
16971 // //
16973 
16975  arraypool *botpoints, arraypool *midpoints)
16976 {
16977  arraypool *crossfaces, *bfacearray;
16978  triface fliptets[6], baktets[2], fliptet, newface;
16979  triface neightet, *parytet;
16980  face checksh;
16981  face checkseg;
16982  badface *pqueue;
16983  badface *popbf, bface;
16984  point plane_pa, plane_pb, plane_pc;
16985  point p1, p2, pd, pe;
16986  point *parypt;
16987  flipconstraints fc;
16988  REAL ori[3];
16989  int convcount, copcount;
16990  int flipflag, fcount;
16991  int n, i;
16992  long f23count, f32count, f44count;
16993  long totalfcount;
16994 
16995  f23count = flip23count;
16996  f32count = flip32count;
16997  f44count = flip44count;
16998 
16999  // Get three affinely independent vertices in the missing region R.
17000  calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
17001 
17002  // Mark top and bottom points. Do not mark midpoints.
17003  for (i = 0; i < toppoints->objects; i++) {
17004  parypt = (point *) fastlookup(toppoints, i);
17005  if (!pmarktested(*parypt)) {
17006  pmarktest2(*parypt);
17007  }
17008  }
17009  for (i = 0; i < botpoints->objects; i++) {
17010  parypt = (point *) fastlookup(botpoints, i);
17011  if (!pmarktested(*parypt)) {
17012  pmarktest3(*parypt);
17013  }
17014  }
17015 
17016  // Collect crossing faces.
17017  crossfaces = cavetetlist; // Re-use array 'cavetetlist'.
17018 
17019  // Each crossing face contains at least one bottom vertex and
17020  // one top vertex.
17021  for (i = 0; i < crosstets->objects; i++) {
17022  parytet = (triface *) fastlookup(crosstets, i);
17023  fliptet = *parytet;
17024  for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
17025  fsym(fliptet, neightet);
17026  if (infected(neightet)) { // It is an interior face.
17027  if (!marktested(neightet)) { // It is an unprocessed face.
17028  crossfaces->newindex((void **) &parytet);
17029  *parytet = fliptet;
17030  }
17031  }
17032  }
17033  marktest(fliptet);
17034  }
17035 
17036  if (b->verbose > 1) {
17037  printf(" Found %ld crossing faces.\n", crossfaces->objects);
17038  }
17039 
17040  for (i = 0; i < crosstets->objects; i++) {
17041  parytet = (triface *) fastlookup(crosstets, i);
17042  unmarktest(*parytet);
17043  uninfect(*parytet);
17044  }
17045 
17046  // Initialize the priority queue.
17047  pqueue = NULL;
17048 
17049  for (i = 0; i < crossfaces->objects; i++) {
17050  parytet = (triface *) fastlookup(crossfaces, i);
17051  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17052  }
17053  crossfaces->restart();
17054 
17055  // The list for temporarily storing unflipable faces.
17056  bfacearray = new arraypool(sizeof(triface), 4);
17057 
17058 
17059  fcount = 0; // Count the number of flips.
17060 
17061  // Flip insert the facet.
17062  while (pqueue != NULL) {
17063 
17064  // Pop a face from the priority queue.
17065  popbf = pqueue;
17066  bface = *popbf;
17067 
17068  // Update the queue.
17069  pqueue = pqueue->nextitem;
17070 
17071  // Delete the popped item from the pool.
17072  flippool->dealloc((void *) popbf);
17073 
17074  if (!isdeadtet(bface.tt)) {
17075  if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
17076  (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
17077  // It is still a crossing face of R.
17078  fliptet = bface.tt;
17079  fsym(fliptet, neightet);
17080  assert(!isdeadtet(neightet));
17081  if (oppo(neightet) == bface.noppo) {
17082  pd = oppo(fliptet);
17083  pe = oppo(neightet);
17084 
17085  if (b->verbose > 2) {
17086  printf(" Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17087  pointmark(bface.forg), pointmark(bface.fdest),
17088  pointmark(bface.fapex), pointmark(bface.foppo),
17089  pointmark(bface.noppo), bface.key);
17090  }
17091  flipflag = 0;
17092 
17093  // Check for which type of flip can we do.
17094  convcount = 3;
17095  copcount = 0;
17096  for (i = 0; i < 3; i++) {
17097  p1 = org(fliptet);
17098  p2 = dest(fliptet);
17099  ori[i] = orient3d(p1, p2, pd, pe);
17100  if (ori[i] < 0) {
17101  convcount--;
17102  //break;
17103  } else if (ori[i] == 0) {
17104  convcount--; // Possible 4-to-4 flip.
17105  copcount++;
17106  //break;
17107  }
17108  enextself(fliptet);
17109  }
17110 
17111  if (convcount == 3) {
17112  // A 2-to-3 flip is found.
17113  // The face should not be a subface.
17114  tspivot(fliptet, checksh);
17115  assert(checksh.sh == NULL);
17116 
17117  fliptets[0] = fliptet; // abcd, d may be the new vertex.
17118  fliptets[1] = neightet; // bace.
17119  flip23(fliptets, 1, &fc);
17120  // Put the link faces into check list.
17121  for (i = 0; i < 3; i++) {
17122  eprevesym(fliptets[i], newface);
17123  crossfaces->newindex((void **) &parytet);
17124  *parytet = newface;
17125  }
17126  for (i = 0; i < 3; i++) {
17127  enextesym(fliptets[i], newface);
17128  crossfaces->newindex((void **) &parytet);
17129  *parytet = newface;
17130  }
17131  flipflag = 1;
17132  } else if (convcount == 2) {
17133  assert(copcount <= 1);
17134  //if (copcount <= 1) {
17135  // A 3-to-2 or 4-to-4 may be possible.
17136  // Get the edge which is locally non-convex or flat.
17137  for (i = 0; i < 3; i++) {
17138  if (ori[i] <= 0) break;
17139  enextself(fliptet);
17140  }
17141  // The edge should not be a segment.
17142  tsspivot1(fliptet, checkseg);
17143  assert(checkseg.sh == NULL);
17144 
17145  // Collect tets sharing at this edge.
17146  // NOTE: This operation may collect tets which lie outside the
17147  // cavity, e.g., when the edge lies on the boundary of the
17148  // cavity. Do not flip if there are outside tets at this edge.
17149  // 2012-07-27.
17150  esym(fliptet, fliptets[0]); // [b,a,d,c]
17151  n = 0;
17152  do {
17153  p1 = apex(fliptets[n]);
17154  if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
17155  // This apex is not on the cavity. Hence the face does not
17156  // lie inside the cavity. Do not flip this edge.
17157  n = 1000; break;
17158  }
17159  fnext(fliptets[n], fliptets[n + 1]);
17160  n++;
17161  } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
17162 
17163  if (n == 3) {
17164  // Found a 3-to-2 flip.
17165  flip32(fliptets, 1, &fc);
17166  // Put the link faces into check list.
17167  for (i = 0; i < 3; i++) {
17168  esym(fliptets[0], newface);
17169  crossfaces->newindex((void **) &parytet);
17170  *parytet = newface;
17171  enextself(fliptets[0]);
17172  }
17173  for (i = 0; i < 3; i++) {
17174  esym(fliptets[1], newface);
17175  crossfaces->newindex((void **) &parytet);
17176  *parytet = newface;
17177  enextself(fliptets[1]);
17178  }
17179  flipflag = 1;
17180  } else if (n == 4) {
17181  if (copcount == 1) {
17182  // Found a 4-to-4 flip.
17183  // Let the six vertices are: a,b,c,d,e,f, where
17184  // fliptets[0] = [b,a,d,c]
17185  // [1] = [b,a,c,e]
17186  // [2] = [b,a,e,f]
17187  // [3] = [b,a,f,d]
17188  // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
17189  // is created.
17190  // First do a 2-to-3 flip.
17191  // Comment: This flip temporarily creates a degenerated
17192  // tet (whose volume is zero). It will be removed by the
17193  // followed 3-to-2 flip.
17194  fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
17195  // fliptets[1]; // = [b,a,c,e].
17196  baktets[0] = fliptets[2]; // = [b,a,e,f]
17197  baktets[1] = fliptets[3]; // = [b,a,f,d]
17198  // The flip may involve hull tets.
17199  flip23(fliptets, 1, &fc);
17200  // Put the "outer" link faces into check list.
17201  // fliptets[0] = [e,d,a,b] => will be flipped, so
17202  // [a,b,d] and [a,b,e] are not "outer" link faces.
17203  for (i = 1; i < 3; i++) {
17204  eprevesym(fliptets[i], newface);
17205  crossfaces->newindex((void **) &parytet);
17206  *parytet = newface;
17207  }
17208  for (i = 1; i < 3; i++) {
17209  enextesym(fliptets[i], newface);
17210  crossfaces->newindex((void **) &parytet);
17211  *parytet = newface;
17212  }
17213  // Then do a 3-to-2 flip.
17214  enextesymself(fliptets[0]); // fliptets[0] is [e,d,a,b].
17215  eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
17216  fliptets[1] = baktets[0]; // = [b,a,e,f]
17217  fliptets[2] = baktets[1]; // = [b,a,f,d]
17218  flip32(fliptets, 1, &fc);
17219  // Put the "outer" link faces into check list.
17220  // fliptets[0] = [d,e,f,a]
17221  // fliptets[1] = [e,d,f,b]
17222  // Faces [a,b,d] and [a,b,e] are not "outer" link faces.
17223  enextself(fliptets[0]);
17224  for (i = 1; i < 3; i++) {
17225  esym(fliptets[0], newface);
17226  crossfaces->newindex((void **) &parytet);
17227  *parytet = newface;
17228  enextself(fliptets[0]);
17229  }
17230  enextself(fliptets[1]);
17231  for (i = 1; i < 3; i++) {
17232  esym(fliptets[1], newface);
17233  crossfaces->newindex((void **) &parytet);
17234  *parytet = newface;
17235  enextself(fliptets[1]);
17236  }
17237  flip23count--;
17238  flip32count--;
17239  flip44count++;
17240  flipflag = 1;
17241  } else {
17242  //n == 4, convflag != 0; assert(0);
17243  }
17244  } else {
17245  // n > 4 => unflipable. //assert(0);
17246  }
17247  } else {
17248  // There are more than 1 non-convex or coplanar cases.
17249  flipflag = -1; // Ignore this face.
17250  if (b->verbose > 2) {
17251  printf(" Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17252  pointmark(bface.forg), pointmark(bface.fdest),
17253  pointmark(bface.fapex), pointmark(bface.foppo),
17254  pointmark(bface.noppo), bface.key);
17255  }
17256  } // if (convcount == 1)
17257 
17258  if (flipflag == 1) {
17259  // Update the priority queue.
17260  for (i = 0; i < crossfaces->objects; i++) {
17261  parytet = (triface *) fastlookup(crossfaces, i);
17262  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17263  }
17264  crossfaces->restart();
17265  if (1) { // if (!b->flipinsert_random) {
17266  // Insert all queued unflipped faces.
17267  for (i = 0; i < bfacearray->objects; i++) {
17268  parytet = (triface *) fastlookup(bfacearray, i);
17269  // This face may be changed.
17270  if (!isdeadtet(*parytet)) {
17271  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17272  }
17273  }
17274  bfacearray->restart();
17275  }
17276  fcount++;
17277  } else if (flipflag == 0) {
17278  // Queue an unflippable face. To process it later.
17279  bfacearray->newindex((void **) &parytet);
17280  *parytet = fliptet;
17281  }
17282  } // if (pe == bface.noppo)
17283  } // if ((pa == bface.forg) && ...)
17284  } // if (bface.tt != NULL)
17285 
17286  } // while (pqueue != NULL)
17287 
17288  if (bfacearray->objects > 0) {
17289  if (fcount == 0) {
17290  printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
17291  assert(0);
17292  }
17293  }
17294 
17295  // 'bfacearray' may be not empty (for what reason ??).
17296  //dbg_unflip_facecount += bfacearray->objects;
17297 
17298  assert(flippool->items == 0l);
17299  delete bfacearray;
17300 
17301  // Un-mark top and bottom points.
17302  for (i = 0; i < toppoints->objects; i++) {
17303  parypt = (point *) fastlookup(toppoints, i);
17304  punmarktest2(*parypt);
17305  }
17306  for (i = 0; i < botpoints->objects; i++) {
17307  parypt = (point *) fastlookup(botpoints, i);
17308  punmarktest3(*parypt);
17309  }
17310 
17311  f23count = flip23count - f23count;
17312  f32count = flip32count - f32count;
17313  f44count = flip44count - f44count;
17314  totalfcount = f23count + f32count + f44count;
17315  if (b->verbose > 2) {
17316  printf(" Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
17317  totalfcount, f23count, f32count, f44count);
17318  }
17319 }
17320 
17322 // //
17323 // fillregion() Fill the missing region by a set of new subfaces. //
17324 // //
17325 // 'missingshs' contains the list of subfaces in R. Moreover, each subface //
17326 // (except the first one) in this list represents an interior edge of R. //
17327 // //
17328 // Note: We assume that all vertices of R are marktested so we can detect //
17329 // new subface by checking the flag in apexes. //
17330 // //
17332 
17333 bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
17334  arraypool* newshs)
17335 {
17336  badface *newflipface, *popface;
17337  triface searchtet, spintet, neightet;
17338  face oldsh, newsh, opensh, *parysh;
17339  face casout, casin, neighsh, checksh;
17340  face neighseg, checkseg;
17341  point pc;
17342  int success;
17343  int t1ver;
17344  int i, j;
17345 
17346 
17347  // Search the first new subface to fill the region.
17348  for (i = 0; i < missingshbds->objects; i++) {
17349  parysh = (face *) fastlookup(missingshbds, i);
17350  sspivot(*parysh, neighseg);
17351  sstpivot1(neighseg, searchtet);
17352  j = 0; // Count the number of passes of R.
17353  spintet = searchtet;
17354  while (1) {
17355  pc = apex(spintet);
17356  if (pmarktested(pc)) {
17357  neightet = spintet;
17358  j++;
17359  }
17360  fnextself(spintet);
17361  if (spintet.tet == searchtet.tet) break;
17362  }
17363  assert(j >= 1);
17364  if (j == 1) {
17365  // Found an interior new subface.
17366  searchtet = neightet;
17367  oldsh = *parysh;
17368  break;
17369  }
17370  } // i
17371 
17372  if (i == missingshbds->objects) {
17373  // Failed to find any interior subface.
17374  // Need Steiner points.
17375  return false;
17376  }
17377 
17378  makeshellface(subfaces, &newsh);
17379  setsorg(newsh, org(searchtet));
17380  setsdest(newsh, dest(searchtet));
17381  setsapex(newsh, apex(searchtet));
17382  // The new subface gets its markers from the old one.
17383  setshellmark(newsh, shellmark(oldsh));
17384  if (checkconstraints) {
17385  setareabound(newsh, areabound(oldsh));
17386  }
17387  // Connect the new subface to adjacent tets.
17388  tsbond(searchtet, newsh);
17389  fsymself(searchtet);
17390  sesymself(newsh);
17391  tsbond(searchtet, newsh);
17392  // Connect newsh to outer subfaces.
17393  sspivot(oldsh, checkseg);
17394  if (sinfected(checkseg)) {
17395  // It's a faked segment. Delete it.
17396  spintet = searchtet;
17397  while (1) {
17398  tssdissolve1(spintet);
17399  fnextself(spintet);
17400  if (spintet.tet == searchtet.tet) break;
17401  }
17402  shellfacedealloc(subsegs, checkseg.sh);
17403  ssdissolve(oldsh);
17404  checkseg.sh = NULL;
17405  }
17406  spivot(oldsh, casout);
17407  if (casout.sh != NULL) {
17408  casin = casout;
17409  if (checkseg.sh != NULL) {
17410  // Make sure that the subface has the right ori at the segment.
17411  checkseg.shver = 0;
17412  if (sorg(newsh) != sorg(checkseg)) {
17413  sesymself(newsh);
17414  }
17415  spivot(casin, neighsh);
17416  while (neighsh.sh != oldsh.sh) {
17417  casin = neighsh;
17418  spivot(casin, neighsh);
17419  }
17420  }
17421  sbond1(newsh, casout);
17422  sbond1(casin, newsh);
17423  }
17424  if (checkseg.sh != NULL) {
17425  ssbond(newsh, checkseg);
17426  }
17427  // Add this new subface into list.
17428  sinfect(newsh);
17429  newshs->newindex((void **) &parysh);
17430  *parysh = newsh;
17431 
17432  // Push two "open" side of the new subface into stack.
17433  for (i = 0; i < 2; i++) {
17434  senextself(newsh);
17435  newflipface = (badface *) flippool->alloc();
17436  newflipface->ss = newsh;
17437  newflipface->nextitem = flipstack;
17438  flipstack = newflipface;
17439  }
17440 
17441  success = 1;
17442 
17443  // Loop until 'flipstack' is empty.
17444  while ((flipstack != NULL) && success) {
17445  // Pop an "open" side from the stack.
17446  popface = flipstack;
17447  opensh = popface->ss;
17448  flipstack = popface->nextitem; // The next top item in stack.
17449  flippool->dealloc((void *) popface);
17450 
17451  // opensh is either (1) an interior edge or (2) a bdry edge.
17452  stpivot(opensh, searchtet);
17453  tsspivot1(searchtet, checkseg);
17454  if (checkseg.sh == NULL) {
17455  // No segment. It is an interior edge of R.
17456  // Search for a new face in R.
17457  spintet = searchtet;
17458  fnextself(spintet); // Skip the current face.
17459  while (1) {
17460  pc = apex(spintet);
17461  if (pmarktested(pc)) {
17462  // 'opensh' is an interior edge.
17463  if (!issubface(spintet)) {
17464  // Create a new subface.
17465  makeshellface(subfaces, &newsh);
17466  setsorg(newsh, org(spintet));
17467  setsdest(newsh, dest(spintet));
17468  setsapex(newsh, pc);
17469  // The new subface gets its markers from its neighbor.
17470  setshellmark(newsh, shellmark(opensh));
17471  if (checkconstraints) {
17472  setareabound(newsh, areabound(opensh));
17473  }
17474  // Connect the new subface to adjacent tets.
17475  tsbond(spintet, newsh);
17476  fsymself(spintet);
17477  sesymself(newsh);
17478  tsbond(spintet, newsh);
17479  // Connect newsh to its adjacent subface.
17480  sbond(newsh, opensh);
17481  // Add this new subface into list.
17482  sinfect(newsh);
17483  newshs->newindex((void **) &parysh);
17484  *parysh = newsh;
17485  // Push two "open" side of the new subface into stack.
17486  for (i = 0; i < 2; i++) {
17487  senextself(newsh);
17488  newflipface = (badface *) flippool->alloc();
17489  newflipface->ss = newsh;
17490  newflipface->nextitem = flipstack;
17491  flipstack = newflipface;
17492  }
17493  } else {
17494  // Connect to another open edge.
17495  tspivot(spintet, checksh);
17496  sbond(opensh, checksh);
17497  }
17498  break;
17499  } // if (pmarktested(pc))
17500  fnextself(spintet);
17501  if (spintet.tet == searchtet.tet) {
17502  // Not find any face to fill in R at this side.
17503  // Suggest a point to split the edge.
17504  success = 0;
17505  break;
17506  }
17507  } // while (1)
17508  } else {
17509  // This side coincident with a boundary edge of R.
17510  checkseg.shver = 0;
17511  spivot(checkseg, oldsh);
17512  if (sinfected(checkseg)) {
17513  // It's a faked segment. Delete it.
17514  spintet = searchtet;
17515  while (1) {
17516  tssdissolve1(spintet);
17517  fnextself(spintet);
17518  if (spintet.tet == searchtet.tet) break;
17519  }
17520  shellfacedealloc(subsegs, checkseg.sh);
17521  ssdissolve(oldsh);
17522  checkseg.sh = NULL;
17523  }
17524  spivot(oldsh, casout);
17525  if (casout.sh != NULL) {
17526  casin = casout;
17527  if (checkseg.sh != NULL) {
17528  // Make sure that the subface has the right ori at the segment.
17529  checkseg.shver = 0;
17530  if (sorg(opensh) != sorg(checkseg)) {
17531  sesymself(opensh);
17532  }
17533  spivot(casin, neighsh);
17534  while (neighsh.sh != oldsh.sh) {
17535  casin = neighsh;
17536  spivot(casin, neighsh);
17537  }
17538  }
17539  sbond1(opensh, casout);
17540  sbond1(casin, opensh);
17541  }
17542  if (checkseg.sh != NULL) {
17543  ssbond(opensh, checkseg);
17544  }
17545  } // if (checkseg.sh != NULL)
17546  } // while ((flipstack != NULL) && success)
17547 
17548  if (success) {
17549  // Uninfect all new subfaces.
17550  for (i = 0; i < newshs->objects; i++) {
17551  parysh = (face *) fastlookup(newshs, i);
17552  suninfect(*parysh);
17553  }
17554  // Delete old subfaces.
17555  for (i = 0; i < missingshs->objects; i++) {
17556  parysh = (face *) fastlookup(missingshs, i);
17557  shellfacedealloc(subfaces, parysh->sh);
17558  }
17559  fillregioncount++;
17560  } else {
17561  // Failed to fill the region.
17562  // Re-connect old subfaces at boundaries of R.
17563  // Also delete fake segments.
17564  for (i = 0; i < missingshbds->objects; i++) {
17565  parysh = (face *) fastlookup(missingshbds, i);
17566  // It still connect to 'casout'.
17567  // Re-connect 'casin' to it.
17568  spivot(*parysh, casout);
17569  casin = casout;
17570  spivot(casin, neighsh);
17571  while (1) {
17572  if (sinfected(neighsh)) break;
17573  if (neighsh.sh == parysh->sh) break;
17574  casin = neighsh;
17575  spivot(casin, neighsh);
17576  }
17577  if (sinfected(neighsh)) {
17578  sbond1(casin, *parysh);
17579  }
17580  sspivot(*parysh, checkseg);
17581  if (checkseg.sh != NULL) {
17582  if (checkseg.sh[3] != NULL) {
17583  if (sinfected(checkseg)) {
17584  sstpivot1(checkseg, searchtet);
17585  spintet = searchtet;
17586  while (1) {
17587  tssdissolve1(spintet);
17588  fnextself(spintet);
17589  if (spintet.tet == searchtet.tet) break;
17590  }
17591  ssdissolve(*parysh);
17592  shellfacedealloc(subsegs, checkseg.sh);
17593  }
17594  }
17595  }
17596  }
17597  // Delete all new subfaces.
17598  for (i = 0; i < newshs->objects; i++) {
17599  parysh = (face *) fastlookup(newshs, i);
17600  shellfacedealloc(subfaces, parysh->sh);
17601  }
17602  // Clear the flip pool.
17603  flippool->restart();
17604  flipstack = NULL;
17605 
17606  // Choose an interior edge of R to split.
17607  assert(missingshs->objects > 1);
17608  // Skip the first subface in 'missingshs'.
17609  i = randomnation(missingshs->objects - 1) + 1;
17610  parysh = (face *) fastlookup(missingshs, i);
17611  recentsh = *parysh;
17612  }
17613 
17614  newshs->restart();
17615 
17616  return success;
17617 }
17618 
17620 // //
17621 // insertpoint_cdt() Insert a new point into a CDT. //
17622 // //
17624 
17625 int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh,
17626  face *splitseg, insertvertexflags *ivf,
17627  arraypool *cavpoints, arraypool *cavfaces,
17628  arraypool *cavshells, arraypool *newtets,
17629  arraypool *crosstets, arraypool *misfaces)
17630 {
17631  triface neightet, *parytet;
17632  face checksh, *parysh, *parysh1;
17633  face *paryseg, *paryseg1;
17634  point *parypt;
17635  int t1ver;
17636  int i;
17637 
17638  if (b->verbose > 2) {
17639  printf(" Insert point %d into CDT\n", pointmark(newpt));
17640  }
17641 
17642  if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
17643  // Point is not inserted. Check ivf->iloc for reason.
17644  return 0;
17645  }
17646 
17647 
17648  for (i = 0; i < cavetetvertlist->objects; i++) {
17649  cavpoints->newindex((void **) &parypt);
17650  *parypt = * (point *) fastlookup(cavetetvertlist, i);
17651  }
17652  // Add the new point into the point list.
17653  cavpoints->newindex((void **) &parypt);
17654  *parypt = newpt;
17655 
17656  for (i = 0; i < cavebdrylist->objects; i++) {
17657  cavfaces->newindex((void **) &parytet);
17658  *parytet = * (triface *) fastlookup(cavebdrylist, i);
17659  }
17660 
17661  for (i = 0; i < caveoldtetlist->objects; i++) {
17662  crosstets->newindex((void **) &parytet);
17663  *parytet = * (triface *) fastlookup(caveoldtetlist, i);
17664  }
17665 
17667  cavebdrylist->restart();
17669 
17670  // Insert the point using the cavity algorithm.
17671  delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets,
17672  misfaces);
17673  fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
17674  carvecavity(crosstets, newtets, NULL);
17675 
17676  if ((splitsh != NULL) || (splitseg != NULL)) {
17677  // Insert the point into the surface mesh.
17678  sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
17679 
17680  // Put all new subfaces into stack.
17681  for (i = 0; i < caveshbdlist->objects; i++) {
17682  // Get an old subface at edge [a, b].
17683  parysh = (face *) fastlookup(caveshbdlist, i);
17684  spivot(*parysh, checksh); // The new subface [a, b, p].
17685  // Do not recover a deleted new face (degenerated).
17686  if (checksh.sh[3] != NULL) {
17687  subfacstack->newindex((void **) &parysh);
17688  *parysh = checksh;
17689  }
17690  }
17691 
17692  if (splitseg != NULL) {
17693  // Queue two new subsegments in C(p) for recovery.
17694  for (i = 0; i < cavesegshlist->objects; i++) {
17695  paryseg = (face *) fastlookup(cavesegshlist, i);
17696  subsegstack->newindex((void **) &paryseg1);
17697  *paryseg1 = *paryseg;
17698  }
17699  } // if (splitseg != NULL)
17700 
17701  // Delete the old subfaces in sC(p).
17702  for (i = 0; i < caveshlist->objects; i++) {
17703  parysh = (face *) fastlookup(caveshlist, i);
17704  if (checksubfaceflag) {
17705  // It is possible that this subface still connects to adjacent
17706  // tets which are not in C(p). If so, clear connections in the
17707  // adjacent tets at this subface.
17708  stpivot(*parysh, neightet);
17709  if (neightet.tet != NULL) {
17710  if (neightet.tet[4] != NULL) {
17711  // Found an adjacent tet. It must be not in C(p).
17712  assert(!infected(neightet));
17713  tsdissolve(neightet);
17714  fsymself(neightet);
17715  assert(!infected(neightet));
17716  tsdissolve(neightet);
17717  }
17718  }
17719  }
17720  shellfacedealloc(subfaces, parysh->sh);
17721  }
17722  if (splitseg != NULL) {
17723  // Delete the old segment in sC(p).
17724  shellfacedealloc(subsegs, splitseg->sh);
17725  }
17726 
17727  // Clear working lists.
17728  caveshlist->restart();
17729  caveshbdlist->restart();
17731  } // if ((splitsh != NULL) || (splitseg != NULL))
17732 
17733  // Put all interior subfaces into stack for recovery.
17734  // They were collected in carvecavity().
17735  // Note: Some collected subfaces may be deleted by sinsertvertex().
17736  for (i = 0; i < caveencshlist->objects; i++) {
17737  parysh = (face *) fastlookup(caveencshlist, i);
17738  if (parysh->sh[3] != NULL) {
17739  subfacstack->newindex((void **) &parysh1);
17740  *parysh1 = *parysh;
17741  }
17742  }
17743 
17744  // Put all interior segments into stack for recovery.
17745  // They were collected in carvecavity().
17746  // Note: Some collected segments may be deleted by sinsertvertex().
17747  for (i = 0; i < caveencseglist->objects; i++) {
17748  paryseg = (face *) fastlookup(caveencseglist, i);
17749  if (paryseg->sh[3] != NULL) {
17750  subsegstack->newindex((void **) &paryseg1);
17751  *paryseg1 = *paryseg;
17752  }
17753  }
17754 
17757 
17758  return 1;
17759 }
17760 
17762 // //
17763 // refineregion() Refine a missing region by inserting points. //
17764 // //
17765 // 'splitsh' represents an edge of the facet to be split. It must be not a //
17766 // segment.
17767 // //
17768 // Assumption: The current mesh is a CDT and is convex. //
17769 // //
17771 
17772 void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints,
17773  arraypool *cavfaces, arraypool *cavshells,
17774  arraypool *newtets, arraypool *crosstets,
17775  arraypool *misfaces)
17776 {
17777  triface searchtet, spintet;
17778  face splitseg, *paryseg;
17779  point steinpt, pa, pb, refpt;
17780  insertvertexflags ivf;
17781  enum interresult dir;
17782  long baknum = points->items;
17783  int t1ver;
17784  int i;
17785 
17786  if (b->verbose > 2) {
17787  printf(" Refining region at edge (%d, %d, %d).\n",
17788  pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
17789  pointmark(sapex(splitsh)));
17790  }
17791 
17792  // Add the Steiner point at the barycenter of the face.
17793  pa = sorg(splitsh);
17794  pb = sdest(splitsh);
17795  // Create a new point.
17796  makepoint(&steinpt, FREEFACETVERTEX);
17797  for (i = 0; i < 3; i++) {
17798  steinpt[i] = 0.5 * (pa[i] + pb[i]);
17799  }
17800 
17801  ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
17802  ivf.cdtflag = 1; // Only create the initial cavity.
17803  ivf.sloc = (int) ONEDGE;
17804  ivf.sbowywat = 1;
17805  ivf.assignmeshsize = b->metric;
17806 
17807  point2tetorg(pa, searchtet); // Start location from it.
17808  ivf.iloc = (int) OUTSIDE;
17809 
17810  ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
17811  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
17812  cavfaces, cavshells, newtets, crosstets, misfaces)) {
17813  if (ivf.iloc == (int) ENCSEGMENT) {
17814  pointdealloc(steinpt);
17815  // Split an encroached segment.
17816  assert(encseglist->objects > 0);
17818  paryseg = (face *) fastlookup(encseglist, i);
17819  splitseg = *paryseg;
17820  encseglist->restart();
17821 
17822  // Split the segment.
17823  pa = sorg(splitseg);
17824  pb = sdest(splitseg);
17825  // Create a new point.
17826  makepoint(&steinpt, FREESEGVERTEX);
17827  for (i = 0; i < 3; i++) {
17828  steinpt[i] = 0.5 * (pa[i] + pb[i]);
17829  }
17830  point2tetorg(pa, searchtet);
17831  ivf.iloc = (int) OUTSIDE;
17832  ivf.rejflag = 0;
17833  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
17834  cavpoints, cavfaces, cavshells, newtets,
17835  crosstets, misfaces)) {
17836  assert(0);
17837  }
17838  st_segref_count++;
17839  if (steinerleft > 0) steinerleft--;
17840  } else {
17841  assert(0);
17842  }
17843  } else {
17844  st_facref_count++;
17845  if (steinerleft > 0) steinerleft--;
17846  }
17847 
17848  while (subsegstack->objects > 0l) {
17849  // seglist is used as a stack.
17850  subsegstack->objects--;
17851  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
17852  splitseg = *paryseg;
17853 
17854  // Check if this segment has been recovered.
17855  sstpivot1(splitseg, searchtet);
17856  if (searchtet.tet != NULL) continue;
17857 
17858  // Search the segment.
17859  dir = scoutsegment(sorg(splitseg), sdest(splitseg), &searchtet, &refpt,
17860  NULL);
17861  if (dir == SHAREEDGE) {
17862  // Found this segment, insert it.
17863  if (!issubseg(searchtet)) {
17864  // Let the segment remember an adjacent tet.
17865  sstbond1(splitseg, searchtet);
17866  // Bond the segment to all tets containing it.
17867  spintet = searchtet;
17868  do {
17869  tssbond1(spintet, splitseg);
17870  fnextself(spintet);
17871  } while (spintet.tet != searchtet.tet);
17872  } else {
17873  // Collision! Should not happen.
17874  assert(0);
17875  }
17876  } else {
17877  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
17878  // Split the segment.
17879  // Create a new point.
17880  makepoint(&steinpt, FREESEGVERTEX);
17881  //setpointtype(newpt, FREESEGVERTEX);
17882  getsteinerptonsegment(&splitseg, refpt, steinpt);
17883  ivf.iloc = (int) OUTSIDE;
17884  ivf.rejflag = 0;
17885  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
17886  cavpoints, cavfaces, cavshells, newtets,
17887  crosstets, misfaces)) {
17888  assert(0);
17889  }
17890  st_segref_count++;
17891  if (steinerleft > 0) steinerleft--;
17892  } else {
17893  // Maybe a PLC problem.
17894  assert(0);
17895  }
17896  }
17897  } // while
17898 
17899  if (b->verbose > 2) {
17900  printf(" Added %ld Steiner points.\n", points->items - baknum);
17901  }
17902 }
17903 
17905 // //
17906 // constrainedfacets() Recover constrained facets in a CDT. //
17907 // //
17908 // All unrecovered subfaces are queued in 'subfacestack'. //
17909 // //
17911 
17913 {
17914  arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
17915  arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
17916  arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
17917  arraypool *tg_toppoints, *tg_botpoints;
17918  arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
17919  triface searchtet, neightet, crossedge;
17920  face searchsh, *parysh, *parysh1;
17921  face *paryseg;
17922  point *parypt;
17923  enum interresult dir;
17924  int facetcount;
17925  int success;
17926  int t1ver;
17927  int i, j;
17928 
17929  // Initialize arrays.
17930  tg_crosstets = new arraypool(sizeof(triface), 10);
17931  tg_topnewtets = new arraypool(sizeof(triface), 10);
17932  tg_botnewtets = new arraypool(sizeof(triface), 10);
17933  tg_topfaces = new arraypool(sizeof(triface), 10);
17934  tg_botfaces = new arraypool(sizeof(triface), 10);
17935  tg_midfaces = new arraypool(sizeof(triface), 10);
17936  tg_toppoints = new arraypool(sizeof(point), 8);
17937  tg_botpoints = new arraypool(sizeof(point), 8);
17938  tg_facfaces = new arraypool(sizeof(face), 10);
17939  tg_topshells = new arraypool(sizeof(face), 10);
17940  tg_botshells = new arraypool(sizeof(face), 10);
17941  tg_missingshs = new arraypool(sizeof(face), 10);
17942  tg_missingshbds = new arraypool(sizeof(face), 10);
17943  tg_missingshverts = new arraypool(sizeof(point), 8);
17944  // This is a global array used by refineregion().
17945  encseglist = new arraypool(sizeof(face), 4);
17946 
17947  facetcount = 0;
17948 
17949  while (subfacstack->objects > 0l) {
17950 
17951  subfacstack->objects--;
17952  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
17953  searchsh = *parysh;
17954 
17955  if (searchsh.sh[3] == NULL) continue; // It is dead.
17956  if (isshtet(searchsh)) continue; // It is recovered.
17957 
17958  // Collect all unrecovered subfaces which are co-facet.
17959  smarktest(searchsh);
17960  tg_facfaces->newindex((void **) &parysh);
17961  *parysh = searchsh;
17962  for (i = 0; i < tg_facfaces->objects; i++) {
17963  parysh = (face *) fastlookup(tg_facfaces, i);
17964  for (j = 0; j < 3; j++) {
17965  if (!isshsubseg(*parysh)) {
17966  spivot(*parysh, searchsh);
17967  assert(searchsh.sh != NULL); // SELF_CHECK
17968  if (!smarktested(searchsh)) {
17969  if (!isshtet(searchsh)) {
17970  smarktest(searchsh);
17971  tg_facfaces->newindex((void **) &parysh1);
17972  *parysh1 = searchsh;
17973  }
17974  }
17975  }
17976  senextself(*parysh);
17977  } // j
17978  } // i
17979  // Have found all facet subfaces. Unmark them.
17980  for (i = 0; i < tg_facfaces->objects; i++) {
17981  parysh = (face *) fastlookup(tg_facfaces, i);
17982  sunmarktest(*parysh);
17983  }
17984 
17985  if (b->verbose > 2) {
17986  printf(" Recovering facet #%d: %ld subfaces.\n", facetcount + 1,
17987  tg_facfaces->objects);
17988  }
17989  facetcount++;
17990 
17991  while (tg_facfaces->objects > 0l) {
17992 
17993  tg_facfaces->objects--;
17994  parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
17995  searchsh = *parysh;
17996 
17997  if (searchsh.sh[3] == NULL) continue; // It is dead.
17998  if (isshtet(searchsh)) continue; // It is recovered.
17999 
18000  searchtet.tet = NULL;
18001  dir = scoutsubface(&searchsh, &searchtet);
18002  if (dir == SHAREFACE) continue; // The subface is inserted.
18003 
18004  // The subface is missing. Form the missing region.
18005  // Re-use 'tg_crosstets' for 'adjtets'.
18006  formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
18007 
18008  if (scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs)) {
18009  // Save this crossing edge, will be used by fillcavity().
18010  crossedge = searchtet;
18011  // Form a cavity of crossing tets.
18012  success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
18013  tg_topfaces, tg_botfaces, tg_toppoints,
18014  tg_botpoints);
18015  if (success) {
18016  if (!b->flipinsert) {
18017  // Tetrahedralize the top part. Re-use 'tg_midfaces'.
18018  delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
18019  tg_topnewtets, tg_crosstets, tg_midfaces);
18020  // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
18021  delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
18022  tg_botnewtets, tg_crosstets, tg_midfaces);
18023  // Fill the cavity with new tets.
18024  success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
18025  tg_missingshs, tg_topnewtets, tg_botnewtets,
18026  &crossedge);
18027  if (success) {
18028  // Cavity is remeshed. Delete old tets and outer new tets.
18029  carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
18030  } else {
18031  restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18032  tg_missingshbds);
18033  }
18034  } else {
18035  // Use the flip algorithm of Shewchuk to recover the subfaces.
18036  flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints,
18037  tg_missingshverts);
18038  // Recover the missing region.
18039  success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18040  assert(success);
18041  // Clear working lists.
18042  tg_crosstets->restart();
18043  tg_topfaces->restart();
18044  tg_botfaces->restart();
18045  tg_toppoints->restart();
18046  tg_botpoints->restart();
18047  } // b->flipinsert
18048 
18049  if (success) {
18050  // Recover interior subfaces.
18051  for (i = 0; i < caveencshlist->objects; i++) {
18052  parysh = (face *) fastlookup(caveencshlist, i);
18053  dir = scoutsubface(parysh, &searchtet);
18054  if (dir != SHAREFACE) {
18055  // Add this face at the end of the list, so it will be
18056  // processed immediately.
18057  tg_facfaces->newindex((void **) &parysh1);
18058  *parysh1 = *parysh;
18059  }
18060  }
18062  // Recover interior segments. This should always be recovered.
18063  for (i = 0; i < caveencseglist->objects; i++) {
18064  paryseg = (face *) fastlookup(caveencseglist, i);
18065  dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
18066  NULL, NULL);
18067  assert(dir == SHAREEDGE);
18068  // Insert this segment.
18069  if (!issubseg(searchtet)) {
18070  // Let the segment remember an adjacent tet.
18071  sstbond1(*paryseg, searchtet);
18072  // Bond the segment to all tets containing it.
18073  neightet = searchtet;
18074  do {
18075  tssbond1(neightet, *paryseg);
18076  fnextself(neightet);
18077  } while (neightet.tet != searchtet.tet);
18078  } else {
18079  // Collision! Should not happen.
18080  assert(0);
18081  }
18082  }
18084  } // success - remesh cavity
18085  } // success - form cavity
18086  } else {
18087  // Recover subfaces by retriangulate the surface mesh.
18088  // Re-use tg_topshells for newshs.
18089  success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18090  }
18091 
18092  // Unmarktest all points of the missing region.
18093  for (i = 0; i < tg_missingshverts->objects; i++) {
18094  parypt = (point *) fastlookup(tg_missingshverts, i);
18095  punmarktest(*parypt);
18096  }
18097  tg_missingshverts->restart();
18098  tg_missingshbds->restart();
18099  tg_missingshs->restart();
18100 
18101  if (!success) {
18102  // The missing region can not be recovered. Refine it.
18103  refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
18104  tg_topnewtets, tg_crosstets, tg_midfaces);
18105  // Clean the current list of facet subfaces.
18106  // tg_facfaces->restart();
18107  }
18108  } // while (tg_facfaces->objects)
18109 
18110  } // while ((subfacstack->objects)
18111 
18112  // Accumulate the dynamic memory.
18113  totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
18114  tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
18115  tg_botfaces->totalmemory + tg_midfaces->totalmemory +
18116  tg_toppoints->totalmemory + tg_botpoints->totalmemory +
18117  tg_facfaces->totalmemory + tg_topshells->totalmemory +
18118  tg_botshells->totalmemory + tg_missingshs->totalmemory +
18119  tg_missingshbds->totalmemory +
18120  tg_missingshverts->totalmemory +
18122 
18123  // Delete arrays.
18124  delete tg_crosstets;
18125  delete tg_topnewtets;
18126  delete tg_botnewtets;
18127  delete tg_topfaces;
18128  delete tg_botfaces;
18129  delete tg_midfaces;
18130  delete tg_toppoints;
18131  delete tg_botpoints;
18132  delete tg_facfaces;
18133  delete tg_topshells;
18134  delete tg_botshells;
18135  delete tg_missingshs;
18136  delete tg_missingshbds;
18137  delete tg_missingshverts;
18138  delete encseglist;
18139 }
18140 
18142 // //
18143 // constraineddelaunay() Create a constrained Delaunay tetrahedralization.//
18144 // //
18146 
18148 {
18149  face searchsh, *parysh;
18150  face searchseg, *paryseg;
18151  int s, i;
18152 
18153  // Statistics.
18154  long bakfillregioncount;
18155  long bakcavitycount, bakcavityexpcount;
18156  long bakseg_ref_count;
18157 
18158  if (!b->quiet) {
18159  printf("Constrained Delaunay...\n");
18160  }
18161 
18163 
18164  if (b->verbose) {
18165  printf(" Delaunizing segments.\n");
18166  }
18167 
18168  checksubsegflag = 1;
18169 
18170  // Put all segments into the list (in random order).
18172  for (i = 0; i < subsegs->items; i++) {
18173  s = randomnation(i + 1);
18174  // Move the s-th seg to the i-th.
18175  subsegstack->newindex((void **) &paryseg);
18176  *paryseg = * (face *) fastlookup(subsegstack, s);
18177  // Put i-th seg to be the s-th.
18178  searchseg.sh = shellfacetraverse(subsegs);
18179  //sinfect(searchseg); // Only save it once.
18180  paryseg = (face *) fastlookup(subsegstack, s);
18181  *paryseg = searchseg;
18182  }
18183 
18184  // Recover non-Delaunay segments.
18186 
18187  if (b->verbose) {
18188  printf(" Inserted %ld Steiner points.\n", st_segref_count);
18189  }
18190 
18191  tv = clock();
18192 
18193  if (b->verbose) {
18194  printf(" Constraining facets.\n");
18195  }
18196 
18197  // Subfaces will be introduced.
18198  checksubfaceflag = 1;
18199 
18200  bakfillregioncount = fillregioncount;
18201  bakcavitycount = cavitycount;
18202  bakcavityexpcount = cavityexpcount;
18203  bakseg_ref_count = st_segref_count;
18204 
18205  // Randomly order the subfaces.
18207  for (i = 0; i < subfaces->items; i++) {
18208  s = randomnation(i + 1);
18209  // Move the s-th subface to the i-th.
18210  subfacstack->newindex((void **) &parysh);
18211  *parysh = * (face *) fastlookup(subfacstack, s);
18212  // Put i-th subface to be the s-th.
18213  searchsh.sh = shellfacetraverse(subfaces);
18214  parysh = (face *) fastlookup(subfacstack, s);
18215  *parysh = searchsh;
18216  }
18217 
18218  // Recover facets.
18220 
18221  if (b->verbose) {
18222  if (fillregioncount > bakfillregioncount) {
18223  printf(" Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
18224  }
18225  if (cavitycount > bakcavitycount) {
18226  printf(" Remeshed %ld cavities", cavitycount - bakcavitycount);
18227  if (cavityexpcount - bakcavityexpcount) {
18228  printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
18229  }
18230  printf(".\n");
18231  }
18232  if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
18233  printf(" Inserted %ld (%ld, %ld) refine points.\n",
18234  st_segref_count + st_facref_count - bakseg_ref_count,
18235  st_segref_count - bakseg_ref_count, st_facref_count);
18236  }
18237  }
18238 }
18239 
18243 
18247 
18249 // //
18250 // checkflipeligibility() A call back function for boundary recovery. //
18251 // //
18252 // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
18253 // and 2 : 3-to-2, respectively. //
18254 // //
18255 // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is //
18256 // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
18257 // other points must not be 'dummypoint'. //
18258 // //
18260 
18262  point pc, point pd, point pe,
18263  int level, int edgepivot,
18264  flipconstraints* fc)
18265 {
18266  point tmppts[3];
18267  enum interresult dir;
18268  int types[2], poss[4];
18269  int intflag;
18270  int rejflag = 0;
18271  int i;
18272 
18273  if (fc->seg[0] != NULL) {
18274  // A constraining edge is given (e.g., for edge recovery).
18275  if (fliptype == 1) {
18276  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18277  tmppts[0] = pa;
18278  tmppts[1] = pb;
18279  tmppts[2] = pc;
18280  for (i = 0; i < 3 && !rejflag; i++) {
18281  if (tmppts[i] != dummypoint) {
18282  // Test if the face [e,d,#] intersects the edge.
18283  intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
18284  NULL, 1, types, poss);
18285  if (intflag == 2) {
18286  // They intersect at a single point.
18287  dir = (enum interresult) types[0];
18288  if (dir == ACROSSFACE) {
18289  // The interior of [e,d,#] intersect the segment.
18290  rejflag = 1;
18291  } else if (dir == ACROSSEDGE) {
18292  if (poss[0] == 0) {
18293  // The interior of [e,d] intersect the segment.
18294  // Since [e,d] is the newly created edge. Reject this flip.
18295  rejflag = 1;
18296  }
18297  }
18298  } else if (intflag == 4) {
18299  // They may intersect at either a point or a line segment.
18300  dir = (enum interresult) types[0];
18301  if (dir == ACROSSEDGE) {
18302  if (poss[0] == 0) {
18303  // The interior of [e,d] intersect the segment.
18304  // Since [e,d] is the newly created edge. Reject this flip.
18305  rejflag = 1;
18306  }
18307  }
18308  }
18309  } // if (tmppts[0] != dummypoint)
18310  } // i
18311  } else if (fliptype == 2) {
18312  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18313  if (pc != dummypoint) {
18314  // Check if the new face [a,b,c] intersect the edge in its interior.
18315  intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL,
18316  1, types, poss);
18317  if (intflag == 2) {
18318  // They intersect at a single point.
18319  dir = (enum interresult) types[0];
18320  if (dir == ACROSSFACE) {
18321  // The interior of [a,b,c] intersect the segment.
18322  rejflag = 1; // Do not flip.
18323  }
18324  } else if (intflag == 4) {
18325  // [a,b,c] is coplanar with the edge.
18326  dir = (enum interresult) types[0];
18327  if (dir == ACROSSEDGE) {
18328  // The boundary of [a,b,c] intersect the segment.
18329  rejflag = 1; // Do not flip.
18330  }
18331  }
18332  } // if (pc != dummypoint)
18333  }
18334  } // if (fc->seg[0] != NULL)
18335 
18336  if ((fc->fac[0] != NULL) && !rejflag) {
18337  // A constraining face is given (e.g., for face recovery).
18338  if (fliptype == 1) {
18339  // A 2-to-3 flip.
18340  // Test if the new edge [e,d] intersects the face.
18341  intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
18342  NULL, 1, types, poss);
18343  if (intflag == 2) {
18344  // They intersect at a single point.
18345  dir = (enum interresult) types[0];
18346  if (dir == ACROSSFACE) {
18347  rejflag = 1;
18348  } else if (dir == ACROSSEDGE) {
18349  rejflag = 1;
18350  }
18351  } else if (intflag == 4) {
18352  // The edge [e,d] is coplanar with the face.
18353  // There may be two intersections.
18354  for (i = 0; i < 2 && !rejflag; i++) {
18355  dir = (enum interresult) types[i];
18356  if (dir == ACROSSFACE) {
18357  rejflag = 1;
18358  } else if (dir == ACROSSEDGE) {
18359  rejflag = 1;
18360  }
18361  }
18362  }
18363  } // if (fliptype == 1)
18364  } // if (fc->fac[0] != NULL)
18365 
18366  if ((fc->remvert != NULL) && !rejflag) {
18367  // The vertex is going to be removed. Do not create a new edge which
18368  // contains this vertex.
18369  if (fliptype == 1) {
18370  // A 2-to-3 flip.
18371  if ((pd == fc->remvert) || (pe == fc->remvert)) {
18372  rejflag = 1;
18373  }
18374  }
18375  }
18376 
18377  if (fc->remove_large_angle && !rejflag) {
18378  // Remove a large dihedral angle. Do not create a new small angle.
18379  REAL cosmaxd = 0, diff;
18380  if (fliptype == 1) {
18381  // We assume that neither 'a' nor 'b' is dummypoint.
18382  assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK
18383  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18384  // The new tet [e,d,a,b] will be flipped later. Only two new tets:
18385  // [e,d,b,c] and [e,d,c,a] need to be checked.
18386  if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
18387  // Get the largest dihedral angle of [e,d,b,c].
18388  tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
18389  diff = cosmaxd - fc->cosdihed_in;
18390  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18391  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18392  rejflag = 1;
18393  } else {
18394  // Record the largest new angle.
18395  if (cosmaxd < fc->cosdihed_out) {
18396  fc->cosdihed_out = cosmaxd;
18397  }
18398  // Get the largest dihedral angle of [e,d,c,a].
18399  tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
18400  diff = cosmaxd - fc->cosdihed_in;
18401  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18402  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18403  rejflag = 1;
18404  } else {
18405  // Record the largest new angle.
18406  if (cosmaxd < fc->cosdihed_out) {
18407  fc->cosdihed_out = cosmaxd;
18408  }
18409  }
18410  }
18411  } // if (pc != dummypoint && ...)
18412  } else if (fliptype == 2) {
18413  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18414  // We assume that neither 'e' nor 'd' is dummypoint.
18415  assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK
18416  if (level == 0) {
18417  // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
18418  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18419  // Get the largest dihedral angle of [a,b,c,d].
18420  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18421  diff = cosmaxd - fc->cosdihed_in;
18422  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
18423  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18424  rejflag = 1;
18425  } else {
18426  // Record the largest new angle.
18427  if (cosmaxd < fc->cosdihed_out) {
18428  fc->cosdihed_out = cosmaxd;
18429  }
18430  // Get the largest dihedral angle of [b,a,c,e].
18431  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18432  diff = cosmaxd - fc->cosdihed_in;
18433  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18434  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18435  rejflag = 1;
18436  } else {
18437  // Record the largest new angle.
18438  if (cosmaxd < fc->cosdihed_out) {
18439  fc->cosdihed_out = cosmaxd;
18440  }
18441  }
18442  }
18443  }
18444  } else { // level > 0
18445  assert(edgepivot != 0);
18446  if (edgepivot == 1) {
18447  // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
18448  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18449  // Get the largest dihedral angle of [b,a,c,e].
18450  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18451  diff = cosmaxd - fc->cosdihed_in;
18452  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18453  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18454  rejflag = 1;
18455  } else {
18456  // Record the largest new angle.
18457  if (cosmaxd < fc->cosdihed_out) {
18458  fc->cosdihed_out = cosmaxd;
18459  }
18460  }
18461  }
18462  } else {
18463  assert(edgepivot == 2);
18464  // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
18465  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18466  // Get the largest dihedral angle of [b,a,c,e].
18467  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18468  diff = cosmaxd - fc->cosdihed_in;
18469  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18470  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18471  rejflag = 1;
18472  } else {
18473  // Record the largest new angle.
18474  if (cosmaxd < fc->cosdihed_out) {
18475  fc->cosdihed_out = cosmaxd;
18476  }
18477  }
18478  }
18479  } // edgepivot
18480  } // level
18481  }
18482  }
18483 
18484  return rejflag;
18485 }
18486 
18488 // //
18489 // removeedgebyflips() Remove an edge by flips. //
18490 // //
18491 // 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. //
18492 // //
18493 // The return value is a positive integer, it indicates whether the edge is //
18494 // removed or not. A value "2" means the edge is removed, otherwise, the //
18495 // edge is not removed and the value (must >= 3) is the current number of //
18496 // tets in the edge star. //
18497 // //
18499 
18501 {
18502  triface *abtets, spintet;
18503  int t1ver;
18504  int n, nn, i;
18505 
18506 
18507  if (checksubsegflag) {
18508  // Do not flip a segment.
18509  if (issubseg(*flipedge)) {
18510  if (fc->collectencsegflag) {
18511  face checkseg, *paryseg;
18512  tsspivot1(*flipedge, checkseg);
18513  if (!sinfected(checkseg)) {
18514  // Queue this segment in list.
18515  sinfect(checkseg);
18516  caveencseglist->newindex((void **) &paryseg);
18517  *paryseg = checkseg;
18518  }
18519  }
18520  return 0;
18521  }
18522  }
18523 
18524  // Count the number of tets at edge [a,b].
18525  n = 0;
18526  spintet = *flipedge;
18527  while (1) {
18528  n++;
18529  fnextself(spintet);
18530  if (spintet.tet == flipedge->tet) break;
18531  }
18532  assert(n >= 3);
18533 
18534  if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
18535  // The star size exceeds the limit.
18536  return 0; // Do not flip it.
18537  }
18538 
18539  // Allocate spaces.
18540  abtets = new triface[n];
18541  // Collect the tets at edge [a,b].
18542  spintet = *flipedge;
18543  i = 0;
18544  while (1) {
18545  abtets[i] = spintet;
18546  setelemcounter(abtets[i], 1);
18547  i++;
18548  fnextself(spintet);
18549  if (spintet.tet == flipedge->tet) break;
18550  }
18551 
18552 
18553  // Try to flip the edge (level = 0, edgepivot = 0).
18554  nn = flipnm(abtets, n, 0, 0, fc);
18555 
18556 
18557  if (nn > 2) {
18558  // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
18559  for (i = 0; i < nn; i++) {
18560  setelemcounter(abtets[i], 0);
18561  }
18562  // Restore the input edge (needed by Lawson's flip).
18563  *flipedge = abtets[0];
18564  }
18565 
18566  // Release the temporary allocated spaces.
18567  // NOTE: fc->unflip must be 0.
18568  int bakunflip = fc->unflip;
18569  fc->unflip = 0;
18570  flipnm_post(abtets, n, nn, 0, fc);
18571  fc->unflip = bakunflip;
18572 
18573  delete [] abtets;
18574 
18575  return nn;
18576 }
18577 
18579 // //
18580 // removefacebyflips() Remove a face by flips. //
18581 // //
18582 // Return 1 if the face is removed. Otherwise, return 0. //
18583 // //
18584 // ASSUMPTIONS: //
18585 // - 'flipface' must not be a hull face. //
18586 // //
18588 
18590 {
18591  if (checksubfaceflag) {
18592  if (issubface(*flipface)) {
18593  return 0;
18594  }
18595  }
18596 
18597  triface fliptets[3], flipedge;
18598  point pa, pb, pc, pd, pe;
18599  REAL ori;
18600  int reducflag = 0;
18601 
18602  fliptets[0] = *flipface;
18603  fsym(*flipface, fliptets[1]);
18604  pa = org(fliptets[0]);
18605  pb = dest(fliptets[0]);
18606  pc = apex(fliptets[0]);
18607  pd = oppo(fliptets[0]);
18608  pe = oppo(fliptets[1]);
18609 
18610  ori = orient3d(pa, pb, pd, pe);
18611  if (ori > 0) {
18612  ori = orient3d(pb, pc, pd, pe);
18613  if (ori > 0) {
18614  ori = orient3d(pc, pa, pd, pe);
18615  if (ori > 0) {
18616  // Found a 2-to-3 flip.
18617  reducflag = 1;
18618  } else {
18619  eprev(*flipface, flipedge); // [c,a]
18620  }
18621  } else {
18622  enext(*flipface, flipedge); // [b,c]
18623  }
18624  } else {
18625  flipedge = *flipface; // [a,b]
18626  }
18627 
18628  if (reducflag) {
18629  // A 2-to-3 flip is found.
18630  flip23(fliptets, 0, fc);
18631  return 1;
18632  } else {
18633  // Try to flip the selected edge of this face.
18634  if (removeedgebyflips(&flipedge, fc) == 2) {
18635  return 1;
18636  }
18637  }
18638 
18639  // Face is not removed.
18640  return 0;
18641 }
18642 
18644 // //
18645 // recoveredge() Recover an edge in current tetrahedralization. //
18646 // //
18647 // If the edge is recovered, 'searchtet' returns a tet containing the edge. //
18648 // //
18649 // This edge may intersect a set of faces and edges in the mesh. All these //
18650 // faces or edges are needed to be removed. //
18651 // //
18652 // If the parameter 'fullsearch' is set, it tries to flip any face or edge //
18653 // that intersects the recovering edge. Otherwise, only the face or edge //
18654 // which is visible by 'startpt' is tried. //
18655 // //
18657 
18659  triface* searchtet, int fullsearch)
18660 {
18661  flipconstraints fc;
18662  enum interresult dir;
18663 
18664  fc.seg[0] = startpt;
18665  fc.seg[1] = endpt;
18666  fc.checkflipeligibility = 1;
18667 
18668  // The mainloop of the edge reocvery.
18669  while (1) { // Loop I
18670 
18671  // Search the edge from 'startpt'.
18672  point2tetorg(startpt, *searchtet);
18673  dir = finddirection(searchtet, endpt);
18674  if (dir == ACROSSVERT) {
18675  if (dest(*searchtet) == endpt) {
18676  return 1; // Edge is recovered.
18677  } else {
18678  printf("Ku!\n"); //return 1;
18679  terminatetetgen(this, 3); // // It may be a PLC problem.
18680  }
18681  }
18682 
18683  // The edge is missing.
18684 
18685 #if 1
18686  // Try to flip the first intersecting face/edge.
18687  enextesymself(*searchtet); // Go to the opposite face.
18688  if (dir == ACROSSFACE) {
18689  // A face is intersected with the segment. Try to flip it.
18690  if (removefacebyflips(searchtet, &fc)) {
18691  continue;
18692  }
18693  } else if (dir == ACROSSEDGE) {
18694  // An edge is intersected with the segment. Try to flip it.
18695  if (removeedgebyflips(searchtet, &fc) == 2) {
18696  continue;
18697  }
18698  } else {
18699  terminatetetgen(this, 3); // It may be a PLC problem.
18700  }
18701 
18702  // The edge is missing.
18703 
18704  if (fullsearch) {
18705  // Try to flip one of the faces/edges which intersects the edge.
18706  triface neightet, spintet;
18707  point pa, pb, pc, pd;
18708  badface bakface;
18709  enum interresult dir1;
18710  int types[2], poss[4], pos = 0;
18711  int success = 0;
18712  int t1ver;
18713  int i, j;
18714 
18715  // Loop through the sequence of intersecting faces/edges from
18716  // 'startpt' to 'endpt'.
18717  point2tetorg(startpt, *searchtet);
18718  dir = finddirection(searchtet, endpt);
18719  //assert(dir != ACROSSVERT);
18720 
18721  // Go to the face/edge intersecting the searching edge.
18722  enextesymself(*searchtet); // Go to the opposite face.
18723  // This face/edge has been tried in previous step.
18724 
18725  while (1) { // Loop I-I
18726 
18727  // Find the next intersecting face/edge.
18728  fsymself(*searchtet);
18729  if (dir == ACROSSFACE) {
18730  neightet = *searchtet;
18731  j = (neightet.ver & 3); // j is the current face number.
18732  for (i = j + 1; i < j + 4; i++) {
18733  neightet.ver = (i % 4);
18734  pa = org(neightet);
18735  pb = dest(neightet);
18736  pc = apex(neightet);
18737  pd = oppo(neightet); // The above point.
18738  if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
18739  dir = (enum interresult) types[0];
18740  pos = poss[0];
18741  break;
18742  } else {
18743  dir = DISJOINT;
18744  pos = 0;
18745  }
18746  } // i
18747  // There must be an intersection face/edge.
18748  assert(dir != DISJOINT); // SELF_CHECK
18749  } else {
18750  assert(dir == ACROSSEDGE);
18751  while (1) { // Loop I-I-I
18752  // Check the two opposite faces (of the edge) in 'searchtet'.
18753  for (i = 0; i < 2; i++) {
18754  if (i == 0) {
18755  enextesym(*searchtet, neightet);
18756  } else {
18757  eprevesym(*searchtet, neightet);
18758  }
18759  pa = org(neightet);
18760  pb = dest(neightet);
18761  pc = apex(neightet);
18762  pd = oppo(neightet); // The above point.
18763  if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
18764  dir = (enum interresult) types[0];
18765  pos = poss[0];
18766  break; // for loop
18767  } else {
18768  dir = DISJOINT;
18769  pos = 0;
18770  }
18771  } // i
18772  if (dir != DISJOINT) {
18773  // Find an intersection face/edge.
18774  break; // Loop I-I-I
18775  }
18776  // No intersection. Rotate to the next tet at the edge.
18777  fnextself(*searchtet);
18778  } // while (1) // Loop I-I-I
18779  }
18780 
18781  // Adjust to the intersecting edge/vertex.
18782  for (i = 0; i < pos; i++) {
18783  enextself(neightet);
18784  }
18785 
18786  if (dir == SHAREVERT) {
18787  // Check if we have reached the 'endpt'.
18788  pd = org(neightet);
18789  if (pd == endpt) {
18790  // Failed to recover the edge.
18791  break; // Loop I-I
18792  } else {
18793  // We need to further check this case. It might be a PLC problem
18794  // or a Steiner point that was added at a bad location.
18795  assert(0);
18796  }
18797  }
18798 
18799  // The next to be flipped face/edge.
18800  *searchtet = neightet;
18801 
18802  // Bakup this face (tetrahedron).
18803  bakface.forg = org(*searchtet);
18804  bakface.fdest = dest(*searchtet);
18805  bakface.fapex = apex(*searchtet);
18806  bakface.foppo = oppo(*searchtet);
18807 
18808  // Try to flip this intersecting face/edge.
18809  if (dir == ACROSSFACE) {
18810  if (removefacebyflips(searchtet, &fc)) {
18811  success = 1;
18812  break; // Loop I-I
18813  }
18814  } else if (dir == ACROSSEDGE) {
18815  if (removeedgebyflips(searchtet, &fc) == 2) {
18816  success = 1;
18817  break; // Loop I-I
18818  }
18819  } else {
18820  assert(0); // A PLC problem.
18821  }
18822 
18823  // The face/edge is not flipped.
18824  if ((searchtet->tet == NULL) ||
18825  (org(*searchtet) != bakface.forg) ||
18826  (dest(*searchtet) != bakface.fdest) ||
18827  (apex(*searchtet) != bakface.fapex) ||
18828  (oppo(*searchtet) != bakface.foppo)) {
18829  // 'searchtet' was flipped. We must restore it.
18830  point2tetorg(bakface.forg, *searchtet);
18831  dir1 = finddirection(searchtet, bakface.fdest);
18832  if (dir1 == ACROSSVERT) {
18833  assert(dest(*searchtet) == bakface.fdest);
18834  spintet = *searchtet;
18835  while (1) {
18836  if (apex(spintet) == bakface.fapex) {
18837  // Found the face.
18838  *searchtet = spintet;
18839  break;
18840  }
18841  fnextself(spintet);
18842  if (spintet.tet == searchtet->tet) {
18843  searchtet->tet = NULL;
18844  break; // Not find.
18845  }
18846  } // while (1)
18847  if (searchtet->tet != NULL) {
18848  if (oppo(*searchtet) != bakface.foppo) {
18849  fsymself(*searchtet);
18850  if (oppo(*searchtet) != bakface.foppo) {
18851  assert(0); // Check this case.
18852  searchtet->tet = NULL;
18853  break; // Not find.
18854  }
18855  }
18856  }
18857  } else {
18858  searchtet->tet = NULL; // Not find.
18859  }
18860  if (searchtet->tet == NULL) {
18861  success = 0; // This face/edge has been destroyed.
18862  break; // Loop I-I
18863  }
18864  }
18865  } // while (1) // Loop I-I
18866 
18867  if (success) {
18868  // One of intersecting faces/edges is flipped.
18869  continue;
18870  }
18871 
18872  } // if (fullsearch)
18873 
18874 #endif
18875  // The edge is missing.
18876  break; // Loop I
18877 
18878  } // while (1) // Loop I
18879 
18880  return 0;
18881 }
18882 
18884 // //
18885 // add_steinerpt_in_schoenhardtpoly() Insert a Steiner point in a Schoen- //
18886 // hardt polyhedron. //
18887 // //
18888 // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
18889 // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, //
18890 // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special //
18891 // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. //
18892 // Such set of tets arises when we want to recover an edge from 'p0' to 'p_ //
18893 // (n-1)', and the number of tets at [a,b] can not be reduced by any flip. //
18894 // //
18896 
18898  int chkencflag)
18899 {
18900  triface worktet, *parytet;
18901  triface faketet1, faketet2;
18902  point pc, pd, steinerpt;
18903  insertvertexflags ivf;
18904  optparameters opm;
18905  REAL vcd[3], sampt[3], smtpt[3];
18906  REAL maxminvol = 0.0, minvol = 0.0, ori;
18907  int success, maxidx = 0;
18908  int it, i;
18909 
18910 
18911  pc = apex(abtets[0]); // pc = p0
18912  pd = oppo(abtets[n-1]); // pd = p_(n-1)
18913 
18914 
18915  // Find an optimial point in edge [c,d]. It is visible by all outer faces
18916  // of 'abtets', and it maxmizes the min volume.
18917 
18918  // initialize the list of 2n boundary faces.
18919  for (i = 0; i < n; i++) {
18920  edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
18921  cavetetlist->newindex((void **) &parytet);
18922  *parytet = worktet;
18923  eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b]
18924  cavetetlist->newindex((void **) &parytet);
18925  *parytet = worktet;
18926  }
18927 
18928  int N = 100;
18929  REAL stepi = 0.01;
18930 
18931  // Search the point along the edge [c,d].
18932  for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
18933 
18934  // Sample N points in edge [c,d].
18935  for (it = 1; it < N; it++) {
18936  for (i = 0; i < 3; i++) {
18937  sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
18938  }
18939  for (i = 0; i < cavetetlist->objects; i++) {
18940  parytet = (triface *) fastlookup(cavetetlist, i);
18941  ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
18942  if (i == 0) {
18943  minvol = ori;
18944  } else {
18945  if (minvol > ori) minvol = ori;
18946  }
18947  } // i
18948  if (it == 1) {
18949  maxminvol = minvol;
18950  maxidx = it;
18951  } else {
18952  if (maxminvol < minvol) {
18953  maxminvol = minvol;
18954  maxidx = it;
18955  }
18956  }
18957  } // it
18958 
18959  if (maxminvol <= 0) {
18960  cavetetlist->restart();
18961  return 0;
18962  }
18963 
18964  for (i = 0; i < 3; i++) {
18965  smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
18966  }
18967 
18968  // Create two faked tets to hold the two non-existing boundary faces:
18969  // [d,c,a] and [c,d,b].
18970  maketetrahedron(&faketet1);
18971  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
18972  cavetetlist->newindex((void **) &parytet);
18973  *parytet = faketet1;
18974  maketetrahedron(&faketet2);
18975  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
18976  cavetetlist->newindex((void **) &parytet);
18977  *parytet = faketet2;
18978 
18979  // Point smooth options.
18980  opm.max_min_volume = 1;
18981  opm.numofsearchdirs = 20;
18982  opm.searchstep = 0.001;
18983  opm.maxiter = 100; // Limit the maximum iterations.
18984  opm.initval = 0.0; // Initial volume is zero.
18985 
18986  // Try to relocate the point into the inside of the polyhedron.
18987  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
18988 
18989  if (success) {
18990  while (opm.smthiter == 100) {
18991  // It was relocated and the prescribed maximum iteration reached.
18992  // Try to increase the search stepsize.
18993  opm.searchstep *= 10.0;
18994  //opm.maxiter = 100; // Limit the maximum iterations.
18995  opm.initval = opm.imprval;
18996  opm.smthiter = 0; // Init.
18997  smoothpoint(smtpt, cavetetlist, 1, &opm);
18998  }
18999  } // if (success)
19000 
19001  // Delete the two faked tets.
19002  tetrahedrondealloc(faketet1.tet);
19003  tetrahedrondealloc(faketet2.tet);
19004 
19005  cavetetlist->restart();
19006 
19007  if (!success) {
19008  return 0;
19009  }
19010 
19011 
19012  // Insert the Steiner point.
19013  makepoint(&steinerpt, FREEVOLVERTEX);
19014  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
19015 
19016  // Insert the created Steiner point.
19017  for (i = 0; i < n; i++) {
19018  infect(abtets[i]);
19019  caveoldtetlist->newindex((void **) &parytet);
19020  *parytet = abtets[i];
19021  }
19022  worktet = abtets[0]; // No need point location.
19023  ivf.iloc = (int) INSTAR;
19024  ivf.chkencflag = chkencflag;
19025  ivf.assignmeshsize = b->metric;
19026  if (ivf.assignmeshsize) {
19027  // Search the tet containing 'steinerpt' for size interpolation.
19028  locate(steinerpt, &(abtets[0]));
19029  worktet = abtets[0];
19030  }
19031 
19032  // Insert the new point into the tetrahedralization T.
19033  // Note that T is convex (nonconvex = 0).
19034  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
19035  // The vertex has been inserted.
19036  st_volref_count++;
19037  if (steinerleft > 0) steinerleft--;
19038  return 1;
19039  } else {
19040  // Not inserted.
19041  pointdealloc(steinerpt);
19042  return 0;
19043  }
19044 }
19045 
19047 // //
19048 // add_steinerpt_in_segment() Add a Steiner point inside a segment. //
19049 // //
19051 
19052 int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
19053 {
19054  triface searchtet;
19055  face *paryseg, candseg;
19056  point startpt, endpt, pc, pd;
19057  flipconstraints fc;
19058  enum interresult dir;
19059  REAL P[3], Q[3], tp, tq;
19060  REAL len, smlen = 0, split = 0, split_q = 0;
19061  int success;
19062  int i;
19063 
19064  startpt = sorg(*misseg);
19065  endpt = sdest(*misseg);
19066 
19067  fc.seg[0] = startpt;
19068  fc.seg[1] = endpt;
19069  fc.checkflipeligibility = 1;
19070  fc.collectencsegflag = 1;
19071 
19072  point2tetorg(startpt, searchtet);
19073  dir = finddirection(&searchtet, endpt);
19074  //assert(dir != ACROSSVERT);
19075 
19076  // Try to flip the first intersecting face/edge.
19077  enextesymself(searchtet); // Go to the opposite face.
19078 
19079  int bak_fliplinklevel = b->fliplinklevel;
19080  b->fliplinklevel = searchlevel;
19081 
19082  if (dir == ACROSSFACE) {
19083  // A face is intersected with the segment. Try to flip it.
19084  success = removefacebyflips(&searchtet, &fc);
19085  assert(success == 0);
19086  } else if (dir == ACROSSEDGE) {
19087  // An edge is intersected with the segment. Try to flip it.
19088  success = removeedgebyflips(&searchtet, &fc);
19089  assert(success != 2);
19090  } else {
19091  terminatetetgen(this, 3); // It may be a PLC problem.
19092  }
19093 
19094  split = 0;
19095  for (i = 0; i < caveencseglist->objects; i++) {
19096  paryseg = (face *) fastlookup(caveencseglist, i);
19097  suninfect(*paryseg);
19098  // Calculate the shortest edge between the two lines.
19099  pc = sorg(*paryseg);
19100  pd = sdest(*paryseg);
19101  tp = tq = 0;
19102  if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
19103  // Does the shortest edge lie between the two segments?
19104  // Round tp and tq.
19105  if ((tp > 0) && (tq < 1)) {
19106  if (tp < 0.5) {
19107  if (tp < (b->epsilon * 1e+3)) tp = 0.0;
19108  } else {
19109  if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
19110  }
19111  }
19112  if ((tp <= 0) || (tp >= 1)) continue;
19113  if ((tq > 0) && (tq < 1)) {
19114  if (tq < 0.5) {
19115  if (tq < (b->epsilon * 1e+3)) tq = 0.0;
19116  } else {
19117  if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
19118  }
19119  }
19120  if ((tq <= 0) || (tq >= 1)) continue;
19121  // It is a valid shortest edge. Calculate its length.
19122  len = distance(P, Q);
19123  if (split == 0) {
19124  smlen = len;
19125  split = tp;
19126  split_q = tq;
19127  candseg = *paryseg;
19128  } else {
19129  if (len < smlen) {
19130  smlen = len;
19131  split = tp;
19132  split_q = tq;
19133  candseg = *paryseg;
19134  }
19135  }
19136  }
19137  }
19138 
19140  b->fliplinklevel = bak_fliplinklevel;
19141 
19142  if (split == 0) {
19143  // Found no crossing segment.
19144  return 0;
19145  }
19146 
19147  face splitsh;
19148  face splitseg;
19149  point steinerpt, *parypt;
19150  insertvertexflags ivf;
19151 
19152  if (b->addsteiner_algo == 1) {
19153  // Split the segment at the closest point to a near segment.
19154  makepoint(&steinerpt, FREESEGVERTEX);
19155  for (i = 0; i < 3; i++) {
19156  steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19157  }
19158  } else { // b->addsteiner_algo == 2
19159  for (i = 0; i < 3; i++) {
19160  P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19161  }
19162  pc = sorg(candseg);
19163  pd = sdest(candseg);
19164  for (i = 0; i < 3; i++) {
19165  Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
19166  }
19167  makepoint(&steinerpt, FREEVOLVERTEX);
19168  for (i = 0; i < 3; i++) {
19169  steinerpt[i] = 0.5 * (P[i] + Q[i]);
19170  }
19171  }
19172 
19173  // We need to locate the point. Start searching from 'searchtet'.
19174  if (split < 0.5) {
19175  point2tetorg(startpt, searchtet);
19176  } else {
19177  point2tetorg(endpt, searchtet);
19178  }
19179  if (b->addsteiner_algo == 1) {
19180  splitseg = *misseg;
19181  spivot(*misseg, splitsh);
19182  } else {
19183  splitsh.sh = NULL;
19184  splitseg.sh = NULL;
19185  }
19186  ivf.iloc = (int) OUTSIDE;
19187  ivf.bowywat = 1;
19188  ivf.lawson = 0;
19189  ivf.rejflag = 0;
19190  ivf.chkencflag = 0;
19191  ivf.sloc = (int) ONEDGE;
19192  ivf.sbowywat = 1;
19193  ivf.splitbdflag = 0;
19194  ivf.validflag = 1;
19195  ivf.respectbdflag = 1;
19196  ivf.assignmeshsize = b->metric;
19197 
19198  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
19199  pointdealloc(steinerpt);
19200  return 0;
19201  }
19202 
19203  if (b->addsteiner_algo == 1) {
19204  // Save this Steiner point (for removal).
19205  // Re-use the array 'subvertstack'.
19206  subvertstack->newindex((void **) &parypt);
19207  *parypt = steinerpt;
19208  st_segref_count++;
19209  } else { // b->addsteiner_algo == 2
19210  // Queue the segment for recovery.
19211  subsegstack->newindex((void **) &paryseg);
19212  *paryseg = *misseg;
19213  st_volref_count++;
19214  }
19215  if (steinerleft > 0) steinerleft--;
19216 
19217  return 1;
19218 }
19219 
19221 // //
19222 // addsteiner4recoversegment() Add a Steiner point for recovering a seg. //
19223 // //
19225 
19226 int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
19227 {
19228  triface *abtets, searchtet, spintet;
19229  face splitsh;
19230  face *paryseg;
19231  point startpt, endpt;
19232  point pa, pb, pd, steinerpt, *parypt;
19233  enum interresult dir;
19234  insertvertexflags ivf;
19235  int types[2], poss[4];
19236  int n, endi, success;
19237  int t1ver;
19238  int i;
19239 
19240  startpt = sorg(*misseg);
19241  if (pointtype(startpt) == FREESEGVERTEX) {
19242  sesymself(*misseg);
19243  startpt = sorg(*misseg);
19244  }
19245  endpt = sdest(*misseg);
19246 
19247  // Try to recover the edge by adding Steiner points.
19248  point2tetorg(startpt, searchtet);
19249  dir = finddirection(&searchtet, endpt);
19250  enextself(searchtet);
19251  //assert(apex(searchtet) == startpt);
19252 
19253  if (dir == ACROSSFACE) {
19254  // The segment is crossing at least 3 faces. Find the common edge of
19255  // the first 3 crossing faces.
19256  esymself(searchtet);
19257  fsym(searchtet, spintet);
19258  pd = oppo(spintet);
19259  for (i = 0; i < 3; i++) {
19260  pa = org(spintet);
19261  pb = dest(spintet);
19262  //pc = apex(neightet);
19263  if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
19264  break; // Found the edge.
19265  }
19266  enextself(spintet);
19267  eprevself(searchtet);
19268  }
19269  assert(i < 3);
19270  esymself(searchtet);
19271  } else {
19272  assert(dir == ACROSSEDGE);
19273  // PLC check.
19274  if (issubseg(searchtet)) {
19275  face checkseg;
19276  tsspivot1(searchtet, checkseg);
19277  printf("Found two segments intersect each other.\n");
19278  pa = farsorg(*misseg);
19279  pb = farsdest(*misseg);
19280  printf(" 1st: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19281  shellmark(*misseg));
19282  pa = farsorg(checkseg);
19283  pb = farsdest(checkseg);
19284  printf(" 2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19285  shellmark(checkseg));
19286  terminatetetgen(this, 3);
19287  }
19288  }
19289  assert(apex(searchtet) == startpt);
19290 
19291  spintet = searchtet;
19292  n = 0; endi = -1;
19293  while (1) {
19294  // Check if the endpt appears in the star.
19295  if (apex(spintet) == endpt) {
19296  endi = n; // Remember the position of endpt.
19297  }
19298  n++; // Count a tet in the star.
19299  fnextself(spintet);
19300  if (spintet.tet == searchtet.tet) break;
19301  }
19302  assert(n >= 3);
19303 
19304  if (endi > 0) {
19305  // endpt is also in the edge star
19306  // Get all tets in the edge star.
19307  abtets = new triface[n];
19308  spintet = searchtet;
19309  for (i = 0; i < n; i++) {
19310  abtets[i] = spintet;
19311  fnextself(spintet);
19312  }
19313 
19314  success = 0;
19315 
19316  if (dir == ACROSSFACE) {
19317  // Find a Steiner points inside the polyhedron.
19318  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19319  success = 1;
19320  }
19321  } else if (dir == ACROSSEDGE) {
19322  if (n > 4) {
19323  // In this case, 'abtets' is separated by the plane (containing the
19324  // two intersecting edges) into two parts, P1 and P2, where P1
19325  // consists of 'endi' tets: abtets[0], abtets[1], ...,
19326  // abtets[endi-1], and P2 consists of 'n - endi' tets:
19327  // abtets[endi], abtets[endi+1], abtets[n-1].
19328  if (endi > 2) { // P1
19329  // There are at least 3 tets in the first part.
19330  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19331  success++;
19332  }
19333  }
19334  if ((n - endi) > 2) { // P2
19335  // There are at least 3 tets in the first part.
19336  if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
19337  success++;
19338  }
19339  }
19340  } else {
19341  // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
19342  // However, there will be invalid tets (either zero or negtive
19343  // volume). Otherwise, [c,d] should already be recovered by the
19344  // recoveredge() function.
19345  terminatetetgen(this, 2); // Report a bug.
19346  }
19347  } else {
19348  terminatetetgen(this, 10); // A PLC problem.
19349  }
19350 
19351  delete [] abtets;
19352 
19353  if (success) {
19354  // Add the missing segment back to the recovering list.
19355  subsegstack->newindex((void **) &paryseg);
19356  *paryseg = *misseg;
19357  return 1;
19358  }
19359  } // if (endi > 0)
19360 
19361  if (!splitsegflag) {
19362  return 0;
19363  }
19364 
19365  if (b->verbose > 2) {
19366  printf(" Splitting segment (%d, %d)\n", pointmark(startpt),
19367  pointmark(endpt));
19368  }
19369  steinerpt = NULL;
19370 
19371  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
19372  if (add_steinerpt_in_segment(misseg, 3)) {
19373  return 1;
19374  }
19375  sesymself(*misseg);
19376  if (add_steinerpt_in_segment(misseg, 3)) {
19377  return 1;
19378  }
19379  sesymself(*misseg);
19380  }
19381 
19382 
19383 
19384 
19385  if (steinerpt == NULL) {
19386  // Split the segment at its midpoint.
19387  makepoint(&steinerpt, FREESEGVERTEX);
19388  for (i = 0; i < 3; i++) {
19389  steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
19390  }
19391 
19392  // We need to locate the point.
19393  assert(searchtet.tet != NULL); // Start searching from 'searchtet'.
19394  spivot(*misseg, splitsh);
19395  ivf.iloc = (int) OUTSIDE;
19396  ivf.bowywat = 1;
19397  ivf.lawson = 0;
19398  ivf.rejflag = 0;
19399  ivf.chkencflag = 0;
19400  ivf.sloc = (int) ONEDGE;
19401  ivf.sbowywat = 1;
19402  ivf.splitbdflag = 0;
19403  ivf.validflag = 1;
19404  ivf.respectbdflag = 1;
19405  ivf.assignmeshsize = b->metric;
19406  if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
19407  assert(0);
19408  }
19409  } // if (endi > 0)
19410 
19411  // Save this Steiner point (for removal).
19412  // Re-use the array 'subvertstack'.
19413  subvertstack->newindex((void **) &parypt);
19414  *parypt = steinerpt;
19415 
19416  st_segref_count++;
19417  if (steinerleft > 0) steinerleft--;
19418 
19419  return 1;
19420 }
19421 
19423 // //
19424 // recoversegments() Recover all segments. //
19425 // //
19426 // All segments need to be recovered are in 'subsegstack'. //
19427 // //
19428 // This routine first tries to recover each segment by only using flips. If //
19429 // no flip is possible, and the flag 'steinerflag' is set, it then tries to //
19430 // insert Steiner points near or in the segment. //
19431 // //
19433 
19434 int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
19435  int steinerflag)
19436 {
19437  triface searchtet, spintet;
19438  face sseg, *paryseg;
19439  point startpt, endpt;
19440  int success;
19441  int t1ver;
19442  long bak_inpoly_count = st_volref_count;
19443  long bak_segref_count = st_segref_count;
19444 
19445  if (b->verbose > 1) {
19446  printf(" Recover segments [%s level = %2d] #: %ld.\n",
19447  (b->fliplinklevel > 0) ? "fixed" : "auto",
19449  subsegstack->objects);
19450  }
19451 
19452  // Loop until 'subsegstack' is empty.
19453  while (subsegstack->objects > 0l) {
19454  // seglist is used as a stack.
19455  subsegstack->objects--;
19456  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
19457  sseg = *paryseg;
19458 
19459  // Check if this segment has been recovered.
19460  sstpivot1(sseg, searchtet);
19461  if (searchtet.tet != NULL) {
19462  continue; // Not a missing segment.
19463  }
19464 
19465  startpt = sorg(sseg);
19466  endpt = sdest(sseg);
19467 
19468  if (b->verbose > 2) {
19469  printf(" Recover segment (%d, %d).\n", pointmark(startpt),
19470  pointmark(endpt));
19471  }
19472 
19473  success = 0;
19474 
19475  if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19476  success = 1;
19477  } else {
19478  // Try to recover it from the other direction.
19479  if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19480  success = 1;
19481  }
19482  }
19483 
19484  if (!success && fullsearch) {
19485  if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) {
19486  success = 1;
19487  }
19488  }
19489 
19490 #if 1
19491  if (success) {
19492  // Segment is recovered. Insert it.
19493  // Let the segment remember an adjacent tet.
19494  sstbond1(sseg, searchtet);
19495  // Bond the segment to all tets containing it.
19496  spintet = searchtet;
19497  do {
19498  tssbond1(spintet, sseg);
19499  fnextself(spintet);
19500  } while (spintet.tet != searchtet.tet);
19501  } else {
19502  if (steinerflag > 0) {
19503  // Try to recover the segment but do not split it.
19504  if (addsteiner4recoversegment(&sseg, 0)) {
19505  success = 1;
19506  }
19507  if (!success && (steinerflag > 1)) {
19508  // Split the segment.
19509  addsteiner4recoversegment(&sseg, 1);
19510  success = 1;
19511  }
19512  }
19513  if (!success) {
19514  if (misseglist != NULL) {
19515  // Save this segment.
19516  misseglist->newindex((void **) &paryseg);
19517  *paryseg = sseg;
19518  }
19519  }
19520  }
19521 #endif
19522  } // while (subsegstack->objects > 0l)
19523 
19524 #if 1
19525  if (steinerflag) {
19526  if (b->verbose > 1) {
19527  // Report the number of added Steiner points.
19528  if (st_volref_count > bak_inpoly_count) {
19529  printf(" Add %ld Steiner points in volume.\n",
19530  st_volref_count - bak_inpoly_count);
19531  }
19532  if (st_segref_count > bak_segref_count) {
19533  printf(" Add %ld Steiner points in segments.\n",
19534  st_segref_count - bak_segref_count);
19535  }
19536  }
19537  }
19538 #endif
19539 
19540  return 0;
19541 }
19542 
19544 // //
19545 // recoverfacebyflips() Recover a face by flips. //
19546 // //
19547 // If 'searchsh' is not NULL, it is a subface to be recovered. It is only //
19548 // used for checking self-intersections. //
19549 // //
19551 
19553  face *searchsh, triface* searchtet)
19554 {
19555  triface spintet, flipedge;
19556  point pd, pe;
19557  enum interresult dir;
19558  flipconstraints fc;
19559  int types[2], poss[4], intflag;
19560  int success, success1;
19561  int t1ver;
19562  int i, j;
19563 
19564 
19565  fc.fac[0] = pa;
19566  fc.fac[1] = pb;
19567  fc.fac[2] = pc;
19568  fc.checkflipeligibility = 1;
19569  success = 0;
19570 
19571  for (i = 0; i < 3 && !success; i++) {
19572  while (1) {
19573  // Get a tet containing the edge [a,b].
19574  point2tetorg(fc.fac[i], *searchtet);
19575  dir = finddirection(searchtet, fc.fac[(i+1)%3]);
19576  //assert(dir == ACROSSVERT);
19577  assert(dest(*searchtet) == fc.fac[(i+1)%3]);
19578  // Search the face [a,b,c]
19579  spintet = *searchtet;
19580  while (1) {
19581  if (apex(spintet) == fc.fac[(i+2)%3]) {
19582  // Found the face.
19583  *searchtet = spintet;
19584  // Return the face [a,b,c].
19585  for (j = i; j > 0; j--) {
19586  eprevself(*searchtet);
19587  }
19588  success = 1;
19589  break;
19590  }
19591  fnextself(spintet);
19592  if (spintet.tet == searchtet->tet) break;
19593  } // while (1)
19594  if (success) break;
19595  // The face is missing. Try to recover it.
19596  success1 = 0;
19597  // Find a crossing edge of this face.
19598  spintet = *searchtet;
19599  while (1) {
19600  pd = apex(spintet);
19601  pe = oppo(spintet);
19602  if ((pd != dummypoint) && (pe != dummypoint)) {
19603  // Check if [d,e] intersects [a,b,c]
19604  intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
19605  if (intflag > 0) {
19606  // By our assumptions, they can only intersect at a single point.
19607  if (intflag == 2) {
19608  // Check the intersection type.
19609  dir = (enum interresult) types[0];
19610  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
19611  // Go to the edge [d,e].
19612  edestoppo(spintet, flipedge); // [d,e,a,b]
19613  if (searchsh != NULL) {
19614  // Check if [e,d] is a segment.
19615  if (issubseg(flipedge)) {
19616  if (!b->quiet) {
19617  face checkseg;
19618  tsspivot1(flipedge, checkseg);
19619  printf("Found a segment and a subface intersect.\n");
19620  pd = farsorg(checkseg);
19621  pe = farsdest(checkseg);
19622  printf(" 1st: [%d, %d] %d.\n", pointmark(pd),
19623  pointmark(pe), shellmark(checkseg));
19624  printf(" 2nd: [%d,%d,%d] %d\n", pointmark(pa),
19625  pointmark(pb), pointmark(pc), shellmark(*searchsh));
19626  }
19627  terminatetetgen(this, 3);
19628  }
19629  }
19630  // Try to flip the edge [d,e].
19631  success1 = (removeedgebyflips(&flipedge, &fc) == 2);
19632  } else {
19633  if (dir == TOUCHFACE) {
19634  point touchpt, *parypt;
19635  if (poss[1] == 0) {
19636  touchpt = pd; // pd is a coplanar vertex.
19637  } else {
19638  touchpt = pe; // pe is a coplanar vertex.
19639  }
19640  if (pointtype(touchpt) == FREEVOLVERTEX) {
19641  // A volume Steiner point was added in this subface.
19642  // Split this subface by this point.
19643  face checksh, *parysh;
19644  int siloc = (int) ONFACE;
19645  int sbowat = 0; // Only split this subface.
19646  setpointtype(touchpt, FREEFACETVERTEX);
19647  sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
19648  st_volref_count--;
19649  st_facref_count++;
19650  // Queue this vertex for removal.
19651  subvertstack->newindex((void **) &parypt);
19652  *parypt = touchpt;
19653  // Queue new subfaces for recovery.
19654  // Put all new subfaces into stack for recovery.
19655  for (i = 0; i < caveshbdlist->objects; i++) {
19656  // Get an old subface at edge [a, b].
19657  parysh = (face *) fastlookup(caveshbdlist, i);
19658  spivot(*parysh, checksh); // The new subface [a, b, p].
19659  // Do not recover a deleted new face (degenerated).
19660  if (checksh.sh[3] != NULL) {
19661  subfacstack->newindex((void **) &parysh);
19662  *parysh = checksh;
19663  }
19664  }
19665  // Delete the old subfaces in sC(p).
19666  assert(caveshlist->objects == 1);
19667  for (i = 0; i < caveshlist->objects; i++) {
19668  parysh = (face *) fastlookup(caveshlist, i);
19669  shellfacedealloc(subfaces, parysh->sh);
19670  }
19671  // Clear working lists.
19672  caveshlist->restart();
19673  caveshbdlist->restart();
19675  // We can return this function.
19676  searchsh->sh = NULL; // It has been split.
19677  success1 = 0;
19678  success = 1;
19679  } else {
19680  // It should be a PLC problem.
19681  if (pointtype(touchpt) == FREESEGVERTEX) {
19682  // A segment and a subface intersect.
19683  } else if (pointtype(touchpt) == FREEFACETVERTEX) {
19684  // Two facets self-intersect.
19685  }
19686  terminatetetgen(this, 3);
19687  }
19688  } else {
19689  assert(0); // Unknown cases. Debug.
19690  }
19691  }
19692  break;
19693  } else { // intflag == 4. Coplanar case.
19694  // This may be an input PLC error.
19695  assert(0);
19696  }
19697  } // if (intflag > 0)
19698  }
19699  fnextself(spintet);
19700  assert(spintet.tet != searchtet->tet);
19701  } // while (1)
19702  if (!success1) break;
19703  } // while (1)
19704  } // i
19705 
19706  return success;
19707 }
19708 
19710 // //
19711 // recoversubfaces() Recover all subfaces. //
19712 // //
19714 
19715 int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
19716 {
19717  triface searchtet, neightet, spintet;
19718  face searchsh, neighsh, neineish, *parysh;
19719  face bdsegs[3];
19720  point startpt, endpt, apexpt, *parypt;
19721  point steinerpt;
19722  enum interresult dir;
19723  insertvertexflags ivf;
19724  int success;
19725  int t1ver;
19726  int i, j;
19727 
19728  //return 0;
19729 
19730  if (b->verbose > 1) {
19731  printf(" Recover subfaces [%s level = %2d] #: %ld.\n",
19732  (b->fliplinklevel > 0) ? "fixed" : "auto",
19734  subfacstack->objects);
19735  }
19736 
19737  // Loop until 'subfacstack' is empty.
19738  while (subfacstack->objects > 0l) {
19739 
19740  subfacstack->objects--;
19741  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
19742  searchsh = *parysh;
19743 
19744  if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
19745 
19746  stpivot(searchsh, neightet);
19747  if (neightet.tet != NULL) continue; // Skip a recovered subface.
19748 
19749 
19750  if (b->verbose > 2) {
19751  printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
19752  pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
19753  }
19754 
19755  // The three edges of the face need to be existed first.
19756  for (i = 0; i < 3; i++) {
19757  sspivot(searchsh, bdsegs[i]);
19758  if (bdsegs[i].sh != NULL) {
19759  // The segment must exist.
19760  sstpivot1(bdsegs[i], searchtet);
19761  if (searchtet.tet == NULL) {
19762  assert(0);
19763  }
19764  } else {
19765  // This edge is not a segment (due to a Steiner point).
19766  // Check whether it exists or not.
19767  success = 0;
19768  startpt = sorg(searchsh);
19769  endpt = sdest(searchsh);
19770  point2tetorg(startpt, searchtet);
19771  dir = finddirection(&searchtet, endpt);
19772  if (dir == ACROSSVERT) {
19773  if (dest(searchtet) == endpt) {
19774  success = 1;
19775  } else {
19776  //assert(0); // A PLC problem.
19777  terminatetetgen(this, 3);
19778  }
19779  } else {
19780  // The edge is missing. Try to recover it.
19781  if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19782  success = 1;
19783  } else {
19784  if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19785  success = 1;
19786  }
19787  }
19788  }
19789  if (success) {
19790  // Insert a temporary segment to protect this edge.
19791  makeshellface(subsegs, &(bdsegs[i]));
19792  setshvertices(bdsegs[i], startpt, endpt, NULL);
19793  smarktest2(bdsegs[i]); // It's a temporary segment.
19794  // Insert this segment into surface mesh.
19795  ssbond(searchsh, bdsegs[i]);
19796  spivot(searchsh, neighsh);
19797  if (neighsh.sh != NULL) {
19798  ssbond(neighsh, bdsegs[i]);
19799  }
19800  // Insert this segment into tetrahedralization.
19801  sstbond1(bdsegs[i], searchtet);
19802  // Bond the segment to all tets containing it.
19803  spintet = searchtet;
19804  do {
19805  tssbond1(spintet, bdsegs[i]);
19806  fnextself(spintet);
19807  } while (spintet.tet != searchtet.tet);
19808  } else {
19809  // An edge of this subface is missing. Can't recover this subface.
19810  // Delete any temporary segment that has been created.
19811  for (j = (i - 1); j >= 0; j--) {
19812  if (smarktest2ed(bdsegs[j])) {
19813  spivot(bdsegs[j], neineish);
19814  assert(neineish.sh != NULL);
19815  //if (neineish.sh != NULL) {
19816  ssdissolve(neineish);
19817  spivot(neineish, neighsh);
19818  if (neighsh.sh != NULL) {
19819  ssdissolve(neighsh);
19820  // There should be only two subfaces at this segment.
19821  spivotself(neighsh); // SELF_CHECK
19822  assert(neighsh.sh == neineish.sh);
19823  }
19824  //}
19825  sstpivot1(bdsegs[j], searchtet);
19826  assert(searchtet.tet != NULL);
19827  //if (searchtet.tet != NULL) {
19828  spintet = searchtet;
19829  while (1) {
19830  tssdissolve1(spintet);
19831  fnextself(spintet);
19832  if (spintet.tet == searchtet.tet) break;
19833  }
19834  //}
19835  shellfacedealloc(subsegs, bdsegs[j].sh);
19836  }
19837  } // j
19838  if (steinerflag) {
19839  // Add a Steiner point at the midpoint of this edge.
19840  if (b->verbose > 2) {
19841  printf(" Add a Steiner point in subedge (%d, %d).\n",
19842  pointmark(startpt), pointmark(endpt));
19843  }
19844  makepoint(&steinerpt, FREEFACETVERTEX);
19845  for (j = 0; j < 3; j++) {
19846  steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
19847  }
19848 
19849  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
19850  ivf.iloc = (int) OUTSIDE; // Need point location.
19851  ivf.bowywat = 1;
19852  ivf.lawson = 0;
19853  ivf.rejflag = 0;
19854  ivf.chkencflag = 0;
19855  ivf.sloc = (int) ONEDGE;
19856  ivf.sbowywat = 1; // Allow flips in facet.
19857  ivf.splitbdflag = 0;
19858  ivf.validflag = 1;
19859  ivf.respectbdflag = 1;
19860  ivf.assignmeshsize = b->metric;
19861  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
19862  assert(0);
19863  }
19864  // Save this Steiner point (for removal).
19865  // Re-use the array 'subvertstack'.
19866  subvertstack->newindex((void **) &parypt);
19867  *parypt = steinerpt;
19868 
19869  st_facref_count++;
19870  if (steinerleft > 0) steinerleft--;
19871  } // if (steinerflag)
19872  break;
19873  }
19874  }
19875  senextself(searchsh);
19876  } // i
19877 
19878  if (i == 3) {
19879  // Recover the subface.
19880  startpt = sorg(searchsh);
19881  endpt = sdest(searchsh);
19882  apexpt = sapex(searchsh);
19883 
19884  success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
19885 
19886  // Delete any temporary segment that has been created.
19887  for (j = 0; j < 3; j++) {
19888  if (smarktest2ed(bdsegs[j])) {
19889  spivot(bdsegs[j], neineish);
19890  assert(neineish.sh != NULL);
19891  //if (neineish.sh != NULL) {
19892  ssdissolve(neineish);
19893  spivot(neineish, neighsh);
19894  if (neighsh.sh != NULL) {
19895  ssdissolve(neighsh);
19896  // There should be only two subfaces at this segment.
19897  spivotself(neighsh); // SELF_CHECK
19898  assert(neighsh.sh == neineish.sh);
19899  }
19900  //}
19901  sstpivot1(bdsegs[j], neightet);
19902  assert(neightet.tet != NULL);
19903  //if (neightet.tet != NULL) {
19904  spintet = neightet;
19905  while (1) {
19906  tssdissolve1(spintet);
19907  fnextself(spintet);
19908  if (spintet.tet == neightet.tet) break;
19909  }
19910  //}
19911  shellfacedealloc(subsegs, bdsegs[j].sh);
19912  }
19913  } // j
19914 
19915  if (success) {
19916  if (searchsh.sh != NULL) {
19917  // Face is recovered. Insert it.
19918  tsbond(searchtet, searchsh);
19919  fsymself(searchtet);
19920  sesymself(searchsh);
19921  tsbond(searchtet, searchsh);
19922  }
19923  } else {
19924  if (steinerflag) {
19925  // Add a Steiner point at the barycenter of this subface.
19926  if (b->verbose > 2) {
19927  printf(" Add a Steiner point in subface (%d, %d, %d).\n",
19928  pointmark(startpt), pointmark(endpt), pointmark(apexpt));
19929  }
19930  makepoint(&steinerpt, FREEFACETVERTEX);
19931  for (j = 0; j < 3; j++) {
19932  steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
19933  }
19934 
19935  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
19936  ivf.iloc = (int) OUTSIDE; // Need point location.
19937  ivf.bowywat = 1;
19938  ivf.lawson = 0;
19939  ivf.rejflag = 0;
19940  ivf.chkencflag = 0;
19941  ivf.sloc = (int) ONFACE;
19942  ivf.sbowywat = 1; // Allow flips in facet.
19943  ivf.splitbdflag = 0;
19944  ivf.validflag = 1;
19945  ivf.respectbdflag = 1;
19946  ivf.assignmeshsize = b->metric;
19947  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
19948  assert(0);
19949  }
19950  // Save this Steiner point (for removal).
19951  // Re-use the array 'subvertstack'.
19952  subvertstack->newindex((void **) &parypt);
19953  *parypt = steinerpt;
19954 
19955  st_facref_count++;
19956  if (steinerleft > 0) steinerleft--;
19957  } // if (steinerflag)
19958  }
19959  } else {
19960  success = 0;
19961  }
19962 
19963  if (!success) {
19964  if (misshlist != NULL) {
19965  // Save this subface.
19966  misshlist->newindex((void **) &parysh);
19967  *parysh = searchsh;
19968  }
19969  }
19970 
19971  } // while (subfacstack->objects > 0l)
19972 
19973  return 0;
19974 }
19975 
19977 // //
19978 // getvertexstar() Return the star of a vertex. //
19979 // //
19980 // If the flag 'fullstar' is set, return the complete star of this vertex. //
19981 // Otherwise, only a part of the star which is bounded by facets is returned.//
19982 // //
19983 // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'. //
19984 // Every tet in 'tetlist' is at the face opposing to 'searchpt'. //
19985 // //
19986 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
19987 // //
19988 // 'shlist' returns the list of subfaces in the star. Each subface must face //
19989 // to the interior of this star. //
19990 // //
19992 
19993 int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
19994  arraypool* vertlist, arraypool* shlist)
19995 {
19996  triface searchtet, neightet, *parytet;
19997  face checksh, *parysh;
19998  point pt, *parypt;
19999  int collectflag;
20000  int t1ver;
20001  int i, j;
20002 
20003  point2tetorg(searchpt, searchtet);
20004 
20005  // Go to the opposite face (the link face) of the vertex.
20006  enextesymself(searchtet);
20007  //assert(oppo(searchtet) == searchpt);
20008  infect(searchtet); // Collect this tet (link face).
20009  tetlist->newindex((void **) &parytet);
20010  *parytet = searchtet;
20011  if (vertlist != NULL) {
20012  // Collect three (link) vertices.
20013  j = (searchtet.ver & 3); // The current vertex index.
20014  for (i = 1; i < 4; i++) {
20015  pt = (point) searchtet.tet[4 + ((j + i) % 4)];
20016  pinfect(pt);
20017  vertlist->newindex((void **) &parypt);
20018  *parypt = pt;
20019  }
20020  }
20021 
20022  collectflag = 1;
20023  esym(searchtet, neightet);
20024  if (issubface(neightet)) {
20025  if (shlist != NULL) {
20026  tspivot(neightet, checksh);
20027  if (!sinfected(checksh)) {
20028  // Collect this subface (link edge).
20029  sinfected(checksh);
20030  shlist->newindex((void **) &parysh);
20031  *parysh = checksh;
20032  }
20033  }
20034  if (!fullstar) {
20035  collectflag = 0;
20036  }
20037  }
20038  if (collectflag) {
20039  fsymself(neightet); // Goto the adj tet of this face.
20040  esymself(neightet); // Goto the oppo face of this vertex.
20041  // assert(oppo(neightet) == searchpt);
20042  infect(neightet); // Collect this tet (link face).
20043  tetlist->newindex((void **) &parytet);
20044  *parytet = neightet;
20045  if (vertlist != NULL) {
20046  // Collect its apex.
20047  pt = apex(neightet);
20048  pinfect(pt);
20049  vertlist->newindex((void **) &parypt);
20050  *parypt = pt;
20051  }
20052  } // if (collectflag)
20053 
20054  // Continue to collect all tets in the star.
20055  for (i = 0; i < tetlist->objects; i++) {
20056  searchtet = * (triface *) fastlookup(tetlist, i);
20057  // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
20058  // tet at the current edge is already collected.
20059  // Check the neighbors at the other two edges of this face.
20060  for (j = 0; j < 2; j++) {
20061  collectflag = 1;
20062  enextself(searchtet);
20063  esym(searchtet, neightet);
20064  if (issubface(neightet)) {
20065  if (shlist != NULL) {
20066  tspivot(neightet, checksh);
20067  if (!sinfected(checksh)) {
20068  // Collect this subface (link edge).
20069  sinfected(checksh);
20070  shlist->newindex((void **) &parysh);
20071  *parysh = checksh;
20072  }
20073  }
20074  if (!fullstar) {
20075  collectflag = 0;
20076  }
20077  }
20078  if (collectflag) {
20079  fsymself(neightet);
20080  if (!infected(neightet)) {
20081  esymself(neightet); // Go to the face opposite to 'searchpt'.
20082  infect(neightet);
20083  tetlist->newindex((void **) &parytet);
20084  *parytet = neightet;
20085  if (vertlist != NULL) {
20086  // Check if a vertex is collected.
20087  pt = apex(neightet);
20088  if (!pinfected(pt)) {
20089  pinfect(pt);
20090  vertlist->newindex((void **) &parypt);
20091  *parypt = pt;
20092  }
20093  }
20094  } // if (!infected(neightet))
20095  } // if (collectflag)
20096  } // j
20097  } // i
20098 
20099 
20100  // Uninfect the list of tets and vertices.
20101  for (i = 0; i < tetlist->objects; i++) {
20102  parytet = (triface *) fastlookup(tetlist, i);
20103  uninfect(*parytet);
20104  }
20105 
20106  if (vertlist != NULL) {
20107  for (i = 0; i < vertlist->objects; i++) {
20108  parypt = (point *) fastlookup(vertlist, i);
20109  puninfect(*parypt);
20110  }
20111  }
20112 
20113  if (shlist != NULL) {
20114  for (i = 0; i < shlist->objects; i++) {
20115  parysh = (face *) fastlookup(shlist, i);
20116  suninfect(*parysh);
20117  }
20118  }
20119 
20120  return (int) tetlist->objects;
20121 }
20122 
20124 // //
20125 // getedge() Get a tetrahedron having the two endpoints. //
20126 // //
20127 // The method here is to search the second vertex in the link faces of the //
20128 // first vertex. The global array 'cavetetlist' is re-used for searching. //
20129 // //
20130 // This function is used for the case when the mesh is non-convex. Otherwise,//
20131 // the function finddirection() should be faster than this. //
20132 // //
20134 
20136 {
20137  triface searchtet, neightet, *parytet;
20138  point pt;
20139  int done;
20140  int i, j;
20141 
20142  if (b->verbose > 2) {
20143  printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
20144  }
20145 
20146  // Quickly check if 'tedge' is just this edge.
20147  if (!isdeadtet(*tedge)) {
20148  if (org(*tedge) == e1) {
20149  if (dest(*tedge) == e2) {
20150  return 1;
20151  }
20152  } else if (org(*tedge) == e2) {
20153  if (dest(*tedge) == e1) {
20154  esymself(*tedge);
20155  return 1;
20156  }
20157  }
20158  }
20159 
20160  // Search for the edge [e1, e2].
20161  point2tetorg(e1, *tedge);
20162  finddirection(tedge, e2);
20163  if (dest(*tedge) == e2) {
20164  return 1;
20165  } else {
20166  // Search for the edge [e2, e1].
20167  point2tetorg(e2, *tedge);
20168  finddirection(tedge, e1);
20169  if (dest(*tedge) == e1) {
20170  esymself(*tedge);
20171  return 1;
20172  }
20173  }
20174 
20175 
20176  // Go to the link face of e1.
20177  point2tetorg(e1, searchtet);
20178  enextesymself(searchtet);
20179  //assert(oppo(searchtet) == e1);
20180 
20181  assert(cavebdrylist->objects == 0l); // It will re-use this list.
20182  arraypool *tetlist = cavebdrylist;
20183 
20184  // Search e2.
20185  for (i = 0; i < 3; i++) {
20186  pt = apex(searchtet);
20187  if (pt == e2) {
20188  // Found. 'searchtet' is [#,#,e2,e1].
20189  eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
20190  return 1;
20191  }
20192  enextself(searchtet);
20193  }
20194 
20195  // Get the adjacent link face at 'searchtet'.
20196  fnext(searchtet, neightet);
20197  esymself(neightet);
20198  // assert(oppo(neightet) == e1);
20199  pt = apex(neightet);
20200  if (pt == e2) {
20201  // Found. 'neightet' is [#,#,e2,e1].
20202  eorgoppo(neightet, *tedge); // [e1,e2,#,#].
20203  return 1;
20204  }
20205 
20206  // Continue searching in the link face of e1.
20207  infect(searchtet);
20208  tetlist->newindex((void **) &parytet);
20209  *parytet = searchtet;
20210  infect(neightet);
20211  tetlist->newindex((void **) &parytet);
20212  *parytet = neightet;
20213 
20214  done = 0;
20215 
20216  for (i = 0; (i < tetlist->objects) && !done; i++) {
20217  parytet = (triface *) fastlookup(tetlist, i);
20218  searchtet = *parytet;
20219  for (j = 0; (j < 2) && !done; j++) {
20220  enextself(searchtet);
20221  fnext(searchtet, neightet);
20222  if (!infected(neightet)) {
20223  esymself(neightet);
20224  pt = apex(neightet);
20225  if (pt == e2) {
20226  // Found. 'neightet' is [#,#,e2,e1].
20227  eorgoppo(neightet, *tedge);
20228  done = 1;
20229  } else {
20230  infect(neightet);
20231  tetlist->newindex((void **) &parytet);
20232  *parytet = neightet;
20233  }
20234  }
20235  } // j
20236  } // i
20237 
20238  // Uninfect the list of visited tets.
20239  for (i = 0; i < tetlist->objects; i++) {
20240  parytet = (triface *) fastlookup(tetlist, i);
20241  uninfect(*parytet);
20242  }
20243  tetlist->restart();
20244 
20245  return done;
20246 }
20247 
20249 // //
20250 // reduceedgesatvertex() Reduce the number of edges at a given vertex. //
20251 // //
20252 // 'endptlist' contains the endpoints of edges connecting at the vertex. //
20253 // //
20255 
20257 {
20258  triface searchtet;
20259  point *pendpt, *parypt;
20260  enum interresult dir;
20261  flipconstraints fc;
20262  int reduceflag;
20263  int count;
20264  int n, i, j;
20265 
20266 
20267  fc.remvert = startpt;
20268  fc.checkflipeligibility = 1;
20269 
20270  while (1) {
20271 
20272  count = 0;
20273 
20274  for (i = 0; i < endptlist->objects; i++) {
20275  pendpt = (point *) fastlookup(endptlist, i);
20276  if (*pendpt == dummypoint) {
20277  continue; // Do not reduce a virtual edge.
20278  }
20279  reduceflag = 0;
20280  // Find the edge.
20281  if (nonconvex) {
20282  if (getedge(startpt, *pendpt, &searchtet)) {
20283  dir = ACROSSVERT;
20284  } else {
20285  // The edge does not exist (was flipped).
20286  dir = INTERSECT;
20287  }
20288  } else {
20289  point2tetorg(startpt, searchtet);
20290  dir = finddirection(&searchtet, *pendpt);
20291  }
20292  if (dir == ACROSSVERT) {
20293  if (dest(searchtet) == *pendpt) {
20294  // Do not flip a segment.
20295  if (!issubseg(searchtet)) {
20296  n = removeedgebyflips(&searchtet, &fc);
20297  if (n == 2) {
20298  reduceflag = 1;
20299  }
20300  }
20301  } else {
20302  assert(0); // A plc problem.
20303  }
20304  } else {
20305  // The edge has been flipped.
20306  reduceflag = 1;
20307  }
20308  if (reduceflag) {
20309  count++;
20310  // Move the last vertex into this slot.
20311  j = endptlist->objects - 1;
20312  parypt = (point *) fastlookup(endptlist, j);
20313  *pendpt = *parypt;
20314  endptlist->objects--;
20315  i--;
20316  }
20317  } // i
20318 
20319  if (count == 0) {
20320  // No edge is reduced.
20321  break;
20322  }
20323 
20324  } // while (1)
20325 
20326  return (int) endptlist->objects;
20327 }
20328 
20330 // //
20331 // removevertexbyflips() Remove a vertex by flips. //
20332 // //
20333 // This routine attempts to remove the given vertex 'rempt' (p) from the //
20334 // tetrahedralization (T) by a sequence of flips. //
20335 // //
20336 // The algorithm used here is a simple edge reduce method. Suppose there are //
20337 // n edges connected at p. We try to reduce the number of edges by flipping //
20338 // any edge (not a segment) that is connecting at p. //
20339 // //
20340 // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
20341 // can be successfully removed. //
20342 // //
20344 
20346 {
20347  triface *fliptets = NULL, wrktets[4];
20348  triface searchtet, spintet, neightet;
20349  face parentsh, spinsh, checksh;
20350  face leftseg, rightseg, checkseg;
20351  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
20352  flipconstraints fc;
20353  enum verttype vt;
20354  enum locateresult loc;
20355  int valence, removeflag;
20356  int slawson;
20357  int t1ver;
20358  int n, i;
20359 
20360  vt = pointtype(steinerpt);
20361 
20362  if (vt == FREESEGVERTEX) {
20363  sdecode(point2sh(steinerpt), leftseg);
20364  assert(leftseg.sh != NULL);
20365  leftseg.shver = 0;
20366  if (sdest(leftseg) == steinerpt) {
20367  senext(leftseg, rightseg);
20368  spivotself(rightseg);
20369  assert(rightseg.sh != NULL);
20370  rightseg.shver = 0;
20371  assert(sorg(rightseg) == steinerpt);
20372  } else {
20373  assert(sorg(leftseg) == steinerpt);
20374  rightseg = leftseg;
20375  senext2(rightseg, leftseg);
20376  spivotself(leftseg);
20377  assert(leftseg.sh != NULL);
20378  leftseg.shver = 0;
20379  assert(sdest(leftseg) == steinerpt);
20380  }
20381  lpt = sorg(leftseg);
20382  rpt = sdest(rightseg);
20383  if (b->verbose > 2) {
20384  printf(" Removing Steiner point %d in segment (%d, %d).\n",
20385  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20386 
20387  }
20388  } else if (vt == FREEFACETVERTEX) {
20389  if (b->verbose > 2) {
20390  printf(" Removing Steiner point %d in facet.\n",
20391  pointmark(steinerpt));
20392  }
20393  } else if (vt == FREEVOLVERTEX) {
20394  if (b->verbose > 2) {
20395  printf(" Removing Steiner point %d in volume.\n",
20396  pointmark(steinerpt));
20397  }
20398  } else if (vt == VOLVERTEX) {
20399  if (b->verbose > 2) {
20400  printf(" Removing a point %d in volume.\n",
20401  pointmark(steinerpt));
20402  }
20403  } else {
20404  // It is not a Steiner point.
20405  return 0;
20406  }
20407 
20408  // Try to reduce the number of edges at 'p' by flips.
20409  getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
20410  cavetetlist->restart(); // This list may be re-used.
20411  if (cavetetvertlist->objects > 3l) {
20412  valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
20413  } else {
20414  valence = cavetetvertlist->objects;
20415  }
20416  assert(cavetetlist->objects == 0l);
20418 
20419  removeflag = 0;
20420 
20421  if (valence == 4) {
20422  // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
20423  // vertices. This case is due to that 'p' is not exactly on the segment.
20424  point2tetorg(steinerpt, searchtet);
20425  loc = INTETRAHEDRON;
20426  removeflag = 1;
20427  } else if (valence == 5) {
20428  // There are 5 edges.
20429  if (vt == FREESEGVERTEX) {
20430  sstpivot1(leftseg, searchtet);
20431  if (org(searchtet) != steinerpt) {
20432  esymself(searchtet);
20433  }
20434  assert(org(searchtet) == steinerpt);
20435  assert(dest(searchtet) == lpt);
20436  i = 0; // Count the numbe of tet at the edge [p,lpt].
20437  neightet.tet = NULL; // Init the face.
20438  spintet = searchtet;
20439  while (1) {
20440  i++;
20441  if (apex(spintet) == rpt) {
20442  // Remember the face containing the edge [lpt, rpt].
20443  neightet = spintet;
20444  }
20445  fnextself(spintet);
20446  if (spintet.tet == searchtet.tet) break;
20447  }
20448  if (i == 3) {
20449  // This case has been checked below.
20450  } else if (i == 4) {
20451  // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
20452  // at [p,rpt]. There must be a face [p, lpt, rpt].
20453  if (apex(neightet) == rpt) {
20454  // The edge (segment) has been already recovered!
20455  // Check if a 6-to-2 flip is possible (to remove 'p').
20456  // Let 'searchtet' be [p,d,a,b]
20457  esym(neightet, searchtet);
20458  enextself(searchtet);
20459  // Check if there are exactly three tets at edge [p,d].
20460  wrktets[0] = searchtet; // [p,d,a,b]
20461  for (i = 0; i < 2; i++) {
20462  fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
20463  }
20464  if (apex(wrktets[0]) == oppo(wrktets[2])) {
20465  loc = ONFACE;
20466  removeflag = 1;
20467  }
20468  }
20469  }
20470  } else if (vt == FREEFACETVERTEX) {
20471  // It is possible to do a 6-to-2 flip to remove the vertex.
20472  point2tetorg(steinerpt, searchtet);
20473  // Get the three faces of 'searchtet' which share at p.
20474  // All faces has p as origin.
20475  wrktets[0] = searchtet;
20476  wrktets[1] = searchtet;
20477  esymself(wrktets[1]);
20478  enextself(wrktets[1]);
20479  wrktets[2] = searchtet;
20480  eprevself(wrktets[2]);
20481  esymself(wrktets[2]);
20482  // All internal edges of the six tets have valance either 3 or 4.
20483  // Get one edge which has valance 3.
20484  searchtet.tet = NULL;
20485  for (i = 0; i < 3; i++) {
20486  spintet = wrktets[i];
20487  valence = 0;
20488  while (1) {
20489  valence++;
20490  fnextself(spintet);
20491  if (spintet.tet == wrktets[i].tet) break;
20492  }
20493  if (valence == 3) {
20494  // Found the edge.
20495  searchtet = wrktets[i];
20496  break;
20497  } else {
20498  assert(valence == 4);
20499  }
20500  }
20501  assert(searchtet.tet != NULL);
20502  // Note, we do not detach the three subfaces at p.
20503  // They will be removed within a 4-to-1 flip.
20504  loc = ONFACE;
20505  removeflag = 1;
20506  } else {
20507  // assert(0); DEBUG IT
20508  }
20509  //removeflag = 1;
20510  }
20511 
20512  if (!removeflag) {
20513  if (vt == FREESEGVERTEX) {
20514  // Check is it possible to recover the edge [lpt,rpt].
20515  // The condition to check is: Whether each tet containing 'leftseg' is
20516  // adjacent to a tet containing 'rightseg'.
20517  sstpivot1(leftseg, searchtet);
20518  if (org(searchtet) != steinerpt) {
20519  esymself(searchtet);
20520  }
20521  assert(org(searchtet) == steinerpt);
20522  assert(dest(searchtet) == lpt);
20523  spintet = searchtet;
20524  while (1) {
20525  // Go to the bottom face of this tet.
20526  eprev(spintet, neightet);
20527  esymself(neightet); // [steinerpt, p1, p2, lpt]
20528  // Get the adjacent tet.
20529  fsymself(neightet); // [p1, steinerpt, p2, rpt]
20530  if (oppo(neightet) != rpt) {
20531  // Found a non-matching adjacent tet.
20532  break;
20533  }
20534  fnextself(spintet);
20535  if (spintet.tet == searchtet.tet) {
20536  // 'searchtet' is [p,d,p1,p2].
20537  loc = ONEDGE;
20538  removeflag = 1;
20539  break;
20540  }
20541  }
20542  } // if (vt == FREESEGVERTEX)
20543  }
20544 
20545  if (!removeflag) {
20546  if (vt == FREESEGVERTEX) {
20547  // Check if the edge [lpt, rpt] exists.
20548  if (getedge(lpt, rpt, &searchtet)) {
20549  // We have recovered this edge. Shift the vertex into the volume.
20550  // We can recover this edge if the subfaces are not recovered yet.
20551  if (!checksubfaceflag) {
20552  // Remove the vertex from the surface mesh.
20553  // This will re-create the segment [lpt, rpt] and re-triangulate
20554  // all the facets at the segment.
20555  // Detach the subsegments from their surrounding tets.
20556  for (i = 0; i < 2; i++) {
20557  checkseg = (i == 0) ? leftseg : rightseg;
20558  sstpivot1(checkseg, neightet);
20559  spintet = neightet;
20560  while (1) {
20561  tssdissolve1(spintet);
20562  fnextself(spintet);
20563  if (spintet.tet == neightet.tet) break;
20564  }
20565  sstdissolve1(checkseg);
20566  } // i
20567  slawson = 1; // Do lawson flip after removal.
20568  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20569  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20570  // Clear the list for new subfaces.
20571  caveshbdlist->restart();
20572  // Insert the new segment.
20573  assert(org(searchtet) == lpt);
20574  assert(dest(searchtet) == rpt);
20575  sstbond1(rightseg, searchtet);
20576  spintet = searchtet;
20577  while (1) {
20578  tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20579  assert(checkseg.sh == NULL); // FOR DEBUG ONLY
20580  tssbond1(spintet, rightseg);
20581  fnextself(spintet);
20582  if (spintet.tet == searchtet.tet) break;
20583  }
20584  // The Steiner point has been shifted into the volume.
20585  setpointtype(steinerpt, FREEVOLVERTEX);
20586  st_segref_count--;
20587  st_volref_count++;
20588  return 1;
20589  } // if (!checksubfaceflag)
20590  } // if (getedge(...))
20591  } // if (vt == FREESEGVERTEX)
20592  } // if (!removeflag)
20593 
20594  if (!removeflag) {
20595  return 0;
20596  }
20597 
20598  assert(org(searchtet) == steinerpt);
20599 
20600  if (vt == FREESEGVERTEX) {
20601  // Detach the subsegments from their surronding tets.
20602  for (i = 0; i < 2; i++) {
20603  checkseg = (i == 0) ? leftseg : rightseg;
20604  sstpivot1(checkseg, neightet);
20605  spintet = neightet;
20606  while (1) {
20607  tssdissolve1(spintet);
20608  fnextself(spintet);
20609  if (spintet.tet == neightet.tet) break;
20610  }
20611  sstdissolve1(checkseg);
20612  } // i
20613  if (checksubfaceflag) {
20614  // Detach the subfaces at the subsegments from their attached tets.
20615  for (i = 0; i < 2; i++) {
20616  checkseg = (i == 0) ? leftseg : rightseg;
20617  spivot(checkseg, parentsh);
20618  if (parentsh.sh != NULL) {
20619  spinsh = parentsh;
20620  while (1) {
20621  stpivot(spinsh, neightet);
20622  if (neightet.tet != NULL) {
20623  tsdissolve(neightet);
20624  }
20625  sesymself(spinsh);
20626  stpivot(spinsh, neightet);
20627  if (neightet.tet != NULL) {
20628  tsdissolve(neightet);
20629  }
20630  stdissolve(spinsh);
20631  spivotself(spinsh); // Go to the next subface.
20632  if (spinsh.sh == parentsh.sh) break;
20633  }
20634  }
20635  } // i
20636  } // if (checksubfaceflag)
20637  }
20638 
20639  if (loc == INTETRAHEDRON) {
20640  // Collect the four tets containing 'p'.
20641  fliptets = new triface[4];
20642  fliptets[0] = searchtet; // [p,d,a,b]
20643  for (i = 0; i < 2; i++) {
20644  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20645  }
20646  eprev(fliptets[0], fliptets[3]);
20647  fnextself(fliptets[3]); // it is [a,p,b,c]
20648  eprevself(fliptets[3]);
20649  esymself(fliptets[3]); // [a,b,c,p].
20650  // Remove p by a 4-to-1 flip.
20651  //flip41(fliptets, 1, 0, 0);
20652  flip41(fliptets, 1, &fc);
20653  //recenttet = fliptets[0];
20654  } else if (loc == ONFACE) {
20655  // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
20656  // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b].
20657  // Collect the six tets containing 'p'.
20658  fliptets = new triface[6];
20659  fliptets[0] = searchtet; // [p,d,a,b]
20660  for (i = 0; i < 2; i++) {
20661  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20662  }
20663  eprev(fliptets[0], fliptets[3]);
20664  fnextself(fliptets[3]); // [a,p,b,e]
20665  esymself(fliptets[3]); // [p,a,e,b]
20666  eprevself(fliptets[3]); // [e,p,a,b]
20667  for (i = 3; i < 5; i++) {
20668  fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
20669  }
20670  if (vt == FREEFACETVERTEX) {
20671  // We need to determine the location of three subfaces at p.
20672  valence = 0; // Re-use it.
20673  // Check if subfaces are all located in the lower three tets.
20674  // i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
20675  for (i = 3; i < 6; i++) {
20676  if (issubface(fliptets[i])) valence++;
20677  }
20678  if (valence > 0) {
20679  assert(valence == 2);
20680  // We must do 3-to-2 flip in the upper part. We simply re-arrange
20681  // the six tets.
20682  for (i = 0; i < 3; i++) {
20683  esym(fliptets[i+3], wrktets[i]);
20684  esym(fliptets[i], fliptets[i+3]);
20685  fliptets[i] = wrktets[i];
20686  }
20687  // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
20688  wrktets[1] = fliptets[1];
20689  fliptets[1] = fliptets[2];
20690  fliptets[2] = wrktets[1];
20691  wrktets[1] = fliptets[4];
20692  fliptets[4] = fliptets[5];
20693  fliptets[5] = wrktets[1];
20694  }
20695  }
20696  // Remove p by a 6-to-2 flip, which is a combination of two flips:
20697  // a 3-to-2 (deletes the edge [e,p]), and
20698  // a 4-to-1 (deletes the vertex p).
20699  // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
20700  // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is
20701  // degenerate (has zero volume). It will be deleted in the followed
20702  // 4-to-1 flip.
20703  //flip32(&(fliptets[3]), 1, 0, 0);
20704  flip32(&(fliptets[3]), 1, &fc);
20705  // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
20706  // This creates a new tet [a,b,c,d].
20707  //flip41(fliptets, 1, 0, 0);
20708  flip41(fliptets, 1, &fc);
20709  //recenttet = fliptets[0];
20710  } else if (loc == ONEDGE) {
20711  // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
20712  // tets sharing at edge [e,d] originally. We number the link vertices
20713  // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
20714  // Count the number of tets at edge [e,p] and [p,d] (this is n).
20715  n = 0;
20716  spintet = searchtet;
20717  while (1) {
20718  n++;
20719  fnextself(spintet);
20720  if (spintet.tet == searchtet.tet) break;
20721  }
20722  assert(n >= 3);
20723  // Collect the 2n tets containing 'p'.
20724  fliptets = new triface[2 * n];
20725  fliptets[0] = searchtet; // [p,b,p_0,p_1]
20726  for (i = 0; i < (n - 1); i++) {
20727  fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
20728  }
20729  eprev(fliptets[0], fliptets[n]);
20730  fnextself(fliptets[n]); // [p_0,p,p_1,e]
20731  esymself(fliptets[n]); // [p,p_0,e,p_1]
20732  eprevself(fliptets[n]); // [e,p,p_0,p_1]
20733  for (i = n; i < (2 * n - 1); i++) {
20734  fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
20735  }
20736  // Remove p by a 2n-to-n flip, it is a sequence of n flips:
20737  // - Do a 2-to-3 flip on
20738  // [p_0,p_1,p,d] and
20739  // [p,p_1,p_0,e].
20740  // This produces:
20741  // [e,d,p_0,p_1],
20742  // [e,d,p_1,p] (degenerated), and
20743  // [e,d,p,p_0] (degenerated).
20744  wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
20745  eprevself(wrktets[0]); // [p_0,p,d,p_1]
20746  esymself(wrktets[0]); // [p,p_0,p_1,d]
20747  enextself(wrktets[0]); // [p_0,p_1,p,d] [0]
20748  wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
20749  enextself(wrktets[1]); // [p,p_0,e,p_1]
20750  esymself(wrktets[1]); // [p_0,p,p_1,e]
20751  eprevself(wrktets[1]); // [p_1,p_0,p,e] [1]
20752  //flip23(wrktets, 1, 0, 0);
20753  flip23(wrktets, 1, &fc);
20754  // Save the new tet [e,d,p,p_0] (degenerated).
20755  fliptets[n] = wrktets[2];
20756  // Save the new tet [e,d,p_0,p_1].
20757  fliptets[0] = wrktets[0];
20758  // - Repeat from i = 1 to n-2: (n - 2) flips
20759  // - Do a 3-to-2 flip on
20760  // [p,p_i,d,e],
20761  // [p,p_i,e,p_i+1], and
20762  // [p,p_i,p_i+1,d].
20763  // This produces:
20764  // [d,e,p_i+1,p_i], and
20765  // [e,d,p_i+1,p] (degenerated).
20766  for (i = 1; i < (n - 1); i++) {
20767  wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
20768  enextself(wrktets[0]); // [d,p_i,e,p] (...)
20769  esymself(wrktets[0]); // [p_i,d,p,e] (...)
20770  eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0].
20771  wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1]
20772  enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1]
20773  wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
20774  eprevself(wrktets[2]); // [p_i,p,d,p_i+1]
20775  esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2]
20776  //flip32(wrktets, 1, 0, 0);
20777  flip32(wrktets, 1, &fc);
20778  // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY
20779  fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
20780  esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
20781  }
20782  // - Do a 4-to-1 flip on
20783  // [p,p_0,e,d], [d,e,p_0,p],
20784  // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
20785  // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
20786  // [e,d,p_n-1,p].
20787  // This produces
20788  // [e,d,p_n-1,p_0] and
20789  // deletes p.
20790  wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3]
20791  wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
20792  eprevself(wrktets[0]); // [p,e,d,p_0] (...)
20793  esymself(wrktets[0]); // [e,p,p_0,d] (...)
20794  enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0]
20795  wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0]
20796  esymself(wrktets[1]); // [d,p,p_0,p_n-1]
20797  enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1]
20798  wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
20799  enextself(wrktets[2]); // [p_p_n-1,e,p_0]
20800  esymself(wrktets[2]); // [p_n-1,p,p_0,e]
20801  enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2]
20802  //flip41(wrktets, 1, 0, 0);
20803  flip41(wrktets, 1, &fc);
20804  // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY
20805  fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
20806  //recenttet = fliptets[0];
20807  } else {
20808  assert(0); // Unknown location.
20809  } // if (iloc == ...)
20810 
20811  delete [] fliptets;
20812 
20813  if (vt == FREESEGVERTEX) {
20814  // Remove the vertex from the surface mesh.
20815  // This will re-create the segment [lpt, rpt] and re-triangulate
20816  // all the facets at the segment.
20817  // Only do lawson flip when subfaces are not recovery yet.
20818  slawson = (checksubfaceflag ? 0 : 1);
20819  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20820  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20821 
20822  // The original segment is returned in 'rightseg'.
20823  rightseg.shver = 0;
20824  assert(sorg(rightseg) == lpt);
20825  assert(sdest(rightseg) == rpt);
20826 
20827  // Insert the new segment.
20828  point2tetorg(lpt, searchtet);
20829  finddirection(&searchtet, rpt);
20830  assert(dest(searchtet) == rpt);
20831  sstbond1(rightseg, searchtet);
20832  spintet = searchtet;
20833  while (1) {
20834  tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20835  assert(checkseg.sh == NULL); // FOR DEBUG ONLY
20836  tssbond1(spintet, rightseg);
20837  fnextself(spintet);
20838  if (spintet.tet == searchtet.tet) break;
20839  }
20840 
20841  if (checksubfaceflag) {
20842  // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
20843  spivot(rightseg, parentsh);
20844  if (parentsh.sh != NULL) {
20845  spinsh = parentsh;
20846  while (1) {
20847  if (sorg(spinsh) != lpt) {
20848  sesymself(spinsh);
20849  assert(sorg(spinsh) == lpt);
20850  }
20851  assert(sdest(spinsh) == rpt);
20852  apexpt = sapex(spinsh);
20853  // Find the adjacent tet of [lpt,rpt,apexpt];
20854  spintet = searchtet;
20855  while (1) {
20856  if (apex(spintet) == apexpt) {
20857  tsbond(spintet, spinsh);
20858  sesymself(spinsh); // Get to another side of this face.
20859  fsym(spintet, neightet);
20860  tsbond(neightet, spinsh);
20861  sesymself(spinsh); // Get back to the original side.
20862  break;
20863  }
20864  fnextself(spintet);
20865  assert(spintet.tet != searchtet.tet);
20866  //if (spintet.tet == searchtet.tet) break;
20867  }
20868  spivotself(spinsh);
20869  if (spinsh.sh == parentsh.sh) break;
20870  }
20871  }
20872  } // if (checksubfaceflag)
20873 
20874  // Clear the set of new subfaces.
20875  caveshbdlist->restart();
20876  } // if (vt == FREESEGVERTEX)
20877 
20878  // The point has been removed.
20879  if (pointtype(steinerpt) != UNUSEDVERTEX) {
20880  setpointtype(steinerpt, UNUSEDVERTEX);
20881  unuverts++;
20882  }
20883  if (vt != VOLVERTEX) {
20884  // Update the correspinding counters.
20885  if (vt == FREESEGVERTEX) {
20886  st_segref_count--;
20887  } else if (vt == FREEFACETVERTEX) {
20888  st_facref_count--;
20889  } else if (vt == FREEVOLVERTEX) {
20890  st_volref_count--;
20891  }
20892  if (steinerleft > 0) steinerleft++;
20893  }
20894 
20895  return 1;
20896 }
20897 
20899 // //
20900 // suppressbdrysteinerpoint() Suppress a boundary Steiner point //
20901 // //
20903 
20905 {
20906  face parentsh, spinsh, *parysh;
20907  face leftseg, rightseg;
20908  point lpt = NULL, rpt = NULL;
20909  int i;
20910 
20911  verttype vt = pointtype(steinerpt);
20912 
20913  if (vt == FREESEGVERTEX) {
20914  sdecode(point2sh(steinerpt), leftseg);
20915  leftseg.shver = 0;
20916  if (sdest(leftseg) == steinerpt) {
20917  senext(leftseg, rightseg);
20918  spivotself(rightseg);
20919  assert(rightseg.sh != NULL);
20920  rightseg.shver = 0;
20921  assert(sorg(rightseg) == steinerpt);
20922  } else {
20923  assert(sorg(leftseg) == steinerpt);
20924  rightseg = leftseg;
20925  senext2(rightseg, leftseg);
20926  spivotself(leftseg);
20927  assert(leftseg.sh != NULL);
20928  leftseg.shver = 0;
20929  assert(sdest(leftseg) == steinerpt);
20930  }
20931  lpt = sorg(leftseg);
20932  rpt = sdest(rightseg);
20933  if (b->verbose > 2) {
20934  printf(" Suppressing Steiner point %d in segment (%d, %d).\n",
20935  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20936  }
20937  // Get all subfaces at the left segment [lpt, steinerpt].
20938  spivot(leftseg, parentsh);
20939  spinsh = parentsh;
20940  while (1) {
20941  cavesegshlist->newindex((void **) &parysh);
20942  *parysh = spinsh;
20943  // Orient the face consistently.
20944  if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
20945  spivotself(spinsh);
20946  if (spinsh.sh == NULL) break;
20947  if (spinsh.sh == parentsh.sh) break;
20948  }
20949  if (cavesegshlist->objects < 2) {
20950  // It is a single segment. Not handle it yet.
20952  return 0;
20953  }
20954  } else if (vt == FREEFACETVERTEX) {
20955  if (b->verbose > 2) {
20956  printf(" Suppressing Steiner point %d from facet.\n",
20957  pointmark(steinerpt));
20958  }
20959  sdecode(point2sh(steinerpt), parentsh);
20960  // A facet Steiner point. There are exactly two sectors.
20961  for (i = 0; i < 2; i++) {
20962  cavesegshlist->newindex((void **) &parysh);
20963  *parysh = parentsh;
20964  sesymself(parentsh);
20965  }
20966  } else {
20967  return 0;
20968  }
20969 
20970  triface searchtet, neightet, *parytet;
20971  point pa, pb, pc, pd;
20972  REAL v1[3], v2[3], len, u;
20973 
20974  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
20975  REAL ori, minvol, smallvol;
20976  int samplesize;
20977  int it, j, k;
20978 
20979  int n = (int) cavesegshlist->objects;
20980  point *newsteiners = new point[n];
20981  for (i = 0; i < n; i++) newsteiners[i] = NULL;
20982 
20983  // Search for each sector an interior vertex.
20984  for (i = 0; i < cavesegshlist->objects; i++) {
20985  parysh = (face *) fastlookup(cavesegshlist, i);
20986  stpivot(*parysh, searchtet);
20987  // Skip it if it is outside.
20988  if (ishulltet(searchtet)) continue;
20989  // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
20990  // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
20991  // Moreover, subfaces are oriented towards the interior of the ball.
20992  setpoint2tet(steinerpt, encode(searchtet));
20993  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
20994  // Calculate the searching vector.
20995  pa = sorg(*parysh);
20996  pb = sdest(*parysh);
20997  pc = sapex(*parysh);
20998  facenormal(pa, pb, pc, v1, 1, NULL);
20999  len = sqrt(dot(v1, v1));
21000  assert(len > 0.0);
21001  v1[0] /= len;
21002  v1[1] /= len;
21003  v1[2] /= len;
21004  if (vt == FREESEGVERTEX) {
21005  parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
21006  pd = sapex(*parysh);
21007  facenormal(pb, pa, pd, v2, 1, NULL);
21008  len = sqrt(dot(v2, v2));
21009  assert(len > 0.0);
21010  v2[0] /= len;
21011  v2[1] /= len;
21012  v2[2] /= len;
21013  // Average the two vectors.
21014  v1[0] = 0.5 * (v1[0] + v2[0]);
21015  v1[1] = 0.5 * (v1[1] + v2[1]);
21016  v1[2] = 0.5 * (v1[2] + v2[2]);
21017  }
21018  // Search the intersection of the ray starting from 'steinerpt' to
21019  // the search direction 'v1' and the shell of the half-ball.
21020  // - Construct an endpoint.
21021  len = distance(pa, pb);
21022  v2[0] = steinerpt[0] + len * v1[0];
21023  v2[1] = steinerpt[1] + len * v1[1];
21024  v2[2] = steinerpt[2] + len * v1[2];
21025  for (j = 0; j < cavetetlist->objects; j++) {
21026  parytet = (triface *) fastlookup(cavetetlist, j);
21027  pa = org(*parytet);
21028  pb = dest(*parytet);
21029  pc = apex(*parytet);
21030  // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
21031  // is the apex, and three sides are defined by the triangle
21032  // [pa, pb, pc].
21033  ori = orient3d(steinerpt, pa, pb, v2);
21034  if (ori >= 0) {
21035  ori = orient3d(steinerpt, pb, pc, v2);
21036  if (ori >= 0) {
21037  ori = orient3d(steinerpt, pc, pa, v2);
21038  if (ori >= 0) {
21039  // Found! Calculate the intersection.
21040  planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
21041  assert(u != 0.0);
21042  break;
21043  }
21044  }
21045  }
21046  } // j
21047  assert(j < cavetetlist->objects); // There must be an intersection.
21048  // Close the ball by adding the subfaces.
21049  for (j = 0; j < caveshlist->objects; j++) {
21050  parysh = (face *) fastlookup(caveshlist, j);
21051  stpivot(*parysh, neightet);
21052  cavetetlist->newindex((void **) &parytet);
21053  *parytet = neightet;
21054  }
21055  // Search a best point inside the segment [startpt, steinerpt].
21056  it = 0;
21057  samplesize = 100;
21058  v1[0] = steinerpt[0] - startpt[0];
21059  v1[1] = steinerpt[1] - startpt[1];
21060  v1[2] = steinerpt[2] - startpt[2];
21061  minvol = -1.0;
21062  while (it < 3) {
21063  for (j = 1; j < samplesize - 1; j++) {
21064  samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
21065  samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
21066  samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
21067  // Find the minimum volume for 'samplept'.
21068  smallvol = -1;
21069  for (k = 0; k < cavetetlist->objects; k++) {
21070  parytet = (triface *) fastlookup(cavetetlist, k);
21071  pa = org(*parytet);
21072  pb = dest(*parytet);
21073  pc = apex(*parytet);
21074  ori = orient3d(pb, pa, pc, samplept);
21075  if (ori <= 0) {
21076  break; // An invalid tet.
21077  }
21078  if (smallvol == -1) {
21079  smallvol = ori;
21080  } else {
21081  if (ori < smallvol) smallvol = ori;
21082  }
21083  } // k
21084  if (k == cavetetlist->objects) {
21085  // Found a valid point. Remember it.
21086  if (minvol == -1.0) {
21087  candpt[0] = samplept[0];
21088  candpt[1] = samplept[1];
21089  candpt[2] = samplept[2];
21090  minvol = smallvol;
21091  } else {
21092  if (minvol < smallvol) {
21093  // It is a better location. Remember it.
21094  candpt[0] = samplept[0];
21095  candpt[1] = samplept[1];
21096  candpt[2] = samplept[2];
21097  minvol = smallvol;
21098  } else {
21099  // No improvement of smallest volume.
21100  // Since we are searching along the line [startpt, steinerpy],
21101  // The smallest volume can only be decreased later.
21102  break;
21103  }
21104  }
21105  }
21106  } // j
21107  if (minvol > 0) break;
21108  samplesize *= 10;
21109  it++;
21110  } // while (it < 3)
21111  if (minvol == -1.0) {
21112  // Failed to find a valid point.
21113  cavetetlist->restart();
21114  caveshlist->restart();
21115  break;
21116  }
21117  // Create a new Steiner point inside this section.
21118  makepoint(&(newsteiners[i]), FREEVOLVERTEX);
21119  newsteiners[i][0] = candpt[0];
21120  newsteiners[i][1] = candpt[1];
21121  newsteiners[i][2] = candpt[2];
21122  cavetetlist->restart();
21123  caveshlist->restart();
21124  } // i
21125 
21126  if (i < cavesegshlist->objects) {
21127  // Failed to suppress the vertex.
21128  for (; i > 0; i--) {
21129  if (newsteiners[i - 1] != NULL) {
21130  pointdealloc(newsteiners[i - 1]);
21131  }
21132  }
21133  delete [] newsteiners;
21135  return 0;
21136  }
21137 
21138  // Remove p from the segment or the facet.
21139  triface newtet, newface, spintet;
21140  face newsh, neighsh;
21141  face *splitseg, checkseg;
21142  int slawson = 0; // Do not do flip afterword.
21143  int t1ver;
21144 
21145  if (vt == FREESEGVERTEX) {
21146  // Detach 'leftseg' and 'rightseg' from their adjacent tets.
21147  // These two subsegments will be deleted.
21148  sstpivot1(leftseg, neightet);
21149  spintet = neightet;
21150  while (1) {
21151  tssdissolve1(spintet);
21152  fnextself(spintet);
21153  if (spintet.tet == neightet.tet) break;
21154  }
21155  sstpivot1(rightseg, neightet);
21156  spintet = neightet;
21157  while (1) {
21158  tssdissolve1(spintet);
21159  fnextself(spintet);
21160  if (spintet.tet == neightet.tet) break;
21161  }
21162  }
21163 
21164  // Loop through all sectors bounded by facets at this segment.
21165  // Within each sector, create a new Steiner point 'np', and replace 'p'
21166  // by 'np' for all tets in this sector.
21167  for (i = 0; i < cavesegshlist->objects; i++) {
21168  parysh = (face *) fastlookup(cavesegshlist, i);
21169  // 'parysh' is the face [lpt, steinerpt, #].
21170  stpivot(*parysh, neightet);
21171  // Get all tets in this sector.
21172  setpoint2tet(steinerpt, encode(neightet));
21173  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21174  if (!ishulltet(neightet)) {
21175  // Within each tet in the ball, replace 'p' by 'np'.
21176  for (j = 0; j < cavetetlist->objects; j++) {
21177  parytet = (triface *) fastlookup(cavetetlist, j);
21178  setoppo(*parytet, newsteiners[i]);
21179  } // j
21180  // Point to a parent tet.
21181  parytet = (triface *) fastlookup(cavetetlist, 0);
21182  setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
21183  st_volref_count++;
21184  if (steinerleft > 0) steinerleft--;
21185  }
21186  // Disconnect the set of boundary faces. They're temporarily open faces.
21187  // They will be connected to the new tets after 'p' is removed.
21188  for (j = 0; j < caveshlist->objects; j++) {
21189  // Get a boundary face.
21190  parysh = (face *) fastlookup(caveshlist, j);
21191  stpivot(*parysh, neightet);
21192  //assert(apex(neightet) == newpt);
21193  // Clear the connection at this face.
21194  dissolve(neightet);
21195  tsdissolve(neightet);
21196  }
21197  // Clear the working lists.
21198  cavetetlist->restart();
21199  caveshlist->restart();
21200  } // i
21202 
21203  if (vt == FREESEGVERTEX) {
21204  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21205  splitseg = &rightseg;
21206  } else {
21207  if (sdest(parentsh) == steinerpt) {
21208  senextself(parentsh);
21209  } else if (sapex(parentsh) == steinerpt) {
21210  senext2self(parentsh);
21211  }
21212  assert(sorg(parentsh) == steinerpt);
21213  splitseg = NULL;
21214  }
21215  sremovevertex(steinerpt, &parentsh, splitseg, slawson);
21216 
21217  if (vt == FREESEGVERTEX) {
21218  // The original segment is returned in 'rightseg'.
21219  rightseg.shver = 0;
21220  }
21221 
21222  // For each new subface, create two new tets at each side of it.
21223  // Both of the two new tets have its opposite be dummypoint.
21224  for (i = 0; i < caveshbdlist->objects; i++) {
21225  parysh = (face *) fastlookup(caveshbdlist, i);
21226  sinfect(*parysh); // Mark it for connecting new tets.
21227  newsh = *parysh;
21228  pa = sorg(newsh);
21229  pb = sdest(newsh);
21230  pc = sapex(newsh);
21231  maketetrahedron(&newtet);
21232  maketetrahedron(&neightet);
21233  setvertices(newtet, pa, pb, pc, dummypoint);
21234  setvertices(neightet, pb, pa, pc, dummypoint);
21235  bond(newtet, neightet);
21236  tsbond(newtet, newsh);
21237  sesymself(newsh);
21238  tsbond(neightet, newsh);
21239  }
21240  // Temporarily increase the hullsize.
21241  hullsize += (caveshbdlist->objects * 2l);
21242 
21243  if (vt == FREESEGVERTEX) {
21244  // Connecting new tets at the recovered segment.
21245  spivot(rightseg, parentsh);
21246  assert(parentsh.sh != NULL);
21247  spinsh = parentsh;
21248  while (1) {
21249  if (sorg(spinsh) != lpt) sesymself(spinsh);
21250  // Get the new tet at this subface.
21251  stpivot(spinsh, newtet);
21252  tssbond1(newtet, rightseg);
21253  // Go to the other face at this segment.
21254  spivot(spinsh, neighsh);
21255  if (sorg(neighsh) != lpt) sesymself(neighsh);
21256  sesymself(neighsh);
21257  stpivot(neighsh, neightet);
21258  tssbond1(neightet, rightseg);
21259  sstbond1(rightseg, neightet);
21260  // Connecting two adjacent tets at this segment.
21261  esymself(newtet);
21262  esymself(neightet);
21263  // Connect the two tets (at rightseg) together.
21264  bond(newtet, neightet);
21265  // Go to the next subface.
21266  spivotself(spinsh);
21267  if (spinsh.sh == parentsh.sh) break;
21268  }
21269  }
21270 
21271  // Connecting new tets at new subfaces together.
21272  for (i = 0; i < caveshbdlist->objects; i++) {
21273  parysh = (face *) fastlookup(caveshbdlist, i);
21274  newsh = *parysh;
21275  //assert(sinfected(newsh));
21276  // Each new subface contains two new tets.
21277  for (k = 0; k < 2; k++) {
21278  stpivot(newsh, newtet);
21279  for (j = 0; j < 3; j++) {
21280  // Check if this side is open.
21281  esym(newtet, newface);
21282  if (newface.tet[newface.ver & 3] == NULL) {
21283  // An open face. Connect it to its adjacent tet.
21284  sspivot(newsh, checkseg);
21285  if (checkseg.sh != NULL) {
21286  // A segment. It must not be the recovered segment.
21287  tssbond1(newtet, checkseg);
21288  sstbond1(checkseg, newtet);
21289  }
21290  spivot(newsh, neighsh);
21291  if (neighsh.sh != NULL) {
21292  // The adjacent subface exists. It's not a dangling segment.
21293  if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
21294  stpivot(neighsh, neightet);
21295  if (sinfected(neighsh)) {
21296  esymself(neightet);
21297  assert(neightet.tet[neightet.ver & 3] == NULL);
21298  } else {
21299  // Search for an open face at this edge.
21300  spintet = neightet;
21301  while (1) {
21302  esym(spintet, searchtet);
21303  fsym(searchtet, spintet);
21304  if (spintet.tet == NULL) break;
21305  assert(spintet.tet != neightet.tet);
21306  }
21307  // Found an open face at 'searchtet'.
21308  neightet = searchtet;
21309  }
21310  } else {
21311  // The edge (at 'newsh') is a dangling segment.
21312  assert(checkseg.sh != NULL);
21313  // Get an adjacent tet at this segment.
21314  sstpivot1(checkseg, neightet);
21315  assert(!isdeadtet(neightet));
21316  if (org(neightet) != sdest(newsh)) esymself(neightet);
21317  assert((org(neightet) == sdest(newsh)) &&
21318  (dest(neightet) == sorg(newsh)));
21319  // Search for an open face at this edge.
21320  spintet = neightet;
21321  while (1) {
21322  esym(spintet, searchtet);
21323  fsym(searchtet, spintet);
21324  if (spintet.tet == NULL) break;
21325  assert(spintet.tet != neightet.tet);
21326  }
21327  // Found an open face at 'searchtet'.
21328  neightet = searchtet;
21329  }
21330  pc = apex(newface);
21331  if (apex(neightet) == steinerpt) {
21332  // Exterior case. The 'neightet' is a hull tet which contain
21333  // 'steinerpt'. It will be deleted after 'steinerpt' is removed.
21334  assert(pc == dummypoint);
21335  caveoldtetlist->newindex((void **) &parytet);
21336  *parytet = neightet;
21337  // Connect newface to the adjacent hull tet of 'neightet', which
21338  // has the same edge as 'newface', and does not has 'steinerpt'.
21339  fnextself(neightet);
21340  } else {
21341  if (pc == dummypoint) {
21342  if (apex(neightet) != dummypoint) {
21343  setapex(newface, apex(neightet));
21344  // A hull tet has turned into an interior tet.
21345  hullsize--; // Must update the hullsize.
21346  }
21347  }
21348  }
21349  bond(newface, neightet);
21350  } // if (newface.tet[newface.ver & 3] == NULL)
21351  enextself(newtet);
21352  senextself(newsh);
21353  } // j
21354  sesymself(newsh);
21355  } // k
21356  } // i
21357 
21358  // Unmark all new subfaces.
21359  for (i = 0; i < caveshbdlist->objects; i++) {
21360  parysh = (face *) fastlookup(caveshbdlist, i);
21361  suninfect(*parysh);
21362  }
21363  caveshbdlist->restart();
21364 
21365  if (caveoldtetlist->objects > 0l) {
21366  // Delete hull tets which contain 'steinerpt'.
21367  for (i = 0; i < caveoldtetlist->objects; i++) {
21368  parytet = (triface *) fastlookup(caveoldtetlist, i);
21369  tetrahedrondealloc(parytet->tet);
21370  }
21371  // Must update the hullsize.
21374  }
21375 
21376  setpointtype(steinerpt, UNUSEDVERTEX);
21377  unuverts++;
21378  if (vt == FREESEGVERTEX) {
21379  st_segref_count--;
21380  } else { // vt == FREEFACETVERTEX
21381  st_facref_count--;
21382  }
21383  if (steinerleft > 0) steinerleft++; // We've removed a Steiner points.
21384 
21385 
21386  point *parypt;
21387  int steinercount = 0;
21388 
21389  int bak_fliplinklevel = b->fliplinklevel;
21390  b->fliplinklevel = 100000; // Unlimited flip level.
21391 
21392  // Try to remove newly added Steiner points.
21393  for (i = 0; i < n; i++) {
21394  if (newsteiners[i] != NULL) {
21395  if (!removevertexbyflips(newsteiners[i])) {
21396  if (b->nobisect_param > 0) { // Not -Y0
21397  // Save it in subvertstack for removal.
21398  subvertstack->newindex((void **) &parypt);
21399  *parypt = newsteiners[i];
21400  }
21401  steinercount++;
21402  }
21403  }
21404  }
21405 
21406  b->fliplinklevel = bak_fliplinklevel;
21407 
21408  if (steinercount > 0) {
21409  if (b->verbose > 2) {
21410  printf(" Added %d interior Steiner points.\n", steinercount);
21411  }
21412  }
21413 
21414  delete [] newsteiners;
21415 
21416  return 1;
21417 }
21418 
21419 
21421 // //
21422 // suppresssteinerpoints() Suppress Steiner points. //
21423 // //
21424 // All Steiner points have been saved in 'subvertstack' in the routines //
21425 // carveholes() and suppresssteinerpoint(). //
21426 // Each Steiner point is either removed or shifted into the interior. //
21427 // //
21429 
21431 {
21432 
21433  if (!b->quiet) {
21434  printf("Suppressing Steiner points ...\n");
21435  }
21436 
21437  point rempt, *parypt;
21438 
21439  int bak_fliplinklevel = b->fliplinklevel;
21440  b->fliplinklevel = 100000; // Unlimited flip level.
21441  int suppcount = 0, remcount = 0;
21442  int i;
21443 
21444  // Try to suppress boundary Steiner points.
21445  for (i = 0; i < subvertstack->objects; i++) {
21446  parypt = (point *) fastlookup(subvertstack, i);
21447  rempt = *parypt;
21448  if (pointtype(rempt) != UNUSEDVERTEX) {
21449  if ((pointtype(rempt) == FREESEGVERTEX) ||
21450  (pointtype(rempt) == FREEFACETVERTEX)) {
21451  if (suppressbdrysteinerpoint(rempt)) {
21452  suppcount++;
21453  }
21454  }
21455  }
21456  } // i
21457 
21458  if (suppcount > 0) {
21459  if (b->verbose) {
21460  printf(" Suppressed %d boundary Steiner points.\n", suppcount);
21461  }
21462  }
21463 
21464  if (b->nobisect_param > 0) { // -Y1
21465  for (i = 0; i < subvertstack->objects; i++) {
21466  parypt = (point *) fastlookup(subvertstack, i);
21467  rempt = *parypt;
21468  if (pointtype(rempt) != UNUSEDVERTEX) {
21469  if (pointtype(rempt) == FREEVOLVERTEX) {
21470  if (removevertexbyflips(rempt)) {
21471  remcount++;
21472  }
21473  }
21474  }
21475  }
21476  }
21477 
21478  if (remcount > 0) {
21479  if (b->verbose) {
21480  printf(" Removed %d interior Steiner points.\n", remcount);
21481  }
21482  }
21483 
21484  b->fliplinklevel = bak_fliplinklevel;
21485 
21486  if (b->nobisect_param > 1) { // -Y2
21487  // Smooth interior Steiner points.
21488  optparameters opm;
21489  triface *parytet;
21490  point *ppt;
21491  REAL ori;
21492  int smtcount, count, ivcount;
21493  int nt, j;
21494 
21495  // Point smooth options.
21496  opm.max_min_volume = 1;
21497  opm.numofsearchdirs = 20;
21498  opm.searchstep = 0.001;
21499  opm.maxiter = 30; // Limit the maximum iterations.
21500 
21501  smtcount = 0;
21502 
21503  do {
21504 
21505  nt = 0;
21506 
21507  while (1) {
21508  count = 0;
21509  ivcount = 0; // Clear the inverted count.
21510 
21511  for (i = 0; i < subvertstack->objects; i++) {
21512  parypt = (point *) fastlookup(subvertstack, i);
21513  rempt = *parypt;
21514  if (pointtype(rempt) == FREEVOLVERTEX) {
21515  getvertexstar(1, rempt, cavetetlist, NULL, NULL);
21516  // Calculate the initial smallest volume (maybe zero or negative).
21517  for (j = 0; j < cavetetlist->objects; j++) {
21518  parytet = (triface *) fastlookup(cavetetlist, j);
21519  ppt = (point *) &(parytet->tet[4]);
21520  ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
21521  if (j == 0) {
21522  opm.initval = ori;
21523  } else {
21524  if (opm.initval > ori) opm.initval = ori;
21525  }
21526  }
21527  if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
21528  count++;
21529  }
21530  if (opm.imprval <= 0.0) {
21531  ivcount++; // The mesh contains inverted elements.
21532  }
21533  cavetetlist->restart();
21534  }
21535  } // i
21536 
21537  smtcount += count;
21538 
21539  if (count == 0) {
21540  // No point has been smoothed.
21541  break;
21542  }
21543 
21544  nt++;
21545  if (nt > 2) {
21546  break; // Already three iterations.
21547  }
21548  } // while
21549 
21550  if (ivcount > 0) {
21551  // There are inverted elements!
21552  if (opm.maxiter > 0) {
21553  // Set unlimited smoothing steps. Try again.
21554  opm.numofsearchdirs = 30;
21555  opm.searchstep = 0.0001;
21556  opm.maxiter = -1;
21557  continue;
21558  }
21559  }
21560 
21561  break;
21562  } while (1); // Additional loop for (ivcount > 0)
21563 
21564  if (ivcount > 0) {
21565  printf("BUG Report! The mesh contain inverted elements.\n");
21566  }
21567 
21568  if (b->verbose) {
21569  if (smtcount > 0) {
21570  printf(" Smoothed %d Steiner points.\n", smtcount);
21571  }
21572  }
21573  } // -Y2
21574 
21575  subvertstack->restart();
21576 
21577  return 1;
21578 }
21579 
21581 // //
21582 // recoverboundary() Recover segments and facets. //
21583 // //
21585 
21587 {
21588  arraypool *misseglist, *misshlist;
21589  arraypool *bdrysteinerptlist;
21590  face searchsh, *parysh;
21591  face searchseg, *paryseg;
21592  point rempt, *parypt;
21593  long ms; // The number of missing segments/subfaces.
21594  int nit; // The number of iterations.
21595  int s, i;
21596 
21597  // Counters.
21598  long bak_segref_count, bak_facref_count, bak_volref_count;
21599 
21600  if (!b->quiet) {
21601  printf("Recovering boundaries...\n");
21602  }
21603 
21604 
21605  if (b->verbose) {
21606  printf(" Recovering segments.\n");
21607  }
21608 
21609  // Segments will be introduced.
21610  checksubsegflag = 1;
21611 
21612  misseglist = new arraypool(sizeof(face), 8);
21613  bdrysteinerptlist = new arraypool(sizeof(point), 8);
21614 
21615  // In random order.
21617  for (i = 0; i < subsegs->items; i++) {
21618  s = randomnation(i + 1);
21619  // Move the s-th seg to the i-th.
21620  subsegstack->newindex((void **) &paryseg);
21621  *paryseg = * (face *) fastlookup(subsegstack, s);
21622  // Put i-th seg to be the s-th.
21623  searchseg.sh = shellfacetraverse(subsegs);
21624  paryseg = (face *) fastlookup(subsegstack, s);
21625  *paryseg = searchseg;
21626  }
21627 
21628  // The init number of missing segments.
21629  ms = subsegs->items;
21630  nit = 0;
21631  if (b->fliplinklevel < 0) {
21632  autofliplinklevel = 1; // Init value.
21633  }
21634 
21635  // First, trying to recover segments by only doing flips.
21636 #if 1
21637  while (1) {
21638  recoversegments(misseglist, 0, 0);
21639 
21640  if (misseglist->objects > 0) {
21641  if (b->fliplinklevel >= 0) {
21642  break;
21643  } else {
21644  if (misseglist->objects >= ms) {
21645  nit++;
21646  if (nit >= 3) {
21647  //break;
21648  // Do the last round with unbounded flip link level.
21649  b->fliplinklevel = 100000;
21650  }
21651  } else {
21652  ms = misseglist->objects;
21653  if (nit > 0) {
21654  nit--;
21655  }
21656  }
21657  for (i = 0; i < misseglist->objects; i++) {
21658  subsegstack->newindex((void **) &paryseg);
21659  *paryseg = * (face *) fastlookup(misseglist, i);
21660  }
21661  misseglist->restart();
21663  }
21664  } else {
21665  // All segments are recovered.
21666  break;
21667  }
21668  } // while (1)
21669 #endif
21670 
21671 #if 1
21672  if (b->verbose) {
21673  printf(" %ld (%ld) segments are recovered (missing).\n",
21674  subsegs->items - misseglist->objects, misseglist->objects);
21675  }
21676 
21677  if (misseglist->objects > 0) {
21678  // Second, trying to recover segments by doing more flips (fullsearch).
21679  while (misseglist->objects > 0) {
21680  ms = misseglist->objects;
21681  for (i = 0; i < misseglist->objects; i++) {
21682  subsegstack->newindex((void **) &paryseg);
21683  *paryseg = * (face *) fastlookup(misseglist, i);
21684  }
21685  misseglist->restart();
21686 
21687  recoversegments(misseglist, 1, 0);
21688 
21689  if (misseglist->objects < ms) {
21690  // The number of missing segments is reduced.
21691  continue;
21692  } else {
21693  break;
21694  }
21695  }
21696  if (b->verbose) {
21697  printf(" %ld (%ld) segments are recovered (missing).\n",
21698  subsegs->items - misseglist->objects, misseglist->objects);
21699  }
21700  }
21701 
21702  if (misseglist->objects > 0) {
21703  // Third, trying to recover segments by doing more flips (fullsearch)
21704  // and adding Steiner points in the volume.
21705  while (misseglist->objects > 0) {
21706  ms = misseglist->objects;
21707  for (i = 0; i < misseglist->objects; i++) {
21708  subsegstack->newindex((void **) &paryseg);
21709  *paryseg = * (face *) fastlookup(misseglist, i);
21710  }
21711  misseglist->restart();
21712 
21713  recoversegments(misseglist, 1, 1);
21714 
21715  if (misseglist->objects < ms) {
21716  // The number of missing segments is reduced.
21717  continue;
21718  } else {
21719  break;
21720  }
21721  }
21722  if (b->verbose) {
21723  printf(" Added %ld Steiner points in volume.\n", st_volref_count);
21724  }
21725  }
21726 
21727  if (misseglist->objects > 0) {
21728  // Last, trying to recover segments by doing more flips (fullsearch),
21729  // and adding Steiner points in the volume, and splitting segments.
21730  long bak_inpoly_count = st_volref_count; //st_inpoly_count;
21731  for (i = 0; i < misseglist->objects; i++) {
21732  subsegstack->newindex((void **) &paryseg);
21733  *paryseg = * (face *) fastlookup(misseglist, i);
21734  }
21735  misseglist->restart();
21736 
21737  recoversegments(misseglist, 1, 2);
21738 
21739  if (b->verbose) {
21740  printf(" Added %ld Steiner points in segments.\n", st_segref_count);
21741  if (st_volref_count > bak_inpoly_count) {
21742  printf(" Added another %ld Steiner points in volume.\n",
21743  st_volref_count - bak_inpoly_count);
21744  }
21745  }
21746  assert(misseglist->objects == 0l);
21747  }
21748 
21749 
21750  if (st_segref_count > 0) {
21751  // Try to remove the Steiner points added in segments.
21752  bak_segref_count = st_segref_count;
21753  bak_volref_count = st_volref_count;
21754  for (i = 0; i < subvertstack->objects; i++) {
21755  // Get the Steiner point.
21756  parypt = (point *) fastlookup(subvertstack, i);
21757  rempt = *parypt;
21758  if (!removevertexbyflips(rempt)) {
21759  // Save it in list.
21760  bdrysteinerptlist->newindex((void **) &parypt);
21761  *parypt = rempt;
21762  }
21763  }
21764  if (b->verbose) {
21765  if (st_segref_count < bak_segref_count) {
21766  if (bak_volref_count < st_volref_count) {
21767  printf(" Suppressed %ld Steiner points in segments.\n",
21768  st_volref_count - bak_volref_count);
21769  }
21770  if ((st_segref_count + (st_volref_count - bak_volref_count)) <
21771  bak_segref_count) {
21772  printf(" Removed %ld Steiner points in segments.\n",
21773  bak_segref_count -
21774  (st_segref_count + (st_volref_count - bak_volref_count)));
21775  }
21776  }
21777  }
21778  subvertstack->restart();
21779  }
21780 
21781 
21782  tv = clock();
21783 
21784  if (b->verbose) {
21785  printf(" Recovering facets.\n");
21786  }
21787 
21788  // Subfaces will be introduced.
21789  checksubfaceflag = 1;
21790 
21791  misshlist = new arraypool(sizeof(face), 8);
21792 
21793  // Randomly order the subfaces.
21795  for (i = 0; i < subfaces->items; i++) {
21796  s = randomnation(i + 1);
21797  // Move the s-th subface to the i-th.
21798  subfacstack->newindex((void **) &parysh);
21799  *parysh = * (face *) fastlookup(subfacstack, s);
21800  // Put i-th subface to be the s-th.
21801  searchsh.sh = shellfacetraverse(subfaces);
21802  parysh = (face *) fastlookup(subfacstack, s);
21803  *parysh = searchsh;
21804  }
21805 
21806  ms = subfaces->items;
21807  nit = 0;
21808  b->fliplinklevel = -1; // Init.
21809  if (b->fliplinklevel < 0) {
21810  autofliplinklevel = 1; // Init value.
21811  }
21812 
21813  while (1) {
21814  recoversubfaces(misshlist, 0);
21815 
21816  if (misshlist->objects > 0) {
21817  if (b->fliplinklevel >= 0) {
21818  break;
21819  } else {
21820  if (misshlist->objects >= ms) {
21821  nit++;
21822  if (nit >= 3) {
21823  //break;
21824  // Do the last round with unbounded flip link level.
21825  b->fliplinklevel = 100000;
21826  }
21827  } else {
21828  ms = misshlist->objects;
21829  if (nit > 0) {
21830  nit--;
21831  }
21832  }
21833  for (i = 0; i < misshlist->objects; i++) {
21834  subfacstack->newindex((void **) &parysh);
21835  *parysh = * (face *) fastlookup(misshlist, i);
21836  }
21837  misshlist->restart();
21839  }
21840  } else {
21841  // All subfaces are recovered.
21842  break;
21843  }
21844  } // while (1)
21845 
21846  if (b->verbose) {
21847  printf(" %ld (%ld) subfaces are recovered (missing).\n",
21848  subfaces->items - misshlist->objects, misshlist->objects);
21849  }
21850 
21851  if (misshlist->objects > 0) {
21852  // There are missing subfaces. Add Steiner points.
21853  for (i = 0; i < misshlist->objects; i++) {
21854  subfacstack->newindex((void **) &parysh);
21855  *parysh = * (face *) fastlookup(misshlist, i);
21856  }
21857  misshlist->restart();
21858 
21859  recoversubfaces(NULL, 1);
21860 
21861  if (b->verbose) {
21862  printf(" Added %ld Steiner points in facets.\n", st_facref_count);
21863  }
21864  }
21865 
21866 
21867  if (st_facref_count > 0) {
21868  // Try to remove the Steiner points added in facets.
21869  bak_facref_count = st_facref_count;
21870  for (i = 0; i < subvertstack->objects; i++) {
21871  // Get the Steiner point.
21872  parypt = (point *) fastlookup(subvertstack, i);
21873  rempt = *parypt;
21874  if (!removevertexbyflips(*parypt)) {
21875  // Save it in list.
21876  bdrysteinerptlist->newindex((void **) &parypt);
21877  *parypt = rempt;
21878  }
21879  }
21880  if (b->verbose) {
21881  if (st_facref_count < bak_facref_count) {
21882  printf(" Removed %ld Steiner points in facets.\n",
21883  bak_facref_count - st_facref_count);
21884  }
21885  }
21886  subvertstack->restart();
21887  }
21888 
21889 
21890  if (bdrysteinerptlist->objects > 0) {
21891  if (b->verbose) {
21892  printf(" %ld Steiner points remained in boundary.\n",
21893  bdrysteinerptlist->objects);
21894  }
21895  } // if
21896 
21897 
21898  // Accumulate the dynamic memory.
21899  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
21900  bdrysteinerptlist->totalmemory);
21901 
21902  delete bdrysteinerptlist;
21903  delete misseglist;
21904  delete misshlist;
21905 #endif
21906 }
21907 
21911 
21912 
21916 
21918 // //
21919 // carveholes() Remove tetrahedra not in the mesh domain. //
21920 // //
21922 
21923 
21925 {
21926  arraypool *tetarray, *hullarray;
21927  triface tetloop, neightet, *parytet, *parytet1;
21928  triface *regiontets = NULL;
21929  face checksh, *parysh;
21930  face checkseg;
21931  point ptloop, *parypt;
21932  int t1ver;
21933  int i, j, k;
21934 
21935  if (!b->quiet) {
21936  if (b->convex) {
21937  printf("Marking exterior tetrahedra ...\n");
21938  } else {
21939  printf("Removing exterior tetrahedra ...\n");
21940  }
21941  }
21942 
21943  // Initialize the pool of exterior tets.
21944  tetarray = new arraypool(sizeof(triface), 10);
21945  hullarray = new arraypool(sizeof(triface), 10);
21946 
21947  // Collect unprotected tets and hull tets.
21949  tetloop.ver = 11; // The face opposite to dummypoint.
21950  tetloop.tet = alltetrahedrontraverse();
21951  while (tetloop.tet != (tetrahedron *) NULL) {
21952  if (ishulltet(tetloop)) {
21953  // Is this side protected by a subface?
21954  if (!issubface(tetloop)) {
21955  // Collect an unprotected hull tet and tet.
21956  infect(tetloop);
21957  hullarray->newindex((void **) &parytet);
21958  *parytet = tetloop;
21959  // tetloop's face number is 11 & 3 = 3.
21960  decode(tetloop.tet[3], neightet);
21961  if (!infected(neightet)) {
21962  infect(neightet);
21963  tetarray->newindex((void **) &parytet);
21964  *parytet = neightet;
21965  }
21966  }
21967  }
21968  tetloop.tet = alltetrahedrontraverse();
21969  }
21970 
21971  if (in->numberofholes > 0) {
21972  // Mark as infected any tets inside volume holes.
21973  for (i = 0; i < 3 * in->numberofholes; i += 3) {
21974  // Search a tet containing the i-th hole point.
21975  neightet.tet = NULL;
21976  randomsample(&(in->holelist[i]), &neightet);
21977  if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
21978  // The tet 'neightet' contain this point.
21979  if (!infected(neightet)) {
21980  infect(neightet);
21981  tetarray->newindex((void **) &parytet);
21982  *parytet = neightet;
21983  // Add its adjacent tet if it is not protected.
21984  if (!issubface(neightet)) {
21985  decode(neightet.tet[neightet.ver & 3], tetloop);
21986  if (!infected(tetloop)) {
21987  infect(tetloop);
21988  if (ishulltet(tetloop)) {
21989  hullarray->newindex((void **) &parytet);
21990  } else {
21991  tetarray->newindex((void **) &parytet);
21992  }
21993  *parytet = tetloop;
21994  }
21995  }
21996  else {
21997  // It is protected. Check if its adjacent tet is a hull tet.
21998  decode(neightet.tet[neightet.ver & 3], tetloop);
21999  if (ishulltet(tetloop)) {
22000  // It is hull tet, add it into the list. Moreover, the subface
22001  // is dead, i.e., both sides are in exterior.
22002  if (!infected(tetloop)) {
22003  infect(tetloop);
22004  hullarray->newindex((void **) &parytet);
22005  *parytet = tetloop;
22006  }
22007  }
22008  if (infected(tetloop)) {
22009  // Both sides of this subface are in exterior.
22010  tspivot(neightet, checksh);
22011  sinfect(checksh); // Only queue it once.
22012  subfacstack->newindex((void **) &parysh);
22013  *parysh = checksh;
22014  }
22015  }
22016  } // if (!infected(neightet))
22017  } else {
22018  // A hole point locates outside of the convex hull.
22019  if (!b->quiet) {
22020  printf("Warning: The %d-th hole point ", i/3 + 1);
22021  printf("lies outside the convex hull.\n");
22022  }
22023  }
22024  } // i
22025  } // if (in->numberofholes > 0)
22026 
22027  if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
22028  // Record the tetrahedra that contains the region points for assigning
22029  // region attributes after the holes have been carved.
22030  regiontets = new triface[in->numberofregions];
22031  // Mark as marktested any tetrahedra inside volume regions.
22032  for (i = 0; i < 5 * in->numberofregions; i += 5) {
22033  // Search a tet containing the i-th region point.
22034  neightet.tet = NULL;
22035  randomsample(&(in->regionlist[i]), &neightet);
22036  if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
22037  regiontets[i/5] = neightet;
22038  } else {
22039  if (!b->quiet) {
22040  printf("Warning: The %d-th region point ", i/5+1);
22041  printf("lies outside the convex hull.\n");
22042  }
22043  regiontets[i/5].tet = NULL;
22044  }
22045  }
22046  }
22047 
22048  // Collect all exterior tets (in concave place and in holes).
22049  for (i = 0; i < tetarray->objects; i++) {
22050  parytet = (triface *) fastlookup(tetarray, i);
22051  j = (parytet->ver & 3); // j is the current face number.
22052  // Check the other three adjacent tets.
22053  for (k = 1; k < 4; k++) {
22054  decode(parytet->tet[(j + k) % 4], neightet);
22055  // neightet may be a hull tet.
22056  if (!infected(neightet)) {
22057  // Is neightet protected by a subface.
22058  if (!issubface(neightet)) {
22059  // Not proected. Collect it. (It must not be a hull tet).
22060  infect(neightet);
22061  tetarray->newindex((void **) &parytet1);
22062  *parytet1 = neightet;
22063  } else {
22064  // Protected. Check if it is a hull tet.
22065  if (ishulltet(neightet)) {
22066  // A hull tet. Collect it.
22067  infect(neightet);
22068  hullarray->newindex((void **) &parytet1);
22069  *parytet1 = neightet;
22070  // Both sides of this subface are exterior.
22071  tspivot(neightet, checksh);
22072  // Queue this subface (to be deleted later).
22073  assert(!sinfected(checksh));
22074  sinfect(checksh); // Only queue it once.
22075  subfacstack->newindex((void **) &parysh);
22076  *parysh = checksh;
22077  }
22078  }
22079  } else {
22080  // Both sides of this face are in exterior.
22081  // If there is a subface. It should be collected.
22082  if (issubface(neightet)) {
22083  tspivot(neightet, checksh);
22084  if (!sinfected(checksh)) {
22085  sinfect(checksh);
22086  subfacstack->newindex((void **) &parysh);
22087  *parysh = checksh;
22088  }
22089  }
22090  }
22091  } // j, k
22092  } // i
22093 
22094  if (b->regionattrib && (in->numberofregions > 0)) {
22095  // Re-check saved region tets to see if they lie outside.
22096  for (i = 0; i < in->numberofregions; i++) {
22097  if (infected(regiontets[i])) {
22098  if (b->verbose) {
22099  printf("Warning: The %d-th region point ", i+1);
22100  printf("lies in the exterior of the domain.\n");
22101  }
22102  regiontets[i].tet = NULL;
22103  }
22104  }
22105  }
22106 
22107  // Collect vertices which point to infected tets. These vertices
22108  // may get deleted after the removal of exterior tets.
22109  // If -Y1 option is used, collect all Steiner points for removal.
22110  // The lists 'cavetetvertlist' and 'subvertstack' are re-used.
22111  points->traversalinit();
22112  ptloop = pointtraverse();
22113  while (ptloop != NULL) {
22114  if ((pointtype(ptloop) != UNUSEDVERTEX) &&
22115  (pointtype(ptloop) != DUPLICATEDVERTEX)) {
22116  decode(point2tet(ptloop), neightet);
22117  if (infected(neightet)) {
22118  cavetetvertlist->newindex((void **) &parypt);
22119  *parypt = ptloop;
22120  }
22121  if (b->nobisect && (b->nobisect_param > 0)) { // -Y1
22122  // Queue it if it is a Steiner point.
22123  if (pointmark(ptloop) >
22124  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22125  subvertstack->newindex((void **) &parypt);
22126  *parypt = ptloop;
22127  }
22128  }
22129  }
22130  ptloop = pointtraverse();
22131  }
22132 
22133  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
22134  // Remove exterior tets. Hull tets are updated.
22135  arraypool *newhullfacearray;
22136  triface hulltet, casface;
22137  point pa, pb, pc;
22138 
22139  newhullfacearray = new arraypool(sizeof(triface), 10);
22140 
22141  // Create and save new hull tets.
22142  for (i = 0; i < tetarray->objects; i++) {
22143  parytet = (triface *) fastlookup(tetarray, i);
22144  for (j = 0; j < 4; j++) {
22145  decode(parytet->tet[j], tetloop);
22146  if (!infected(tetloop)) {
22147  // Found a new hull face (must be a subface).
22148  tspivot(tetloop, checksh);
22149  maketetrahedron(&hulltet);
22150  pa = org(tetloop);
22151  pb = dest(tetloop);
22152  pc = apex(tetloop);
22153  setvertices(hulltet, pb, pa, pc, dummypoint);
22154  bond(tetloop, hulltet);
22155  // Update the subface-to-tet map.
22156  sesymself(checksh);
22157  tsbond(hulltet, checksh);
22158  // Update the segment-to-tet map.
22159  for (k = 0; k < 3; k++) {
22160  if (issubseg(tetloop)) {
22161  tsspivot1(tetloop, checkseg);
22162  tssbond1(hulltet, checkseg);
22163  sstbond1(checkseg, hulltet);
22164  }
22165  enextself(tetloop);
22166  eprevself(hulltet);
22167  }
22168  // Update the point-to-tet map.
22169  setpoint2tet(pa, (tetrahedron) tetloop.tet);
22170  setpoint2tet(pb, (tetrahedron) tetloop.tet);
22171  setpoint2tet(pc, (tetrahedron) tetloop.tet);
22172  // Save the exterior tet at this hull face. It still holds pointer
22173  // to the adjacent interior tet. Use it to connect new hull tets.
22174  newhullfacearray->newindex((void **) &parytet1);
22175  parytet1->tet = parytet->tet;
22176  parytet1->ver = j;
22177  } // if (!infected(tetloop))
22178  } // j
22179  } // i
22180 
22181  // Connect new hull tets.
22182  for (i = 0; i < newhullfacearray->objects; i++) {
22183  parytet = (triface *) fastlookup(newhullfacearray, i);
22184  fsym(*parytet, neightet);
22185  // Get the new hull tet.
22186  fsym(neightet, hulltet);
22187  for (j = 0; j < 3; j++) {
22188  esym(hulltet, casface);
22189  if (casface.tet[casface.ver & 3] == NULL) {
22190  // Since the boundary of the domain may not be a manifold, we
22191  // find the adjacent hull face by traversing the tets in the
22192  // exterior (which are all infected tets).
22193  neightet = *parytet;
22194  while (1) {
22195  fnextself(neightet);
22196  if (!infected(neightet)) break;
22197  }
22198  if (!ishulltet(neightet)) {
22199  // An interior tet. Get the new hull tet.
22200  fsymself(neightet);
22201  esymself(neightet);
22202  }
22203  // Bond them together.
22204  bond(casface, neightet);
22205  }
22206  enextself(hulltet);
22207  enextself(*parytet);
22208  } // j
22209  } // i
22210 
22211  if (subfacstack->objects > 0l) {
22212  // Remove all subfaces which do not attach to any tetrahedron.
22213  // Segments which are not attached to any subfaces and tets
22214  // are deleted too.
22215  face casingout, casingin;
22216  long delsegcount = 0l;
22217 
22218  for (i = 0; i < subfacstack->objects; i++) {
22219  parysh = (face *) fastlookup(subfacstack, i);
22220  if (i == 0) {
22221  if (b->verbose) {
22222  printf("Warning: Removing an open face (%d, %d, %d)\n",
22223  pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
22224  pointmark(sapex(*parysh)));
22225  }
22226  }
22227  // Dissolve this subface from face links.
22228  for (j = 0; j < 3; j++) {
22229  spivot(*parysh, casingout);
22230  sspivot(*parysh, checkseg);
22231  if (casingout.sh != NULL) {
22232  casingin = casingout;
22233  while (1) {
22234  spivot(casingin, checksh);
22235  if (checksh.sh == parysh->sh) break;
22236  casingin = checksh;
22237  }
22238  if (casingin.sh != casingout.sh) {
22239  // Update the link: ... -> casingin -> casingout ->...
22240  sbond1(casingin, casingout);
22241  } else {
22242  // Only one subface at this edge is left.
22243  sdissolve(casingout);
22244  }
22245  if (checkseg.sh != NULL) {
22246  // Make sure the segment does not connect to a dead one.
22247  ssbond(casingout, checkseg);
22248  }
22249  } else {
22250  if (checkseg.sh != NULL) {
22251  // The segment is also dead.
22252  if (delsegcount == 0) {
22253  if (b->verbose) {
22254  printf("Warning: Removing a dangling segment (%d, %d)\n",
22255  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
22256  }
22257  }
22258  shellfacedealloc(subsegs, checkseg.sh);
22259  delsegcount++;
22260  }
22261  }
22262  senextself(*parysh);
22263  } // j
22264  // Delete this subface.
22265  shellfacedealloc(subfaces, parysh->sh);
22266  } // i
22267  if (b->verbose) {
22268  printf(" Deleted %ld subfaces.\n", subfacstack->objects);
22269  if (delsegcount > 0) {
22270  printf(" Deleted %ld segments.\n", delsegcount);
22271  }
22272  }
22273  subfacstack->restart();
22274  } // if (subfacstack->objects > 0l)
22275 
22276  if (cavetetvertlist->objects > 0l) {
22277  // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
22278  long delvertcount = unuverts;
22279  long delsteinercount = 0l;
22280 
22281  for (i = 0; i < cavetetvertlist->objects; i++) {
22282  parypt = (point *) fastlookup(cavetetvertlist, i);
22283  decode(point2tet(*parypt), neightet);
22284  if (infected(neightet)) {
22285  // Found an exterior vertex.
22286  if (pointmark(*parypt) >
22287  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22288  // A Steiner point.
22289  if (pointtype(*parypt) == FREESEGVERTEX) {
22290  st_segref_count--;
22291  } else if (pointtype(*parypt) == FREEFACETVERTEX) {
22292  st_facref_count--;
22293  } else {
22294  assert(pointtype(*parypt) == FREEVOLVERTEX);
22295  st_volref_count--;
22296  }
22297  delsteinercount++;
22298  if (steinerleft > 0) steinerleft++;
22299  }
22300  setpointtype(*parypt, UNUSEDVERTEX);
22301  unuverts++;
22302  }
22303  }
22304 
22305  if (b->verbose) {
22306  if (unuverts > delvertcount) {
22307  if (delsteinercount > 0l) {
22308  if (unuverts > (delvertcount + delsteinercount)) {
22309  printf(" Removed %ld exterior input vertices.\n",
22310  unuverts - delvertcount - delsteinercount);
22311  }
22312  printf(" Removed %ld exterior Steiner vertices.\n",
22313  delsteinercount);
22314  } else {
22315  printf(" Removed %ld exterior input vertices.\n",
22316  unuverts - delvertcount);
22317  }
22318  }
22319  }
22321  // Comment: 'subvertstack' will be cleaned in routine
22322  // suppresssteinerpoints().
22323  } // if (cavetetvertlist->objects > 0l)
22324 
22325  // Update the hull size.
22326  hullsize += (newhullfacearray->objects - hullarray->objects);
22327 
22328  // Delete all exterior tets and old hull tets.
22329  for (i = 0; i < tetarray->objects; i++) {
22330  parytet = (triface *) fastlookup(tetarray, i);
22331  tetrahedrondealloc(parytet->tet);
22332  }
22333  tetarray->restart();
22334 
22335  for (i = 0; i < hullarray->objects; i++) {
22336  parytet = (triface *) fastlookup(hullarray, i);
22337  tetrahedrondealloc(parytet->tet);
22338  }
22339  hullarray->restart();
22340 
22341  delete newhullfacearray;
22342  } // if (!b->convex && (tetarray->objects > 0l))
22343 
22344  if (b->convex && (tetarray->objects > 0l)) { // With -c option
22345  // In this case, all exterior tets get a region marker '-1'.
22346  assert(b->regionattrib > 0); // -A option must be enabled.
22347  int attrnum = numelemattrib - 1;
22348 
22349  for (i = 0; i < tetarray->objects; i++) {
22350  parytet = (triface *) fastlookup(tetarray, i);
22351  setelemattribute(parytet->tet, attrnum, -1);
22352  }
22353  tetarray->restart();
22354 
22355  for (i = 0; i < hullarray->objects; i++) {
22356  parytet = (triface *) fastlookup(hullarray, i);
22357  uninfect(*parytet);
22358  }
22359  hullarray->restart();
22360 
22361  if (subfacstack->objects > 0l) {
22362  for (i = 0; i < subfacstack->objects; i++) {
22363  parysh = (face *) fastlookup(subfacstack, i);
22364  suninfect(*parysh);
22365  }
22366  subfacstack->restart();
22367  }
22368 
22369  if (cavetetvertlist->objects > 0l) {
22371  }
22372  } // if (b->convex && (tetarray->objects > 0l))
22373 
22374  if (b->regionattrib) { // With -A option.
22375  if (!b->quiet) {
22376  printf("Spreading region attributes.\n");
22377  }
22378  REAL volume;
22379  int attr, maxattr = 0; // Choose a small number here.
22380  int attrnum = numelemattrib - 1;
22381  // Comment: The element region marker is at the end of the list of
22382  // the element attributes.
22383  int regioncount = 0;
22384 
22385  // If has user-defined region attributes.
22386  if (in->numberofregions > 0) {
22387  // Spread region attributes.
22388  for (i = 0; i < 5 * in->numberofregions; i += 5) {
22389  if (regiontets[i/5].tet != NULL) {
22390  attr = (int) in->regionlist[i + 3];
22391  if (attr > maxattr) {
22392  maxattr = attr;
22393  }
22394  volume = in->regionlist[i + 4];
22395  tetarray->restart(); // Re-use this array.
22396  infect(regiontets[i/5]);
22397  tetarray->newindex((void **) &parytet);
22398  *parytet = regiontets[i/5];
22399  // Collect and set attrs for all tets of this region.
22400  for (j = 0; j < tetarray->objects; j++) {
22401  parytet = (triface *) fastlookup(tetarray, j);
22402  tetloop = *parytet;
22403  setelemattribute(tetloop.tet, attrnum, attr);
22404  if (b->varvolume) { // If has -a option.
22405  setvolumebound(tetloop.tet, volume);
22406  }
22407  for (k = 0; k < 4; k++) {
22408  decode(tetloop.tet[k], neightet);
22409  // Is the adjacent already checked?
22410  if (!infected(neightet)) {
22411  // Is this side protected by a subface?
22412  if (!issubface(neightet)) {
22413  infect(neightet);
22414  tetarray->newindex((void **) &parytet);
22415  *parytet = neightet;
22416  }
22417  }
22418  } // k
22419  } // j
22420  regioncount++;
22421  } // if (regiontets[i/5].tet != NULL)
22422  } // i
22423  }
22424 
22425  // Set attributes for all tetrahedra.
22426  attr = maxattr + 1;
22428  tetloop.tet = tetrahedrontraverse();
22429  while (tetloop.tet != (tetrahedron *) NULL) {
22430  if (!infected(tetloop)) {
22431  // An unmarked region.
22432  tetarray->restart(); // Re-use this array.
22433  infect(tetloop);
22434  tetarray->newindex((void **) &parytet);
22435  *parytet = tetloop;
22436  // Find and mark all tets.
22437  for (j = 0; j < tetarray->objects; j++) {
22438  parytet = (triface *) fastlookup(tetarray, j);
22439  tetloop = *parytet;
22440  setelemattribute(tetloop.tet, attrnum, attr);
22441  for (k = 0; k < 4; k++) {
22442  decode(tetloop.tet[k], neightet);
22443  // Is the adjacent tet already checked?
22444  if (!infected(neightet)) {
22445  // Is this side protected by a subface?
22446  if (!issubface(neightet)) {
22447  infect(neightet);
22448  tetarray->newindex((void **) &parytet);
22449  *parytet = neightet;
22450  }
22451  }
22452  } // k
22453  } // j
22454  attr++; // Increase the attribute.
22455  regioncount++;
22456  }
22457  tetloop.tet = tetrahedrontraverse();
22458  }
22459  // Until here, every tet has a region attribute.
22460 
22461  // Uninfect processed tets.
22463  tetloop.tet = tetrahedrontraverse();
22464  while (tetloop.tet != (tetrahedron *) NULL) {
22465  uninfect(tetloop);
22466  tetloop.tet = tetrahedrontraverse();
22467  }
22468 
22469  if (b->verbose) {
22470  //assert(regioncount > 0);
22471  if (regioncount > 1) {
22472  printf(" Found %d subdomains.\n", regioncount);
22473  } else {
22474  printf(" Found %d domain.\n", regioncount);
22475  }
22476  }
22477  } // if (b->regionattrib)
22478 
22479  if (regiontets != NULL) {
22480  delete [] regiontets;
22481  }
22482  delete tetarray;
22483  delete hullarray;
22484 
22485  if (!b->convex) { // No -c option
22486  // The mesh is non-convex now.
22487  nonconvex = 1;
22488 
22489  // Push all hull tets into 'flipstack'.
22491  tetloop.ver = 11; // The face opposite to dummypoint.
22492  tetloop.tet = alltetrahedrontraverse();
22493  while (tetloop.tet != (tetrahedron *) NULL) {
22494  if ((point) tetloop.tet[7] == dummypoint) {
22495  fsym(tetloop, neightet);
22496  flippush(flipstack, &neightet);
22497  }
22498  tetloop.tet = alltetrahedrontraverse();
22499  }
22500 
22501  flipconstraints fc;
22502  fc.enqflag = 2;
22503  long sliver_peel_count = lawsonflip3d(&fc);
22504 
22505  if (sliver_peel_count > 0l) {
22506  if (b->verbose) {
22507  printf(" Removed %ld hull slivers.\n", sliver_peel_count);
22508  }
22509  }
22510  unflipqueue->restart();
22511  } // if (!b->convex)
22512 }
22513 
22515 // //
22516 // reconstructmesh() Reconstruct a tetrahedral mesh. //
22517 // //
22519 
22521 {
22522  tetrahedron *ver2tetarray;
22523  point *idx2verlist;
22524  triface tetloop, checktet, prevchktet;
22525  triface hulltet, face1, face2;
22526  tetrahedron tptr;
22527  face subloop, neighsh, nextsh;
22528  face segloop;
22529  shellface sptr;
22530  point p[4], q[3];
22531  REAL ori, attrib, volume;
22532  REAL angtol, ang;
22533  int eextras, marker = 0;
22534  int bondflag;
22535  int t1ver;
22536  int idx, i, j, k;
22537 
22538  if (!b->quiet) {
22539  printf("Reconstructing mesh ...\n");
22540  }
22541 
22542  if (b->convex) { // -c option.
22543  // Assume the mesh is convex. Exterior tets have region attribute -1.
22544  assert(in->numberoftetrahedronattributes > 0);
22545  } else {
22546  // Assume the mesh is non-convex.
22547  nonconvex = 1;
22548  }
22549 
22550  // Create a map from indices to vertices.
22551  makeindex2pointmap(idx2verlist);
22552  // 'idx2verlist' has length 'in->numberofpoints + 1'.
22553  if (in->firstnumber == 1) {
22554  idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
22555  }
22556 
22557  // Allocate an array that maps each vertex to its adjacent tets.
22558  ver2tetarray = new tetrahedron[in->numberofpoints + 1];
22559  //for (i = 0; i < in->numberofpoints + 1; i++) {
22560  for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
22561  setpointtype(idx2verlist[i], VOLVERTEX); // initial type.
22562  ver2tetarray[i] = NULL;
22563  }
22564 
22565  // Create the tetrahedra and connect those that share a common face.
22566  for (i = 0; i < in->numberoftetrahedra; i++) {
22567  // Get the four vertices.
22568  idx = i * in->numberofcorners;
22569  for (j = 0; j < 4; j++) {
22570  p[j] = idx2verlist[in->tetrahedronlist[idx++]];
22571  }
22572  // Check the orientation.
22573  ori = orient3d(p[0], p[1], p[2], p[3]);
22574  if (ori > 0.0) {
22575  // Swap the first two vertices.
22576  q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
22577  } else if (ori == 0.0) {
22578  if (!b->quiet) {
22579  printf("Warning: Tet #%d is degenerate.\n", i + in->firstnumber);
22580  }
22581  }
22582  // Create a new tetrahedron.
22583  maketetrahedron(&tetloop); // tetloop.ver = 11.
22584  setvertices(tetloop, p[0], p[1], p[2], p[3]);
22585  // Set element attributes if they exist.
22586  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
22587  idx = i * in->numberoftetrahedronattributes;
22588  attrib = in->tetrahedronattributelist[idx + j];
22589  setelemattribute(tetloop.tet, j, attrib);
22590  }
22591  // If -a switch is used (with no number follows) Set a volume
22592  // constraint if it exists.
22593  if (b->varvolume) {
22594  if (in->tetrahedronvolumelist != (REAL *) NULL) {
22595  volume = in->tetrahedronvolumelist[i];
22596  } else {
22597  volume = -1.0;
22598  }
22599  setvolumebound(tetloop.tet, volume);
22600  }
22601  // Try connecting this tet to others that share the common faces.
22602  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22603  p[3] = oppo(tetloop);
22604  // Look for other tets having this vertex.
22605  idx = pointmark(p[3]);
22606  tptr = ver2tetarray[idx];
22607  // Link the current tet to the next one in the stack.
22608  tetloop.tet[8 + tetloop.ver] = tptr;
22609  // Push the current tet onto the stack.
22610  ver2tetarray[idx] = encode(tetloop);
22611  decode(tptr, checktet);
22612  if (checktet.tet != NULL) {
22613  p[0] = org(tetloop); // a
22614  p[1] = dest(tetloop); // b
22615  p[2] = apex(tetloop); // c
22616  prevchktet = tetloop;
22617  do {
22618  q[0] = org(checktet); // a'
22619  q[1] = dest(checktet); // b'
22620  q[2] = apex(checktet); // c'
22621  // Check the three faces at 'd' in 'checktet'.
22622  bondflag = 0;
22623  for (j = 0; j < 3; j++) {
22624  // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
22625  esym(checktet, face2);
22626  if (face2.tet[face2.ver & 3] == NULL) {
22627  k = ((j + 1) % 3);
22628  if (q[k] == p[0]) { // b', c', a' = a
22629  if (q[j] == p[1]) { // a', b', c' = b
22630  // [#,#,d] is matched to [b,a,d].
22631  esym(tetloop, face1);
22632  bond(face1, face2);
22633  bondflag++;
22634  }
22635  }
22636  if (q[k] == p[1]) { // b',c',a' = b
22637  if (q[j] == p[2]) { // a',b',c' = c
22638  // [#,#,d] is matched to [c,b,d].
22639  enext(tetloop, face1);
22640  esymself(face1);
22641  bond(face1, face2);
22642  bondflag++;
22643  }
22644  }
22645  if (q[k] == p[2]) { // b',c',a' = c
22646  if (q[j] == p[0]) { // a',b',c' = a
22647  // [#,#,d] is matched to [a,c,d].
22648  eprev(tetloop, face1);
22649  esymself(face1);
22650  bond(face1, face2);
22651  bondflag++;
22652  }
22653  }
22654  } else {
22655  bondflag++;
22656  }
22657  enextself(checktet);
22658  } // j
22659  // Go to the next tet in the link.
22660  tptr = checktet.tet[8 + checktet.ver];
22661  if (bondflag == 3) {
22662  // All three faces at d in 'checktet' have been connected.
22663  // It can be removed from the link.
22664  prevchktet.tet[8 + prevchktet.ver] = tptr;
22665  } else {
22666  // Bakup the previous tet in the link.
22667  prevchktet = checktet;
22668  }
22669  decode(tptr, checktet);
22670  } while (checktet.tet != NULL);
22671  } // if (checktet.tet != NULL)
22672  } // for (tetloop.ver = 0; ...
22673  } // i
22674 
22675  // Remember a tet of the mesh.
22676  recenttet = tetloop;
22677 
22678  // Create hull tets, create the point-to-tet map, and clean up the
22679  // temporary spaces used in each tet.
22681 
22683  tetloop.tet = tetrahedrontraverse();
22684  while (tetloop.tet != (tetrahedron *) NULL) {
22685  tptr = encode(tetloop);
22686  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22687  if (tetloop.tet[tetloop.ver] == NULL) {
22688  // Create a hull tet.
22689  maketetrahedron(&hulltet);
22690  p[0] = org(tetloop);
22691  p[1] = dest(tetloop);
22692  p[2] = apex(tetloop);
22693  setvertices(hulltet, p[1], p[0], p[2], dummypoint);
22694  bond(tetloop, hulltet);
22695  // Try connecting this to others that share common hull edges.
22696  for (j = 0; j < 3; j++) {
22697  fsym(hulltet, face2);
22698  while (1) {
22699  if (face2.tet == NULL) break;
22700  esymself(face2);
22701  if (apex(face2) == dummypoint) break;
22702  fsymself(face2);
22703  }
22704  if (face2.tet != NULL) {
22705  // Found an adjacent hull tet.
22706  assert(face2.tet[face2.ver & 3] == NULL);
22707  esym(hulltet, face1);
22708  bond(face1, face2);
22709  }
22710  enextself(hulltet);
22711  }
22712  //hullsize++;
22713  }
22714  // Create the point-to-tet map.
22715  setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
22716  // Clean the temporary used space.
22717  tetloop.tet[8 + tetloop.ver] = NULL;
22718  }
22719  tetloop.tet = tetrahedrontraverse();
22720  }
22721 
22723 
22724  // Subfaces will be inserted into the mesh.
22725  if (in->trifacelist != NULL) {
22726  // A .face file is given. It may contain boundary faces. Insert them.
22727  for (i = 0; i < in->numberoftrifaces; i++) {
22728  // Is it a subface?
22729  if (in->trifacemarkerlist != NULL) {
22730  marker = in->trifacemarkerlist[i];
22731  } else {
22732  // Face markers are not available. Assume all of them are subfaces.
22733  marker = 1;
22734  }
22735  if (marker > 0) {
22736  idx = i * 3;
22737  for (j = 0; j < 3; j++) {
22738  p[j] = idx2verlist[in->trifacelist[idx++]];
22739  }
22740  // Search the subface.
22741  bondflag = 0;
22742  // Make sure all vertices are in the mesh. Avoid crash.
22743  for (j = 0; j < 3; j++) {
22744  decode(point2tet(p[j]), checktet);
22745  if (checktet.tet == NULL) break;
22746  }
22747  if ((j == 3) && getedge(p[0], p[1], &checktet)) {
22748  tetloop = checktet;
22749  q[2] = apex(checktet);
22750  while (1) {
22751  if (apex(tetloop) == p[2]) {
22752  // Found the face.
22753  // Check if there exist a subface already?
22754  tspivot(tetloop, neighsh);
22755  if (neighsh.sh != NULL) {
22756  // Found a duplicated subface.
22757  // This happens when the mesh was generated by other mesher.
22758  bondflag = 0;
22759  } else {
22760  bondflag = 1;
22761  }
22762  break;
22763  }
22764  fnextself(tetloop);
22765  if (apex(tetloop) == q[2]) break;
22766  }
22767  }
22768  if (bondflag) {
22769  // Create a new subface.
22770  makeshellface(subfaces, &subloop);
22771  setshvertices(subloop, p[0], p[1], p[2]);
22772  // Create the point-to-subface map.
22773  sptr = sencode(subloop);
22774  for (j = 0; j < 3; j++) {
22775  setpointtype(p[j], FACETVERTEX); // initial type.
22776  setpoint2sh(p[j], sptr);
22777  }
22778  if (in->trifacemarkerlist != NULL) {
22779  setshellmark(subloop, in->trifacemarkerlist[i]);
22780  }
22781  // Insert the subface into the mesh.
22782  tsbond(tetloop, subloop);
22783  fsymself(tetloop);
22784  sesymself(subloop);
22785  tsbond(tetloop, subloop);
22786  } else {
22787  if (!b->quiet) {
22788  if (neighsh.sh == NULL) {
22789  printf("Warning: Subface #%d [%d,%d,%d] is missing.\n",
22790  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22791  pointmark(p[2]));
22792  } else {
22793  printf("Warning: Ignore a dunplicated subface #%d [%d,%d,%d].\n",
22794  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22795  pointmark(p[2]));
22796  }
22797  }
22798  } // if (bondflag)
22799  } // if (marker > 0)
22800  } // i
22801  } // if (in->trifacelist)
22802 
22803  // Indentify subfaces from the mesh.
22804  // Create subfaces for hull faces (if they're not subface yet) and
22805  // interior faces which separate two different materials.
22806  eextras = in->numberoftetrahedronattributes;
22808  tetloop.tet = tetrahedrontraverse();
22809  while (tetloop.tet != (tetrahedron *) NULL) {
22810  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22811  tspivot(tetloop, neighsh);
22812  if (neighsh.sh == NULL) {
22813  bondflag = 0;
22814  fsym(tetloop, checktet);
22815  if (ishulltet(checktet)) {
22816  // A hull face.
22817  if (!b->convex) {
22818  bondflag = 1; // Insert a hull subface.
22819  }
22820  } else {
22821  if (eextras > 0) {
22822  if (elemattribute(tetloop.tet, eextras - 1) !=
22823  elemattribute(checktet.tet, eextras - 1)) {
22824  bondflag = 1; // Insert an interior interface.
22825  }
22826  }
22827  }
22828  if (bondflag) {
22829  // Create a new subface.
22830  makeshellface(subfaces, &subloop);
22831  p[0] = org(tetloop);
22832  p[1] = dest(tetloop);
22833  p[2] = apex(tetloop);
22834  setshvertices(subloop, p[0], p[1], p[2]);
22835  // Create the point-to-subface map.
22836  sptr = sencode(subloop);
22837  for (j = 0; j < 3; j++) {
22838  setpointtype(p[j], FACETVERTEX); // initial type.
22839  setpoint2sh(p[j], sptr);
22840  }
22841  setshellmark(subloop, 0); // Default marker.
22842  // Insert the subface into the mesh.
22843  tsbond(tetloop, subloop);
22844  sesymself(subloop);
22845  tsbond(checktet, subloop);
22846  } // if (bondflag)
22847  } // if (neighsh.sh == NULL)
22848  }
22849  tetloop.tet = tetrahedrontraverse();
22850  }
22851 
22852  // Connect subfaces together.
22854  subloop.shver = 0;
22855  subloop.sh = shellfacetraverse(subfaces);
22856  while (subloop.sh != (shellface *) NULL) {
22857  for (i = 0; i < 3; i++) {
22858  spivot(subloop, neighsh);
22859  if (neighsh.sh == NULL) {
22860  // Form a subface ring by linking all subfaces at this edge.
22861  // Traversing all faces of the tets at this edge.
22862  stpivot(subloop, tetloop);
22863  q[2] = apex(tetloop);
22864  neighsh = subloop;
22865  while (1) {
22866  fnextself(tetloop);
22867  tspivot(tetloop, nextsh);
22868  if (nextsh.sh != NULL) {
22869  // Link neighsh <= nextsh.
22870  sbond1(neighsh, nextsh);
22871  neighsh = nextsh;
22872  }
22873  if (apex(tetloop) == q[2]) {
22874  assert(nextsh.sh == subloop.sh); // It's a ring.
22875  break;
22876  }
22877  } // while (1)
22878  } // if (neighsh.sh == NULL)
22879  senextself(subloop);
22880  }
22881  subloop.sh = shellfacetraverse(subfaces);
22882  }
22883 
22884 
22885  // Segments will be introduced.
22886  if (in->edgelist != NULL) {
22887  // A .edge file is given. It may contain boundary edges. Insert them.
22888  for (i = 0; i < in->numberofedges; i++) {
22889  // Is it a segment?
22890  if (in->edgemarkerlist != NULL) {
22891  marker = in->edgemarkerlist[i];
22892  } else {
22893  // Edge markers are not available. Assume all of them are segments.
22894  marker = 1;
22895  }
22896  if (marker != 0) {
22897  // Insert a segment.
22898  idx = i * 2;
22899  for (j = 0; j < 2; j++) {
22900  p[j] = idx2verlist[in->edgelist[idx++]];
22901  }
22902  // Make sure all vertices are in the mesh. Avoid crash.
22903  for (j = 0; j < 2; j++) {
22904  decode(point2tet(p[j]), checktet);
22905  if (checktet.tet == NULL) break;
22906  }
22907  // Search the segment.
22908  if ((j == 2) && getedge(p[0], p[1], &checktet)) {
22909  // Create a new subface.
22910  makeshellface(subsegs, &segloop);
22911  setshvertices(segloop, p[0], p[1], NULL);
22912  // Create the point-to-segment map.
22913  sptr = sencode(segloop);
22914  for (j = 0; j < 2; j++) {
22915  setpointtype(p[j], RIDGEVERTEX); // initial type.
22916  setpoint2sh(p[j], sptr);
22917  }
22918  if (in->edgemarkerlist != NULL) {
22919  setshellmark(segloop, marker);
22920  }
22921  // Insert the segment into the mesh.
22922  tetloop = checktet;
22923  q[2] = apex(checktet);
22924  subloop.sh = NULL;
22925  while (1) {
22926  tssbond1(tetloop, segloop);
22927  tspivot(tetloop, subloop);
22928  if (subloop.sh != NULL) {
22929  ssbond1(subloop, segloop);
22930  sbond1(segloop, subloop);
22931  }
22932  fnextself(tetloop);
22933  if (apex(tetloop) == q[2]) break;
22934  } // while (1)
22935  // Remember an adjacent tet for this segment.
22936  sstbond1(segloop, tetloop);
22937  } else {
22938  if (!b->quiet) {
22939  printf("Warning: Segment #%d [%d,%d] is missing.\n",
22940  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
22941  }
22942  }
22943  } // if (marker != 0)
22944  } // i
22945  } // if (in->edgelist)
22946 
22947  // Identify segments from the mesh.
22948  // Create segments for non-manifold edges (which are shared by more
22949  // than two subfaces), and for non-coplanar edges, i.e., two subfaces
22950  // form an dihedral angle > 'b->facet_ang_tol' (degree).
22951  angtol = b->facet_ang_tol / 180.0 * PI;
22953  subloop.shver = 0;
22954  subloop.sh = shellfacetraverse(subfaces);
22955  while (subloop.sh != (shellface *) NULL) {
22956  for (i = 0; i < 3; i++) {
22957  sspivot(subloop, segloop);
22958  if (segloop.sh == NULL) {
22959  // Check if this edge is a segment.
22960  bondflag = 0;
22961  // Counter the number of subfaces at this edge.
22962  idx = 0;
22963  nextsh = subloop;
22964  while (1) {
22965  idx++;
22966  spivotself(nextsh);
22967  if (nextsh.sh == subloop.sh) break;
22968  }
22969  if (idx != 2) {
22970  // It's a non-manifold edge. Insert a segment.
22971  p[0] = sorg(subloop);
22972  p[1] = sdest(subloop);
22973  bondflag = 1;
22974  } else {
22975  spivot(subloop, neighsh);
22976  if (shellmark(subloop) != shellmark(neighsh)) {
22977  // It's an interior interface. Insert a segment.
22978  p[0] = sorg(subloop);
22979  p[1] = sdest(subloop);
22980  bondflag = 1;
22981  } else {
22982  if (!b->convex) {
22983  // Check the dihedral angle formed by the two subfaces.
22984  p[0] = sorg(subloop);
22985  p[1] = sdest(subloop);
22986  p[2] = sapex(subloop);
22987  p[3] = sapex(neighsh);
22988  ang = facedihedral(p[0], p[1], p[2], p[3]);
22989  if (ang > PI) ang = 2 * PI - ang;
22990  if (ang < angtol) {
22991  bondflag = 1;
22992  }
22993  }
22994  }
22995  }
22996  if (bondflag) {
22997  // Create a new segment.
22998  makeshellface(subsegs, &segloop);
22999  setshvertices(segloop, p[0], p[1], NULL);
23000  // Create the point-to-segment map.
23001  sptr = sencode(segloop);
23002  for (j = 0; j < 2; j++) {
23003  setpointtype(p[j], RIDGEVERTEX); // initial type.
23004  setpoint2sh(p[j], sptr);
23005  }
23006  setshellmark(segloop, 0); // Initially has no marker.
23007  // Insert the subface into the mesh.
23008  stpivot(subloop, tetloop);
23009  q[2] = apex(tetloop);
23010  while (1) {
23011  tssbond1(tetloop, segloop);
23012  tspivot(tetloop, neighsh);
23013  if (neighsh.sh != NULL) {
23014  ssbond1(neighsh, segloop);
23015  }
23016  fnextself(tetloop);
23017  if (apex(tetloop) == q[2]) break;
23018  } // while (1)
23019  // Remember an adjacent tet for this segment.
23020  sstbond1(segloop, tetloop);
23021  sbond1(segloop, subloop);
23022  } // if (bondflag)
23023  } // if (neighsh.sh == NULL)
23024  senextself(subloop);
23025  } // i
23026  subloop.sh = shellfacetraverse(subfaces);
23027  }
23028 
23029  // Remember the number of input segments.
23031 
23032  if (!b->nobisect || checkconstraints) {
23033  // Mark Steiner points on segments and facets.
23034  // - all vertices which remaining type FEACTVERTEX become
23035  // Steiner points in facets (= FREEFACERVERTEX).
23036  // - vertices on segment need to be checked.
23037  face* segperverlist;
23038  int* idx2seglist;
23039  face parentseg, nextseg;
23040  verttype vt;
23041  REAL area, len, l1, l2;
23042  int fmarker;
23043 
23044  makepoint2submap(subsegs, idx2seglist, segperverlist);
23045 
23046  points->traversalinit();
23047  point ptloop = pointtraverse();
23048  while (ptloop != NULL) {
23049  vt = pointtype(ptloop);
23050  if (vt == VOLVERTEX) {
23051  setpointtype(ptloop, FREEVOLVERTEX);
23052  st_volref_count++;
23053  } else if (vt == FACETVERTEX) {
23054  setpointtype(ptloop, FREEFACETVERTEX);
23055  st_facref_count++;
23056  } else if (vt == RIDGEVERTEX) {
23057  idx = pointmark(ptloop) - in->firstnumber;
23058  if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
23059  i = idx2seglist[idx];
23060  parentseg = segperverlist[i];
23061  nextseg = segperverlist[i + 1];
23062  sesymself(nextseg);
23063  p[0] = sorg(nextseg);
23064  p[1] = sdest(parentseg);
23065  // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
23066  len = distance(p[0], p[1]);
23067  l1 = distance(p[0], ptloop);
23068  l2 = distance(ptloop, p[1]);
23069  if (((l1 + l2 - len) / len) < b->epsilon) {
23070  // They are (nearly) collinear.
23071  setpointtype(ptloop, FREESEGVERTEX);
23072  // Connect nextseg and parentseg together at ptloop.
23073  senextself(nextseg);
23074  senext2self(parentseg);
23075  sbond(nextseg, parentseg);
23076  st_segref_count++;
23077  }
23078  }
23079  }
23080  ptloop = pointtraverse();
23081  }
23082 
23083  // Are there area constraints?
23084  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
23085  // Set maximum area constraints on facets.
23086  for (i = 0; i < in->numberoffacetconstraints; i++) {
23087  fmarker = (int) in->facetconstraintlist[i * 2];
23088  area = in->facetconstraintlist[i * 2 + 1];
23090  subloop.sh = shellfacetraverse(subfaces);
23091  while (subloop.sh != NULL) {
23092  if (shellmark(subloop) == fmarker) {
23093  setareabound(subloop, area);
23094  }
23095  subloop.sh = shellfacetraverse(subfaces);
23096  }
23097  }
23098  }
23099 
23100  // Are there length constraints?
23101  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
23102  // Set maximum length constraints on segments.
23103  int e1, e2;
23104  for (i = 0; i < in->numberofsegmentconstraints; i++) {
23105  e1 = (int) in->segmentconstraintlist[i * 3];
23106  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
23107  len = in->segmentconstraintlist[i * 3 + 2];
23108  // Search for edge [e1, e2].
23109  idx = e1 - in->firstnumber;
23110  for (j = idx2seglist[idx]; j < idx2seglist[idx + 1]; j++) {
23111  parentseg = segperverlist[j];
23112  if (pointmark(sdest(parentseg)) == e2) {
23113  setareabound(parentseg, len);
23114  break;
23115  }
23116  }
23117  }
23118  }
23119 
23120  delete [] idx2seglist;
23121  delete [] segperverlist;
23122  }
23123 
23124 
23125  // Set global flags.
23126  checksubsegflag = 1;
23127  checksubfaceflag = 1;
23128 
23129  delete [] idx2verlist;
23130  delete [] ver2tetarray;
23131 }
23132 
23134 // //
23135 // scoutpoint() Search a point in mesh. //
23136 // //
23137 // This function searches the point in a mesh whose domain may be not convex.//
23138 // In case of a convex domain, the locate() function is sufficient. //
23139 // //
23140 // If 'randflag' is used, randomly select a start searching tet. Otherwise, //
23141 // start searching directly from 'searchtet'. //
23142 // //
23144 
23145 int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
23146 {
23147  point pa, pb, pc, pd;
23148  enum locateresult loc = OUTSIDE;
23149  REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
23150  int t1ver;
23151 
23152 
23153  // Randomly select a good starting tet.
23154  if (randflag) {
23155  randomsample(searchpt, searchtet);
23156  } else {
23157  if (searchtet->tet == NULL) {
23158  *searchtet = recenttet;
23159  }
23160  }
23161  loc = locate(searchpt, searchtet);
23162 
23163  if (loc == OUTSIDE) {
23164  if (b->convex) { // -c option
23165  // The point lies outside of the convex hull.
23166  return (int) loc;
23167  }
23168  // Test if it lies nearly on the hull face.
23169  // Reuse vol, ori1.
23170  pa = org(*searchtet);
23171  pb = dest(*searchtet);
23172  pc = apex(*searchtet);
23173  vol = triarea(pa, pb, pc);
23174  ori1 = orient3dfast(pa, pb, pc, searchpt);
23175  if (fabs(ori1 / vol) < b->epsilon) {
23176  loc = ONFACE; // On face (or on edge, or on vertex).
23177  fsymself(*searchtet);
23178  }
23179  }
23180 
23181  if (loc != OUTSIDE) {
23182  // Round the result of location.
23183  pa = org(*searchtet);
23184  pb = dest(*searchtet);
23185  pc = apex(*searchtet);
23186  pd = oppo(*searchtet);
23187  vol = orient3dfast(pa, pb, pc, pd);
23188  ori1 = orient3dfast(pa, pb, pc, searchpt);
23189  ori2 = orient3dfast(pb, pa, pd, searchpt);
23190  ori3 = orient3dfast(pc, pb, pd, searchpt);
23191  ori4 = orient3dfast(pa, pc, pd, searchpt);
23192  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
23193  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23194  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23195  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23196  } else { // if (loc == OUTSIDE) {
23197  // Do a brute force search for the point (with rounding).
23199  searchtet->tet = tetrahedrontraverse();
23200  while (searchtet->tet != NULL) {
23201  pa = org(*searchtet);
23202  pb = dest(*searchtet);
23203  pc = apex(*searchtet);
23204  pd = oppo(*searchtet);
23205 
23206  vol = orient3dfast(pa, pb, pc, pd);
23207  if (vol < 0) {
23208  ori1 = orient3dfast(pa, pb, pc, searchpt);
23209  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
23210  if (ori1 <= 0) {
23211  ori2 = orient3dfast(pb, pa, pd, searchpt);
23212  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23213  if (ori2 <= 0) {
23214  ori3 = orient3dfast(pc, pb, pd, searchpt);
23215  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23216  if (ori3 <= 0) {
23217  ori4 = orient3dfast(pa, pc, pd, searchpt);
23218  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23219  if (ori4 <= 0) {
23220  // Found the tet. Return its location.
23221  break;
23222  } // ori4
23223  } // ori3
23224  } // ori2
23225  } // ori1
23226  }
23227 
23228  searchtet->tet = tetrahedrontraverse();
23229  } // while (searchtet->tet != NULL)
23230  nonregularcount++; // Re-use this counter.
23231  }
23232 
23233  if (searchtet->tet != NULL) {
23234  // Return the point location.
23235  if (ori1 == 0) { // on face [a,b,c]
23236  if (ori2 == 0) { // on edge [a,b].
23237  if (ori3 == 0) { // on vertex [b].
23238  assert(ori4 != 0);
23239  enextself(*searchtet); // [b,c,a,d]
23240  loc = ONVERTEX;
23241  } else {
23242  if (ori4 == 0) { // on vertex [a]
23243  loc = ONVERTEX; // [a,b,c,d]
23244  } else {
23245  loc = ONEDGE; // [a,b,c,d]
23246  }
23247  }
23248  } else { // ori2 != 0
23249  if (ori3 == 0) { // on edge [b,c]
23250  if (ori4 == 0) { // on vertex [c]
23251  eprevself(*searchtet); // [c,a,b,d]
23252  loc = ONVERTEX;
23253  } else {
23254  enextself(*searchtet); // [b,c,a,d]
23255  loc = ONEDGE;
23256  }
23257  } else { // ori3 != 0
23258  if (ori4 == 0) { // on edge [c,a]
23259  eprevself(*searchtet); // [c,a,b,d]
23260  loc = ONEDGE;
23261  } else {
23262  loc = ONFACE;
23263  }
23264  }
23265  }
23266  } else { // ori1 != 0
23267  if (ori2 == 0) { // on face [b,a,d]
23268  esymself(*searchtet); // [b,a,d,c]
23269  if (ori3 == 0) { // on edge [b,d]
23270  eprevself(*searchtet); // [d,b,a,c]
23271  if (ori4 == 0) { // on vertex [d]
23272  loc = ONVERTEX;
23273  } else {
23274  loc = ONEDGE;
23275  }
23276  } else { // ori3 != 0
23277  if (ori4 == 0) { // on edge [a,d]
23278  enextself(*searchtet); // [a,d,b,c]
23279  loc = ONEDGE;
23280  } else {
23281  loc = ONFACE;
23282  }
23283  }
23284  } else { // ori2 != 0
23285  if (ori3 == 0) { // on face [c,b,d]
23286  enextself(*searchtet);
23287  esymself(*searchtet);
23288  if (ori4 == 0) { // on edge [c,d]
23289  eprevself(*searchtet);
23290  loc = ONEDGE;
23291  } else {
23292  loc = ONFACE;
23293  }
23294  } else {
23295  if (ori4 == 0) { // on face [a,c,d]
23296  eprevself(*searchtet);
23297  esymself(*searchtet);
23298  loc = ONFACE;
23299  } else { // inside tet [a,b,c,d]
23300  loc = INTETRAHEDRON;
23301  } // ori4
23302  } // ori3
23303  } // ori2
23304  } // ori1
23305  } else {
23306  loc = OUTSIDE;
23307  }
23308 
23309  return (int) loc;
23310 }
23311 
23313 // //
23314 // getpointmeshsize() Interpolate the mesh size at given point. //
23315 // //
23316 // 'iloc' indicates the location of the point w.r.t. 'searchtet'. The size //
23317 // is obtained by linear interpolation on the vertices of the tet. //
23318 // //
23320 
23321 REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
23322 {
23323  point *pts, pa, pb, pc;
23324  REAL volume, vol[4], wei[4];
23325  REAL size;
23326  int i;
23327 
23328  size = 0;
23329 
23330  if (iloc == (int) INTETRAHEDRON) {
23331  pts = (point *) &(searchtet->tet[4]);
23332  assert(pts[3] != dummypoint);
23333  // Only do interpolation if all vertices have non-zero sizes.
23334  if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
23335  (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
23336  // P1 interpolation.
23337  volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
23338  vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
23339  vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
23340  vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
23341  vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
23342  for (i = 0; i < 4; i++) {
23343  wei[i] = fabs(vol[i] / volume);
23344  size += (wei[i] * pts[i][pointmtrindex]);
23345  }
23346  }
23347  } else if (iloc == (int) ONFACE) {
23348  pa = org(*searchtet);
23349  pb = dest(*searchtet);
23350  pc = apex(*searchtet);
23351  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
23352  (pc[pointmtrindex] > 0)) {
23353  volume = triarea(pa, pb, pc);
23354  vol[0] = triarea(searchpt, pb, pc);
23355  vol[1] = triarea(pa, searchpt, pc);
23356  vol[2] = triarea(pa, pb, searchpt);
23357  size = (vol[0] / volume) * pa[pointmtrindex]
23358  + (vol[1] / volume) * pb[pointmtrindex]
23359  + (vol[2] / volume) * pc[pointmtrindex];
23360  }
23361  } else if (iloc == (int) ONEDGE) {
23362  pa = org(*searchtet);
23363  pb = dest(*searchtet);
23364  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
23365  volume = distance(pa, pb);
23366  vol[0] = distance(searchpt, pb);
23367  vol[1] = distance(pa, searchpt);
23368  size = (vol[0] / volume) * pa[pointmtrindex]
23369  + (vol[1] / volume) * pb[pointmtrindex];
23370  }
23371  } else if (iloc == (int) ONVERTEX) {
23372  pa = org(*searchtet);
23373  if (pa[pointmtrindex] > 0) {
23374  size = pa[pointmtrindex];
23375  }
23376  }
23377 
23378  return size;
23379 }
23380 
23382 // //
23383 // interpolatemeshsize() Interpolate the mesh size from a background mesh //
23384 // (source) to the current mesh (destination). //
23385 // //
23387 
23389 {
23390  triface searchtet;
23391  point ploop;
23392  REAL minval = 0.0, maxval = 0.0;
23393  int iloc;
23394  int count;
23395 
23396  if (!b->quiet) {
23397  printf("Interpolating mesh size ...\n");
23398  }
23399 
23400  long bak_nonregularcount = nonregularcount;
23401  nonregularcount = 0l; // Count the number of (slow) global searches.
23402  long baksmaples = bgm->samples;
23403  bgm->samples = 3l;
23404  count = 0; // Count the number of interpolated points.
23405 
23406  // Interpolate sizes for all points in the current mesh.
23407  points->traversalinit();
23408  ploop = pointtraverse();
23409  while (ploop != NULL) {
23410  // Search a tet in bgm which containing this point.
23411  searchtet.tet = NULL;
23412  iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
23413  if (iloc != (int) OUTSIDE) {
23414  // Interpolate the mesh size.
23415  ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
23416  setpoint2bgmtet(ploop, bgm->encode(searchtet));
23417  if (count == 0) {
23418  // This is the first interpolated point.
23419  minval = maxval = ploop[pointmtrindex];
23420  } else {
23421  if (ploop[pointmtrindex] < minval) {
23422  minval = ploop[pointmtrindex];
23423  }
23424  if (ploop[pointmtrindex] > maxval) {
23425  maxval = ploop[pointmtrindex];
23426  }
23427  }
23428  count++;
23429  } else {
23430  if (!b->quiet) {
23431  printf("Warnning: Failed to locate point %d in source mesh.\n",
23432  pointmark(ploop));
23433  }
23434  }
23435  ploop = pointtraverse();
23436  }
23437 
23438  if (b->verbose) {
23439  printf(" Interoplated %d points.\n", count);
23440  if (nonregularcount > 0l) {
23441  printf(" Performed %ld brute-force searches.\n", nonregularcount);
23442  }
23443  printf(" Size rangle [%.17g, %.17g].\n", minval, maxval);
23444  }
23445 
23446  bgm->samples = baksmaples;
23447  nonregularcount = bak_nonregularcount;
23448 }
23449 
23451 // //
23452 // insertconstrainedpoints() Insert a list of points into the mesh. //
23453 // //
23454 // Assumption: The bounding box of the insert point set should be no larger //
23455 // than the bounding box of the mesh. (Required by point sorting). //
23456 // //
23458 
23459 void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
23460  int rejflag)
23461 {
23462  triface searchtet, spintet;
23463  face splitsh;
23464  face splitseg;
23465  insertvertexflags ivf;
23466  flipconstraints fc;
23467  int randflag = 0;
23468  int t1ver;
23469  int i;
23470 
23471  if (b->verbose) {
23472  printf(" Inserting %d constrained points\n", arylen);
23473  }
23474 
23475  if (b->no_sort) { // -b/1 option.
23476  if (b->verbose) {
23477  printf(" Using the input order.\n");
23478  }
23479  } else {
23480  if (b->verbose) {
23481  printf(" Permuting vertices.\n");
23482  }
23483  point swappoint;
23484  int randindex;
23485  srand(arylen);
23486  for (i = 0; i < arylen; i++) {
23487  randindex = rand() % (i + 1);
23488  swappoint = insertarray[i];
23489  insertarray[i] = insertarray[randindex];
23490  insertarray[randindex] = swappoint;
23491  }
23492  if (b->brio_hilbert) { // -b1 option
23493  if (b->verbose) {
23494  printf(" Sorting vertices.\n");
23495  }
23497  int ngroup = 0;
23498  brio_multiscale_sort(insertarray, arylen, b->brio_threshold,
23499  b->brio_ratio, &ngroup);
23500  } else { // -b0 option.
23501  randflag = 1;
23502  } // if (!b->brio_hilbert)
23503  } // if (!b->no_sort)
23504 
23505  long bak_nonregularcount = nonregularcount;
23506  nonregularcount = 0l;
23507  long baksmaples = samples;
23508  samples = 3l; // Use at least 3 samples. Updated in randomsample().
23509 
23510  long bak_seg_count = st_segref_count;
23511  long bak_fac_count = st_facref_count;
23512  long bak_vol_count = st_volref_count;
23513 
23514  // Initialize the insertion parameters.
23515  if (b->incrflip) { // -l option
23516  // Use incremental flip algorithm.
23517  ivf.bowywat = 0;
23518  ivf.lawson = 1;
23519  ivf.validflag = 0; // No need to validate the cavity.
23520  fc.enqflag = 2;
23521  } else {
23522  // Use Bowyer-Watson algorithm.
23523  ivf.bowywat = 1;
23524  ivf.lawson = 0;
23525  ivf.validflag = 1; // Validate the B-W cavity.
23526  }
23527  ivf.rejflag = rejflag;
23528  ivf.chkencflag = 0;
23529  ivf.sloc = (int) INSTAR;
23530  ivf.sbowywat = 3;
23531  ivf.splitbdflag = 1;
23532  ivf.respectbdflag = 1;
23533  ivf.assignmeshsize = b->metric;
23534 
23535  encseglist = new arraypool(sizeof(face), 8);
23536  encshlist = new arraypool(sizeof(badface), 8);
23537 
23538  // Insert the points.
23539  for (i = 0; i < arylen; i++) {
23540  // Find the location of the inserted point.
23541  // Do not use 'recenttet', since the mesh may be non-convex.
23542  searchtet.tet = NULL;
23543  ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
23544 
23545  // Decide the right type for this point.
23546  setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
23547  splitsh.sh = NULL;
23548  splitseg.sh = NULL;
23549  if (ivf.iloc == (int) ONEDGE) {
23550  if (issubseg(searchtet)) {
23551  tsspivot1(searchtet, splitseg);
23552  setpointtype(insertarray[i], FREESEGVERTEX);
23553  //ivf.rejflag = 0;
23554  } else {
23555  // Check if it is a subface edge.
23556  spintet = searchtet;
23557  while (1) {
23558  if (issubface(spintet)) {
23559  tspivot(spintet, splitsh);
23560  setpointtype(insertarray[i], FREEFACETVERTEX);
23561  //ivf.rejflag |= 1;
23562  break;
23563  }
23564  fnextself(spintet);
23565  if (spintet.tet == searchtet.tet) break;
23566  }
23567  }
23568  } else if (ivf.iloc == (int) ONFACE) {
23569  if (issubface(searchtet)) {
23570  tspivot(searchtet, splitsh);
23571  setpointtype(insertarray[i], FREEFACETVERTEX);
23572  //ivf.rejflag |= 1;
23573  }
23574  }
23575 
23576  // Now insert the point.
23577  if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
23578  if (flipstack != NULL) {
23579  // There are queued faces. Use flips to recover Delaunayness.
23580  lawsonflip3d(&fc);
23581  // There may be unflippable edges. Ignore them.
23582  unflipqueue->restart();
23583  }
23584  // Update the Steiner counters.
23585  if (pointtype(insertarray[i]) == FREESEGVERTEX) {
23586  st_segref_count++;
23587  } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
23588  st_facref_count++;
23589  } else {
23590  st_volref_count++;
23591  }
23592  } else {
23593  // Point is not inserted.
23594  //pointdealloc(insertarray[i]);
23595  setpointtype(insertarray[i], UNUSEDVERTEX);
23596  unuverts++;
23597  encseglist->restart();
23598  encshlist->restart();
23599  }
23600  } // i
23601 
23602  delete encseglist;
23603  delete encshlist;
23604 
23605  if (b->verbose) {
23606  printf(" Inserted %ld (%ld, %ld, %ld) vertices.\n",
23608  (bak_seg_count + bak_fac_count + bak_vol_count),
23609  st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
23610  st_volref_count - bak_vol_count);
23611  if (nonregularcount > 0l) {
23612  printf(" Performed %ld brute-force searches.\n", nonregularcount);
23613  }
23614  }
23615 
23616  nonregularcount = bak_nonregularcount;
23617  samples = baksmaples;
23618 }
23619 
23621 {
23622  point *insertarray, newpt;
23623  REAL x, y, z, w;
23624  int index, attribindex, mtrindex;
23625  int arylen, i, j;
23626 
23627  if (!b->quiet) {
23628  printf("Inserting constrained points ...\n");
23629  }
23630 
23631  insertarray = new point[addio->numberofpoints];
23632  arylen = 0;
23633  index = 0;
23634  attribindex = 0;
23635  mtrindex = 0;
23636 
23637  for (i = 0; i < addio->numberofpoints; i++) {
23638  x = addio->pointlist[index++];
23639  y = addio->pointlist[index++];
23640  z = addio->pointlist[index++];
23641  // Test if this point lies inside the bounding box.
23642  if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
23643  (z < zmin) || (z > zmax)) {
23644  if (b->verbose) {
23645  printf("Warning: Point #%d lies outside the bounding box. Ignored\n",
23646  i + in->firstnumber);
23647  }
23648  continue;
23649  }
23650  makepoint(&newpt, UNUSEDVERTEX);
23651  newpt[0] = x;
23652  newpt[1] = y;
23653  newpt[2] = z;
23654  // Read the point attributes. (Including point weights.)
23655  for (j = 0; j < addio->numberofpointattributes; j++) {
23656  newpt[3 + j] = addio->pointattributelist[attribindex++];
23657  }
23658  // Read the point metric tensor.
23659  for (j = 0; j < addio->numberofpointmtrs; j++) {
23660  newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
23661  }
23662  if (b->weighted) { // -w option
23663  if (addio->numberofpointattributes > 0) {
23664  // The first point attribute is its weight.
23665  w = newpt[3];
23666  } else {
23667  // No given weight available. Default choose the maximum
23668  // absolute value among its coordinates.
23669  w = fabs(x);
23670  if (w < fabs(y)) w = fabs(y);
23671  if (w < fabs(z)) w = fabs(z);
23672  }
23673  if (b->weighted_param == 0) {
23674  newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
23675  } else { // -w1 option
23676  newpt[3] = w; // Regular tetrahedralization.
23677  }
23678  }
23679  insertarray[arylen] = newpt;
23680  arylen++;
23681  } // i
23682 
23683  // Insert the points.
23684  int rejflag = 0; // Do not check encroachment.
23685  if (b->metric) { // -m option.
23686  rejflag |= 4; // Reject it if it lies in some protecting balls.
23687  }
23688 
23689  insertconstrainedpoints(insertarray, arylen, rejflag);
23690 
23691  delete [] insertarray;
23692 }
23693 
23695 // //
23696 // meshcoarsening() Deleting (selected) vertices. //
23697 // //
23699 
23701 {
23702  point ptloop, *parypt;
23703  verttype vt;
23704 
23705  // If a mesh sizing function is given. Collect vertices whose mesh size
23706  // is greater than its smallest edge length.
23707  if (b->metric) { // -m option
23708  REAL len, smlen;
23709  int i;
23710  points->traversalinit();
23711  ptloop = pointtraverse();
23712  while (ptloop != NULL) {
23713  if (ptloop[pointmtrindex] > 0) {
23714  // Get the smallest edge length at this vertex.
23715  getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
23716  parypt = (point *) fastlookup(cavetetvertlist, 0);
23717  smlen = distance(ptloop, *parypt);
23718  for (i = 1; i < cavetetvertlist->objects; i++) {
23719  parypt = (point *) fastlookup(cavetetvertlist, i);
23720  len = distance(ptloop, *parypt);
23721  if (len < smlen) {
23722  smlen = len;
23723  }
23724  }
23726  cavetetlist->restart();
23727  if (smlen < ptloop[pointmtrindex]) {
23728  pinfect(ptloop);
23729  remptlist->newindex((void **) &parypt);
23730  *parypt = ptloop;
23731  }
23732  }
23733  ptloop = pointtraverse();
23734  }
23735  if (b->verbose > 1) {
23736  printf(" Coarsen %ld oversized points.\n", remptlist->objects);
23737  }
23738  }
23739 
23740  // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
23741  if (in->pointmarkerlist != NULL) {
23742  long bak_count = remptlist->objects;
23743  points->traversalinit();
23744  ptloop = pointtraverse();
23745  int index = 0;
23746  while (ptloop != NULL) {
23747  if (index < in->numberofpoints) {
23748  if (in->pointmarkerlist[index] == -1) {
23749  pinfect(ptloop);
23750  remptlist->newindex((void **) &parypt);
23751  *parypt = ptloop;
23752  }
23753  } else {
23754  // Remaining are not input points. Stop here.
23755  break;
23756  }
23757  index++;
23758  ptloop = pointtraverse();
23759  }
23760  if (b->verbose > 1) {
23761  printf(" Coarsen %ld marked points.\n", remptlist->objects - bak_count);
23762  }
23763  } // if (in->pointmarkerlist != NULL)
23764 
23765  if (b->coarsen_param > 0) { // -R1/#
23766  // Remove a coarsen_percent number of interior points.
23767  assert((b->coarsen_percent > 0) && (b->coarsen_percent <= 1.0));
23768  if (b->verbose > 1) {
23769  printf(" Coarsen %g percent of interior points.\n",
23770  b->coarsen_percent * 100.0);
23771  }
23772  arraypool *intptlist = new arraypool(sizeof(point *), 10);
23773  // Count the total number of interior points.
23774  points->traversalinit();
23775  ptloop = pointtraverse();
23776  while (ptloop != NULL) {
23777  vt = pointtype(ptloop);
23778  if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) ||
23779  (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
23780  intptlist->newindex((void **) &parypt);
23781  *parypt = ptloop;
23782  }
23783  ptloop = pointtraverse();
23784  }
23785  if (intptlist->objects > 0l) {
23786  // Sort the list of points randomly.
23787  point *parypt_i, swappt;
23788  int randindex, i;
23789  srand(intptlist->objects);
23790  for (i = 0; i < intptlist->objects; i++) {
23791  randindex = rand() % (i + 1); // randomnation(i + 1);
23792  parypt_i = (point *) fastlookup(intptlist, i);
23793  parypt = (point *) fastlookup(intptlist, randindex);
23794  // Swap this two points.
23795  swappt = *parypt_i;
23796  *parypt_i = *parypt;
23797  *parypt = swappt;
23798  }
23799  int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
23800  // Return the first remcount points.
23801  for (i = 0; i < remcount; i++) {
23802  parypt_i = (point *) fastlookup(intptlist, i);
23803  if (!pinfected(*parypt_i)) {
23804  pinfected(*parypt_i);
23805  remptlist->newindex((void **) &parypt);
23806  *parypt = *parypt_i;
23807  }
23808  }
23809  }
23810  delete intptlist;
23811  }
23812 
23813  // Unmark all collected vertices.
23814  for (int i = 0; i < remptlist->objects; i++) {
23815  parypt = (point *) fastlookup(remptlist, i);
23816  puninfect(*parypt);
23817  }
23818 }
23819 
23821 {
23822  arraypool *remptlist;
23823 
23824  if (!b->quiet) {
23825  printf("Mesh coarsening ...\n");
23826  }
23827 
23828  // Collect the set of points to be removed
23829  remptlist = new arraypool(sizeof(point *), 10);
23830  collectremovepoints(remptlist);
23831 
23832  if (remptlist->objects == 0l) {
23833  delete remptlist;
23834  return;
23835  }
23836 
23837  if (b->verbose) {
23838  if (remptlist->objects > 0l) {
23839  printf(" Removing %ld points...\n", remptlist->objects);
23840  }
23841  }
23842 
23843  point *parypt, *plastpt;
23844  long ms = remptlist->objects;
23845  int nit = 0;
23846  int bak_fliplinklevel = b->fliplinklevel;
23847  b->fliplinklevel = -1;
23848  autofliplinklevel = 1; // Init value.
23849  int i;
23850 
23851  while (1) {
23852 
23853  if (b->verbose > 1) {
23854  printf(" Removing points [%s level = %2d] #: %ld.\n",
23855  (b->fliplinklevel > 0) ? "fixed" : "auto",
23857  remptlist->objects);
23858  }
23859 
23860  // Remove the list of points.
23861  for (i = 0; i < remptlist->objects; i++) {
23862  parypt = (point *) fastlookup(remptlist, i);
23863  assert(pointtype(*parypt) != UNUSEDVERTEX);
23864  if (removevertexbyflips(*parypt)) {
23865  // Move the last entry to the current place.
23866  plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
23867  *parypt = *plastpt;
23868  remptlist->objects--;
23869  i--;
23870  }
23871  }
23872 
23873  if (remptlist->objects > 0l) {
23874  if (b->fliplinklevel >= 0) {
23875  break; // We have tried all levels.
23876  }
23877  if (remptlist->objects == ms) {
23878  nit++;
23879  if (nit >= 3) {
23880  // Do the last round with unbounded flip link level.
23881  b->fliplinklevel = 100000;
23882  }
23883  } else {
23884  ms = remptlist->objects;
23885  if (nit > 0) {
23886  nit--;
23887  }
23888  }
23890  } else {
23891  // All points are removed.
23892  break;
23893  }
23894  } // while (1)
23895 
23896  if (remptlist->objects > 0l) {
23897  if (b->verbose) {
23898  printf(" %ld points are not removed !\n", remptlist->objects);
23899  }
23900  }
23901 
23902  b->fliplinklevel = bak_fliplinklevel;
23903  delete remptlist;
23904 }
23905 
23909 
23913 
23915 // //
23916 // makefacetverticesmap() Create a map from facet to its vertices. //
23917 // //
23918 // All facets will be indexed (starting from 0). The map is saved in two //
23919 // global arrays: 'idx2facetlist' and 'facetverticeslist'. //
23920 // //
23922 
23924 {
23925  arraypool *facetvertexlist, *vertlist, **paryvertlist;
23926  face subloop, neighsh, *parysh, *parysh1;
23927  point pa, *ppt, *parypt;
23928  verttype vt;
23929  int facetindex, totalvertices;
23930  int i, j, k;
23931 
23932  if (b->verbose) {
23933  printf(" Creating the facet vertices map.\n");
23934  }
23935 
23936  facetvertexlist = new arraypool(sizeof(arraypool *), 10);
23937  facetindex = totalvertices = 0;
23938 
23940  subloop.sh = shellfacetraverse(subfaces);
23941  while (subloop.sh != NULL) {
23942  if (!sinfected(subloop)) {
23943  // A new facet. Create its vertices list.
23944  vertlist = new arraypool(sizeof(point *), 8);
23945  ppt = (point *) &(subloop.sh[3]);
23946  for (k = 0; k < 3; k++) {
23947  vt = pointtype(ppt[k]);
23948  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
23949  pinfect(ppt[k]);
23950  vertlist->newindex((void **) &parypt);
23951  *parypt = ppt[k];
23952  }
23953  }
23954  sinfect(subloop);
23955  caveshlist->newindex((void **) &parysh);
23956  *parysh = subloop;
23957  for (i = 0; i < caveshlist->objects; i++) {
23958  parysh = (face *) fastlookup(caveshlist, i);
23959  setfacetindex(*parysh, facetindex);
23960  for (j = 0; j < 3; j++) {
23961  if (!isshsubseg(*parysh)) {
23962  spivot(*parysh, neighsh);
23963  assert(neighsh.sh != NULL);
23964  if (!sinfected(neighsh)) {
23965  pa = sapex(neighsh);
23966  if (!pinfected(pa)) {
23967  vt = pointtype(pa);
23968  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
23969  pinfect(pa);
23970  vertlist->newindex((void **) &parypt);
23971  *parypt = pa;
23972  }
23973  }
23974  sinfect(neighsh);
23975  caveshlist->newindex((void **) &parysh1);
23976  *parysh1 = neighsh;
23977  }
23978  }
23979  senextself(*parysh);
23980  }
23981  } // i
23982  totalvertices += (int) vertlist->objects;
23983  // Uninfect facet vertices.
23984  for (k = 0; k < vertlist->objects; k++) {
23985  parypt = (point *) fastlookup(vertlist, k);
23986  puninfect(*parypt);
23987  }
23988  caveshlist->restart();
23989  // Save this vertex list.
23990  facetvertexlist->newindex((void **) &paryvertlist);
23991  *paryvertlist = vertlist;
23992  facetindex++;
23993  }
23994  subloop.sh = shellfacetraverse(subfaces);
23995  }
23996 
23997  // All subfaces are infected. Uninfect them.
23999  subloop.sh = shellfacetraverse(subfaces);
24000  while (subloop.sh != NULL) {
24001  assert(sinfected(subloop));
24002  suninfect(subloop);
24003  subloop.sh = shellfacetraverse(subfaces);
24004  }
24005 
24006  if (b->verbose) {
24007  printf(" Found %ld facets.\n", facetvertexlist->objects);
24008  }
24009 
24010  idx2facetlist = new int[facetindex + 1];
24011  facetverticeslist = new point[totalvertices];
24012 
24013  totalworkmemory += ((facetindex + 1) * sizeof(int) +
24014  totalvertices * sizeof(point *));
24015 
24016  idx2facetlist[0] = 0;
24017  for (i = 0, k = 0; i < facetindex; i++) {
24018  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24019  vertlist = *paryvertlist;
24020  idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
24021  for (j = 0; j < vertlist->objects; j++) {
24022  parypt = (point *) fastlookup(vertlist, j);
24023  facetverticeslist[k] = *parypt;
24024  k++;
24025  }
24026  }
24027  assert(k == totalvertices);
24028 
24029  // Free the lists.
24030  for (i = 0; i < facetvertexlist->objects; i++) {
24031  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24032  vertlist = *paryvertlist;
24033  delete vertlist;
24034  }
24035  delete facetvertexlist;
24036 }
24037 
24039 // //
24040 // Check whether two segments, or a segment and a facet, or two facets are //
24041 // adjacent to each other. //
24042 // //
24044 
24046 {
24047  int segidx1 = getfacetindex(*seg1);
24048  int segidx2 = getfacetindex(*seg2);
24049 
24050  if (segidx1 == segidx2) return 0;
24051 
24052  point pa1 = segmentendpointslist[segidx1 * 2];
24053  point pb1 = segmentendpointslist[segidx1 * 2 + 1];
24054  point pa2 = segmentendpointslist[segidx2 * 2];
24055  point pb2 = segmentendpointslist[segidx2 * 2 + 1];
24056 
24057  if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
24058  return 1;
24059  }
24060  return 0;
24061 }
24062 
24064 {
24065  int segidx = getfacetindex(*subseg);
24066  point pa = segmentendpointslist[segidx * 2];
24067  point pb = segmentendpointslist[segidx * 2 + 1];
24068 
24069  pinfect(pa);
24070  pinfect(pb);
24071 
24072  int fidx = getfacetindex(*subsh);
24073  int count = 0, i;
24074 
24075  for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
24076  if (pinfected(facetverticeslist[i])) count++;
24077  }
24078 
24079  puninfect(pa);
24080  puninfect(pb);
24081 
24082  return count == 1;
24083 }
24084 
24086 {
24087  int count = 0, i;
24088 
24089  int fidx1 = getfacetindex(*subsh1);
24090  int fidx2 = getfacetindex(*subsh2);
24091 
24092  if (fidx1 == fidx2) return 0;
24093 
24094  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24096  }
24097 
24098  for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
24099  if (pinfected(facetverticeslist[i])) count++;
24100  }
24101 
24102  // Uninfect the vertices.
24103  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24105  }
24106 
24107  return count > 0;
24108 }
24109 
24111 // //
24112 // checkseg4encroach() Check if an edge is encroached upon by a point. //
24113 // //
24115 
24117 {
24118  // Check if the point lies inside the diametrical sphere of this seg.
24119  REAL v1[3], v2[3];
24120 
24121  v1[0] = pa[0] - checkpt[0];
24122  v1[1] = pa[1] - checkpt[1];
24123  v1[2] = pa[2] - checkpt[2];
24124  v2[0] = pb[0] - checkpt[0];
24125  v2[1] = pb[1] - checkpt[1];
24126  v2[2] = pb[2] - checkpt[2];
24127 
24128  if (dot(v1, v2) < 0) {
24129  // Inside.
24130  if (b->metric) { // -m option.
24131  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
24132  // The projection of 'checkpt' lies inside the segment [a,b].
24133  REAL prjpt[3], u, v, t;
24134  projpt2edge(checkpt, pa, pb, prjpt);
24135  // Interoplate the mesh size at the location 'prjpt'.
24136  u = distance(pa, pb);
24137  v = distance(pa, prjpt);
24138  t = v / u;
24139  // 'u' is the mesh size at 'prjpt'
24140  u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
24141  v = distance(checkpt, prjpt);
24142  if (v < u) {
24143  return 1; // Encroached prot-ball!
24144  }
24145  } else {
24146  return 1; // NO protecting ball. Encroached.
24147  }
24148  } else {
24149  return 1; // Inside! Encroached.
24150  }
24151  }
24152 
24153  return 0;
24154 }
24155 
24157 // //
24158 // checkseg4split() Check if we need to split a segment. //
24159 // //
24160 // A segment needs to be split if it is in the following case: //
24161 // (1) It is encroached by an existing vertex. //
24162 // (2) It has bad quality (too long). //
24163 // (3) Its length is larger than the mesh sizes at its endpoints. //
24164 // //
24165 // Return 1 if it needs to be split, otherwise, return 0. 'pencpt' returns //
24166 // an encroaching point if there exists. 'qflag' returns '1' if the segment //
24167 // has a length larger than the desired edge length. //
24168 // //
24170 
24171 int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
24172 {
24173  REAL ccent[3], len, r;
24174  int i;
24175 
24176  point forg = sorg(*chkseg);
24177  point fdest = sdest(*chkseg);
24178 
24179  // Initialize the return values.
24180  encpt = NULL;
24181  qflag = 0;
24182 
24183  len = distance(forg, fdest);
24184  r = 0.5 * len;
24185  for (i = 0; i < 3; i++) {
24186  ccent[i] = 0.5 * (forg[i] + fdest[i]);
24187  }
24188 
24189  // First check its quality.
24190  if (checkconstraints && (areabound(*chkseg) > 0.0)) {
24191  if (len > areabound(*chkseg)) {
24192  qflag = 1;
24193  return 1;
24194  }
24195  }
24196 
24197  if (b->fixedvolume) {
24198  if ((len * len * len) > b->maxvolume) {
24199  qflag = 1;
24200  return 1;
24201  }
24202  }
24203 
24204  if (b->metric) { // -m option. Check mesh size.
24205  // Check if the ccent lies outside one of the prot.balls at vertices.
24206  if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
24207  ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
24208  qflag = 1; // Enforce mesh size.
24209  return 1;
24210  }
24211  }
24212 
24213 
24214  // Second check if it is encroached.
24215  // Comment: There may exist more than one encroaching points of this segment.
24216  // The 'encpt' returns the one which is closet to it.
24217  triface searchtet, spintet;
24218  point eapex;
24219  REAL d, diff, smdist = 0;
24220  int t1ver;
24221 
24222  sstpivot1(*chkseg, searchtet);
24223  spintet = searchtet;
24224  while (1) {
24225  eapex = apex(spintet);
24226  if (eapex != dummypoint) {
24227  d = distance(ccent, eapex);
24228  diff = d - r;
24229  if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
24230  if (diff < 0) {
24231  // This segment is encroached by eapex.
24232  if (useinsertradius) {
24233  if (encpt == NULL) {
24234  encpt = eapex;
24235  smdist = d;
24236  } else {
24237  // Choose the closet encroaching point.
24238  if (d < smdist) {
24239  encpt = eapex;
24240  smdist = d;
24241  }
24242  }
24243  } else {
24244  encpt = eapex;
24245  break;
24246  }
24247  }
24248  }
24249  fnextself(spintet);
24250  if (spintet.tet == searchtet.tet) break;
24251  } // while (1)
24252 
24253  if (encpt != NULL) {
24254  return 1;
24255  }
24256 
24257  return 0; // No need to split it.
24258 }
24259 
24261 // //
24262 // splitsegment() Split a segment. //
24263 // //
24264 // The segment 'splitseg' is intended to be split. It will be split if it //
24265 // is in one of the following cases: //
24266 // (1) It is encroached by an existing vertex 'encpt != NULL'; or //
24267 // (2) It is in bad quality 'qflag == 1'; or //
24268 // (3) Its length is larger than the mesh sizes at its endpoints. //
24269 // //
24271 
24272 int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp,
24273  point encpt1, point encpt2, int qflag,
24274  int chkencflag)
24275 {
24276  point pa = sorg(*splitseg);
24277  point pb = sdest(*splitseg);
24278 
24279 
24280 
24281  if ((encpt == NULL) && (qflag == 0)) {
24282  if (useinsertradius) {
24283  // Do not split this segment if the length is smaller than the smaller
24284  // insertion radius at its endpoints.
24285  REAL len = distance(pa, pb);
24286  REAL smrrv = getpointinsradius(pa);
24287  REAL rrv = getpointinsradius(pb);
24288  if (rrv > 0) {
24289  if (smrrv > 0) {
24290  if (rrv < smrrv) {
24291  smrrv = rrv;
24292  }
24293  } else {
24294  smrrv = rrv;
24295  }
24296  }
24297  if (smrrv > 0) {
24298  if ((fabs(smrrv - len) / len) < b->epsilon) smrrv = len;
24299  if (len < smrrv) {
24300  return 0;
24301  }
24302  }
24303  }
24304  }
24305 
24306  if (b->nobisect) { // With -Y option.
24307  // Only split this segment if it is allowed to be split.
24308  if (checkconstraints) {
24309  // Check if it has a non-zero length bound.
24310  if (areabound(*splitseg) == 0) {
24311  // It is not allowed. However, if all of facets containing this seg
24312  // is allowed to be split, we still split it.
24313  face parentsh, spinsh;
24314  //splitseg.shver = 0;
24315  spivot(*splitseg, parentsh);
24316  if (parentsh.sh == NULL) {
24317  return 0; // A dangling segment. Do not split it.
24318  }
24319  spinsh = parentsh;
24320  while (1) {
24321  if (areabound(spinsh) == 0) break;
24322  spivotself(spinsh);
24323  if (spinsh.sh == parentsh.sh) break;
24324  }
24325  if (areabound(spinsh) == 0) {
24326  // All facets at this seg are not allowed to be split.
24327  return 0; // Do not split it.
24328  }
24329  }
24330  } else {
24331  return 0; // Do not split this segment.
24332  }
24333  } // if (b->nobisect)
24334 
24335  triface searchtet;
24336  face searchsh;
24337  point newpt;
24338  insertvertexflags ivf;
24339 
24340  makepoint(&newpt, FREESEGVERTEX);
24341  getsteinerptonsegment(splitseg, encpt, newpt);
24342 
24343  // Split the segment by the Bowyer-Watson algorithm.
24344  sstpivot1(*splitseg, searchtet);
24345  ivf.iloc = (int) ONEDGE;
24346  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24347  ivf.bowywat = 3;
24348  ivf.validflag = 1; // Validate the B-W cavity.
24349  ivf.lawson = 2; // Do flips to recover Delaunayness.
24350  ivf.rejflag = 0; // Do not check encroachment of new segments/facets.
24351  if (b->metric) {
24352  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
24353  }
24354  ivf.chkencflag = chkencflag;
24355  ivf.sloc = (int) INSTAR; // ivf.iloc;
24356  ivf.sbowywat = 3; // ivf.bowywat; // Surface mesh options.
24357  ivf.splitbdflag = 1;
24358  ivf.respectbdflag = 1;
24359  ivf.assignmeshsize = b->metric;
24360  ivf.smlenflag = useinsertradius;
24361 
24362 
24363  if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
24364  st_segref_count++;
24365  if (steinerleft > 0) steinerleft--;
24366  if (useinsertradius) {
24367  // Update 'rv' (to be the shortest distance).
24368  REAL rv = ivf.smlen, rp;
24369  if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
24370  face parentseg1, parentseg2;
24371  sdecode(point2sh(newpt), parentseg1);
24372  sdecode(point2sh(ivf.parentpt), parentseg2);
24373  if (segsegadjacent(&parentseg1, &parentseg2)) {
24374  rp = getpointinsradius(ivf.parentpt);
24375  if (rv < rp) {
24376  rv = rp; // The relaxed insertion radius of 'newpt'.
24377  }
24378  }
24379  } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
24380  face parentseg, parentsh;
24381  sdecode(point2sh(newpt), parentseg);
24382  sdecode(point2sh(ivf.parentpt), parentsh);
24383  if (segfacetadjacent(&parentseg, &parentsh)) {
24384  rp = getpointinsradius(ivf.parentpt);
24385  if (rv < rp) {
24386  rv = rp; // The relaxed insertion radius of 'newpt'.
24387  }
24388  }
24389  }
24390  setpointinsradius(newpt, rv);
24391  }
24392  if (flipstack != NULL) {
24393  flipconstraints fc;
24394  fc.chkencflag = chkencflag;
24395  fc.enqflag = 2;
24396  lawsonflip3d(&fc);
24397  unflipqueue->restart();
24398  }
24399  return 1;
24400  } else {
24401  // Point is not inserted.
24402  pointdealloc(newpt);
24403  return 0;
24404  }
24405 }
24406 
24408 // //
24409 // repairencsegs() Repair encroached (sub) segments. //
24410 // //
24412 
24413 void tetgenmesh::repairencsegs(int chkencflag)
24414 {
24415  face *bface;
24416  point encpt = NULL;
24417  int qflag = 0;
24418 
24419  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
24420  // if an unlimited number of Steiner points is allowed.
24421  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
24423  bface = (face *) badsubsegs->traverse();
24424  while ((bface != NULL) && (steinerleft != 0)) {
24425  // Skip a deleleted element.
24426  if (bface->shver >= 0) {
24427  // A queued segment may have been deleted (split).
24428  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24429  // A queued segment may have been processed.
24430  if (smarktest2ed(*bface)) {
24431  sunmarktest2(*bface);
24432  if (checkseg4split(bface, encpt, qflag)) {
24433  splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
24434  }
24435  }
24436  }
24437  // Remove this entry from list.
24438  bface->shver = -1; // Signal it as a deleted element.
24439  badsubsegs->dealloc((void *) bface);
24440  }
24441  bface = (face *) badsubsegs->traverse();
24442  }
24443  }
24444 
24445  if (badsubsegs->items > 0) {
24446  if (steinerleft == 0) {
24447  if (b->verbose) {
24448  printf("The desired number of Steiner points is reached.\n");
24449  }
24450  } else {
24451  assert(0); // Unknown case.
24452  }
24454  bface = (face *) badsubsegs->traverse();
24455  while (bface != NULL) {
24456  // Skip a deleleted element.
24457  if (bface->shver >= 0) {
24458  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24459  if (smarktest2ed(*bface)) {
24460  sunmarktest2(*bface);
24461  }
24462  }
24463  }
24464  bface = (face *) badsubsegs->traverse();
24465  }
24466  badsubsegs->restart();
24467  }
24468 }
24469 
24471 // //
24472 // enqueuesubface() Queue a subface or a subsegment for encroachment chk. //
24473 // //
24475 
24477 {
24478  if (!smarktest2ed(*chkface)) {
24479  smarktest2(*chkface); // Only queue it once.
24480  face *queface = (face *) pool->alloc();
24481  *queface = *chkface;
24482  }
24483 }
24484 
24486 // //
24487 // checkfac4encroach() Check if a subface is encroached by a point. //
24488 // //
24490 
24492  REAL* cent, REAL* r)
24493 {
24494  REAL rd, len;
24495 
24496  circumsphere(pa, pb, pc, NULL, cent, &rd);
24497  assert(rd != 0);
24498  len = distance(cent, checkpt);
24499  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
24500 
24501  if (len < rd) {
24502  // The point lies inside the circumsphere of this face.
24503  if (b->metric) { // -m option.
24504  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
24505  (pc[pointmtrindex] > 0)) {
24506  // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
24507  REAL prjpt[3], n[3];
24508  REAL a, a1, a2, a3;
24509  projpt2face(checkpt, pa, pb, pc, prjpt);
24510  // Get the face area of [a,b,c].
24511  facenormal(pa, pb, pc, n, 1, NULL);
24512  a = sqrt(dot(n,n));
24513  // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
24514  facenormal(pa, pb, prjpt, n, 1, NULL);
24515  a1 = sqrt(dot(n,n));
24516  facenormal(pb, pc, prjpt, n, 1, NULL);
24517  a2 = sqrt(dot(n,n));
24518  facenormal(pc, pa, prjpt, n, 1, NULL);
24519  a3 = sqrt(dot(n,n));
24520  if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
24521  // This face contains the projection.
24522  // Get the mesh size at the location of the projection point.
24523  rd = a1 / a * pc[pointmtrindex]
24524  + a2 / a * pa[pointmtrindex]
24525  + a3 / a * pb[pointmtrindex];
24526  len = distance(prjpt, checkpt);
24527  if (len < rd) {
24528  return 1; // Encroached.
24529  }
24530  }
24531  } else {
24532  return 1; // No protecting ball. Encroached.
24533  }
24534  } else {
24535  *r = rd;
24536  return 1; // Encroached.
24537  }
24538  }
24539 
24540  return 0;
24541 }
24542 
24544 // //
24545 // checkfac4split() Check if a subface needs to be split. //
24546 // //
24547 // A subface needs to be split if it is in the following case: //
24548 // (1) It is encroached by an existing vertex. //
24549 // (2) It has bad quality (has a small angle, -q). //
24550 // (3) It's area is larger than a prescribed value (.var). //
24551 // //
24552 // Return 1 if it needs to be split, otherwise, return 0. //
24553 // 'chkfac' represents its longest edge. //
24554 // //
24556 
24557 int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
24558  REAL *cent)
24559 {
24560  point pa, pb, pc;
24561  REAL area, rd, len;
24562  REAL A[4][4], rhs[4], D;
24563  int indx[4];
24564  int i;
24565 
24566  encpt = NULL;
24567  qflag = 0;
24568 
24569  pa = sorg(*chkfac);
24570  pb = sdest(*chkfac);
24571  pc = sapex(*chkfac);
24572 
24573  // Compute the coefficient matrix A (3x3).
24574  A[0][0] = pb[0] - pa[0];
24575  A[0][1] = pb[1] - pa[1];
24576  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
24577  A[1][0] = pc[0] - pa[0];
24578  A[1][1] = pc[1] - pa[1];
24579  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
24580  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
24581 
24582  area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
24583 
24584  // Compute the right hand side vector b (3x1).
24585  rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
24586  rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
24587  rhs[2] = 0.0;
24588 
24589  // Solve the 3 by 3 equations use LU decomposition with partial
24590  // pivoting and backward and forward substitute.
24591  if (!lu_decmp(A, 3, indx, &D, 0)) {
24592  // A degenerate triangle.
24593  assert(0);
24594  }
24595 
24596  lu_solve(A, 3, indx, rhs, 0);
24597  cent[0] = pa[0] + rhs[0];
24598  cent[1] = pa[1] + rhs[1];
24599  cent[2] = pa[2] + rhs[2];
24600  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
24601 
24602  if (checkconstraints && (areabound(*chkfac) > 0.0)) {
24603  // Check if the subface has too big area.
24604  if (area > areabound(*chkfac)) {
24605  qflag = 1;
24606  return 1;
24607  }
24608  }
24609 
24610  if (b->fixedvolume) {
24611  if ((area * sqrt(area)) > b->maxvolume) {
24612  qflag = 1;
24613  return 1;
24614  }
24615  }
24616 
24617  if (b->varvolume) {
24618  triface adjtet;
24619  REAL volbnd;
24620  int t1ver;
24621 
24622  stpivot(*chkfac, adjtet);
24623  if (!ishulltet(adjtet)) {
24624  volbnd = volumebound(adjtet.tet);
24625  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
24626  qflag = 1;
24627  return 1;
24628  }
24629  }
24630  fsymself(adjtet);
24631  if (!ishulltet(adjtet)) {
24632  volbnd = volumebound(adjtet.tet);
24633  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
24634  qflag = 1;
24635  return 1;
24636  }
24637  }
24638  }
24639 
24640  if (b->metric) { // -m option. Check mesh size.
24641  // Check if the ccent lies outside one of the prot.balls at vertices.
24642  if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
24643  ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
24644  ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
24645  qflag = 1; // Enforce mesh size.
24646  return 1;
24647  }
24648  }
24649 
24650  triface searchtet;
24651  REAL smlen = 0;
24652 
24653  // Check if this subface is locally encroached.
24654  for (i = 0; i < 2; i++) {
24655  stpivot(*chkfac, searchtet);
24656  if (!ishulltet(searchtet)) {
24657  len = distance(oppo(searchtet), cent);
24658  if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
24659  if (len < rd) {
24660  if (smlen == 0) {
24661  smlen = len;
24662  encpt = oppo(searchtet);
24663  } else {
24664  if (len < smlen) {
24665  smlen = len;
24666  encpt = oppo(searchtet);
24667  }
24668  }
24669  //return 1;
24670  }
24671  }
24672  sesymself(*chkfac);
24673  }
24674 
24675  return encpt != NULL; //return 0;
24676 }
24677 
24679 // //
24680 // splitsubface() Split a subface. //
24681 // //
24682 // The subface may be encroached, or in bad-quality. It is split at its cir- //
24683 // cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg- //
24684 // ment. Instead, one of the encroached segments is split. It is possible //
24685 // that none of the encroached segments can be split. //
24686 // //
24687 // The return value indicates whether a new point is inserted (> 0) or not //
24688 // (= 0). Furthermore, it is inserted on an encroached segment (= 1) or //
24689 // in-side the facet (= 2). //
24690 // //
24691 // 'encpt' is a vertex encroaching upon this subface, i.e., it causes the //
24692 // split of this subface. If 'encpt' is NULL, then the cause of the split //
24693 // this subface is a rejected tet circumcenter 'p', and 'encpt1' is the //
24694 // parent of 'p'. //
24695 // //
24697 
24698 int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1,
24699  int qflag, REAL *ccent, int chkencflag)
24700 {
24701  point pa = sorg(*splitfac);
24702  point pb = sdest(*splitfac);
24703  point pc = sapex(*splitfac);
24704 
24705 
24706 
24707  if (b->nobisect) { // With -Y option.
24708  if (checkconstraints) {
24709  // Only split if it is allowed to be split.
24710  // Check if this facet has a non-zero constraint.
24711  if (areabound(*splitfac) == 0) {
24712  return 0; // Do not split it.
24713  }
24714  } else {
24715  return 0;
24716  }
24717  } // if (b->nobisect)
24718 
24719  face searchsh;
24720  insertvertexflags ivf;
24721  point newpt;
24722  REAL rv = 0., rp; // Insertion radius of newpt.
24723  int i;
24724 
24725  // Initialize the inserting point.
24726  makepoint(&newpt, FREEFACETVERTEX);
24727  // Split the subface at its circumcenter.
24728  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
24729 
24730  if (useinsertradius) {
24731  if (encpt != NULL) {
24732  rv = distance(newpt, encpt);
24733  if (pointtype(encpt) == FREESEGVERTEX) {
24734  face parentseg;
24735  sdecode(point2sh(encpt), parentseg);
24736  if (segfacetadjacent(&parentseg, splitfac)) {
24737  rp = getpointinsradius(encpt);
24738  if (rv < (sqrt(2.0) * rp)) {
24739  // This insertion may cause no termination.
24740  pointdealloc(newpt);
24741  return 0; // Reject the insertion of newpt.
24742  }
24743  }
24744  } else if (pointtype(encpt) == FREEFACETVERTEX) {
24745  face parentsh;
24746  sdecode(point2sh(encpt), parentsh);
24747  if (facetfacetadjacent(&parentsh, splitfac)) {
24748  rp = getpointinsradius(encpt);
24749  if (rv < rp) {
24750  pointdealloc(newpt);
24751  return 0; // Reject the insertion of newpt.
24752  }
24753  }
24754  }
24755  }
24756  } // if (useinsertradius)
24757 
24758  // Search a subface which contains 'newpt'.
24759  searchsh = *splitfac;
24760  // Calculate an above point. It lies above the plane containing
24761  // the subface [a,b,c], and save it in dummypoint. Moreover,
24762  // the vector cent->dummypoint is the normal of the plane.
24763  calculateabovepoint4(newpt, pa, pb, pc);
24764  // Parameters: 'aflag' = 1, - above point exists.
24765  // 'cflag' = 0, - non-convex, check co-planarity of the result.
24766  // 'rflag' = 0, - no need to round the locating result.
24767  ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
24768 
24769  if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
24770  pointdealloc(newpt);
24771  return 0;
24772  }
24773 
24774 
24775  triface searchtet;
24776  face *paryseg;
24777  int splitflag;
24778 
24779  // Insert the point.
24780  stpivot(searchsh, searchtet);
24781  //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE));
24782  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24783  ivf.bowywat = 3;
24784  ivf.lawson = 2;
24785  ivf.rejflag = 1; // Do check the encroachment of segments.
24786  if (b->metric) {
24787  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
24788  }
24789  ivf.chkencflag = chkencflag;
24790  ivf.sloc = (int) INSTAR; // ivf.iloc;
24791  ivf.sbowywat = 3; // ivf.bowywat;
24792  ivf.splitbdflag = 1;
24793  ivf.validflag = 1;
24794  ivf.respectbdflag = 1;
24795  ivf.assignmeshsize = b->metric;
24796 
24797  ivf.refineflag = 2;
24798  ivf.refinesh = searchsh;
24799  ivf.smlenflag = useinsertradius; // Update the insertion radius.
24800 
24801 
24802  if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
24803  st_facref_count++;
24804  if (steinerleft > 0) steinerleft--;
24805  if (useinsertradius) {
24806  // Update 'rv' (to be the shortest distance).
24807  rv = ivf.smlen;
24808  if (pointtype(ivf.parentpt) == FREESEGVERTEX) {
24809  face parentseg, parentsh;
24810  sdecode(point2sh(ivf.parentpt), parentseg);
24811  sdecode(point2sh(newpt), parentsh);
24812  if (segfacetadjacent(&parentseg, &parentsh)) {
24813  rp = getpointinsradius(ivf.parentpt);
24814  if (rv < (sqrt(2.0) * rp)) {
24815  rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
24816  }
24817  }
24818  } else if (pointtype(ivf.parentpt) == FREEFACETVERTEX) {
24819  face parentsh1, parentsh2;
24820  sdecode(point2sh(ivf.parentpt), parentsh1);
24821  sdecode(point2sh(newpt), parentsh2);
24822  if (facetfacetadjacent(&parentsh1, &parentsh2)) {
24823  rp = getpointinsradius(ivf.parentpt);
24824  if (rv < rp) {
24825  rv = rp; // The relaxed insertion radius of 'newpt'.
24826  }
24827  }
24828  }
24829  setpointinsradius(newpt, rv);
24830  } // if (useinsertradius)
24831  if (flipstack != NULL) {
24832  flipconstraints fc;
24833  fc.chkencflag = chkencflag;
24834  fc.enqflag = 2;
24835  lawsonflip3d(&fc);
24836  unflipqueue->restart();
24837  }
24838  return 1;
24839  } else {
24840  // Point was not inserted.
24841  pointdealloc(newpt);
24842  if (ivf.iloc == (int) ENCSEGMENT) {
24843  // Select an encroached segment and split it.
24844  splitflag = 0;
24845  for (i = 0; i < encseglist->objects; i++) {
24846  paryseg = (face *) fastlookup(encseglist, i);
24847  if (splitsegment(paryseg, NULL, rv, encpt, encpt1, qflag,
24848  chkencflag | 1)) {
24849  splitflag = 1; // A point is inserted on a segment.
24850  break;
24851  }
24852  }
24853  encseglist->restart();
24854  if (splitflag) {
24855  // Some segments may need to be repaired.
24856  repairencsegs(chkencflag | 1);
24857  // Queue this subface if it is still alive and not queued.
24858  //if ((splitfac->sh != NULL) && (splitfac->sh[3] != NULL)) {
24859  // // Only queue it if 'qflag' is set.
24860  // if (qflag) {
24861  // enqueuesubface(badsubfacs, splitfac);
24862  // }
24863  //}
24864  }
24865  return splitflag;
24866  } else {
24867  return 0;
24868  }
24869  }
24870 }
24871 
24873 // //
24874 // repairencfacs() Repair encroached subfaces. //
24875 // //
24877 
24878 void tetgenmesh::repairencfacs(int chkencflag)
24879 {
24880  face *bface;
24881  point encpt = NULL;
24882  int qflag = 0;
24883  REAL ccent[3];
24884 
24885  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
24886  // if an unlimited number of Steiner points is allowed.
24887  while ((badsubfacs->items > 0) && (steinerleft != 0)) {
24889  bface = (face *) badsubfacs->traverse();
24890  while ((bface != NULL) && (steinerleft != 0)) {
24891  // Skip a deleted element.
24892  if (bface->shver >= 0) {
24893  // A queued subface may have been deleted (split).
24894  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24895  // A queued subface may have been processed.
24896  if (smarktest2ed(*bface)) {
24897  sunmarktest2(*bface);
24898  if (checkfac4split(bface, encpt, qflag, ccent)) {
24899  splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
24900  }
24901  }
24902  }
24903  bface->shver = -1; // Signal it as a deleted element.
24904  badsubfacs->dealloc((void *) bface); // Remove this entry from list.
24905  }
24906  bface = (face *) badsubfacs->traverse();
24907  }
24908  }
24909 
24910  if (badsubfacs->items > 0) {
24911  if (steinerleft == 0) {
24912  if (b->verbose) {
24913  printf("The desired number of Steiner points is reached.\n");
24914  }
24915  } else {
24916  assert(0); // Unknown case.
24917  }
24919  bface = (face *) badsubfacs->traverse();
24920  while (bface != NULL) {
24921  // Skip a deleted element.
24922  if (bface->shver >= 0) {
24923  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
24924  if (smarktest2ed(*bface)) {
24925  sunmarktest2(*bface);
24926  }
24927  }
24928  }
24929  bface = (face *) badsubfacs->traverse();
24930  }
24931  badsubfacs->restart();
24932  }
24933 }
24934 
24936 // //
24937 // enqueuetetrahedron() Queue a tetrahedron for quality check. //
24938 // //
24940 
24942 {
24943  if (!marktest2ed(*chktet)) {
24944  marktest2(*chktet); // Only queue it once.
24945  triface *quetet = (triface *) badtetrahedrons->alloc();
24946  *quetet = *chktet;
24947  }
24948 }
24949 
24951 // //
24952 // checktet4split() Check if the tet needs to be split. //
24953 // //
24955 
24956 int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
24957 {
24958  point pa, pb, pc, pd, *ppt;
24959  REAL vda[3], vdb[3], vdc[3];
24960  REAL vab[3], vbc[3], vca[3];
24961  REAL N[4][3], L[4], cosd[6], elen[6];
24962  REAL maxcosd, vol, volbnd, smlen = 0, rd;
24963  REAL A[4][4], rhs[4], D;
24964  int indx[4];
24965  int i, j;
24966 
24967  if (b->convex) { // -c
24968  // Skip this tet if it lies in the exterior.
24969  if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
24970  return 0;
24971  }
24972  }
24973 
24974  qflag = 0;
24975 
24976  pd = (point) chktet->tet[7];
24977  if (pd == dummypoint) {
24978  return 0; // Do not split a hull tet.
24979  }
24980 
24981  pa = (point) chktet->tet[4];
24982  pb = (point) chktet->tet[5];
24983  pc = (point) chktet->tet[6];
24984 
24985  // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
24986  // Set the matrix A = [vda, vdb, vdc]^T.
24987  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
24988  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
24989  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
24990 
24991  // Get the other edge vectors.
24992  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
24993  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
24994  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
24995 
24996  if (!lu_decmp(A, 3, indx, &D, 0)) {
24997  // A degenerated tet (vol = 0).
24998  // This is possible due to the use of exact arithmetic. We temporarily
24999  // leave this tet. It should be fixed by mesh optimization.
25000  return 0;
25001  }
25002 
25003  // Check volume if '-a#' and '-a' options are used.
25004  if (b->varvolume || b->fixedvolume) {
25005  vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
25006  if (b->fixedvolume) {
25007  if (vol > b->maxvolume) {
25008  qflag = 1;
25009  }
25010  }
25011  if (!qflag && b->varvolume) {
25012  volbnd = volumebound(chktet->tet);
25013  if ((volbnd > 0.0) && (vol > volbnd)) {
25014  qflag = 1;
25015  }
25016  }
25017  if (qflag == 1) {
25018  // Calculate the circumcenter of this tet.
25019  rhs[0] = 0.5 * dot(vda, vda);
25020  rhs[1] = 0.5 * dot(vdb, vdb);
25021  rhs[2] = 0.5 * dot(vdc, vdc);
25022  lu_solve(A, 3, indx, rhs, 0);
25023  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25024  return 1;
25025  }
25026  }
25027 
25028  if (b->metric) { // -m option. Check mesh size.
25029  // Calculate the circumradius of this tet.
25030  rhs[0] = 0.5 * dot(vda, vda);
25031  rhs[1] = 0.5 * dot(vdb, vdb);
25032  rhs[2] = 0.5 * dot(vdc, vdc);
25033  lu_solve(A, 3, indx, rhs, 0);
25034  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25035  rd = sqrt(dot(rhs, rhs));
25036  // Check if the ccent lies outside one of the prot.balls at vertices.
25037  ppt = (point *) &(chktet->tet[4]);
25038  for (i = 0; i < 4; i++) {
25039  if (ppt[i][pointmtrindex] > 0) {
25040  if (rd > ppt[i][pointmtrindex]) {
25041  qflag = 1; // Enforce mesh size.
25042  return 1;
25043  }
25044  }
25045  }
25046  }
25047 
25048  if (in->tetunsuitable != NULL) {
25049  // Execute the user-defined meshing sizing evaluation.
25050  if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
25051  // Calculate the circumcenter of this tet.
25052  rhs[0] = 0.5 * dot(vda, vda);
25053  rhs[1] = 0.5 * dot(vdb, vdb);
25054  rhs[2] = 0.5 * dot(vdc, vdc);
25055  lu_solve(A, 3, indx, rhs, 0);
25056  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25057  return 1;
25058  }
25059  }
25060 
25061  if (useinsertradius) {
25062  // Do not split this tet if the shortest edge is shorter than the
25063  // insertion radius of one of its endpoints.
25064  triface checkedge;
25065  point e1, e2;
25066  REAL rrv, smrrv;
25067 
25068  // Get the shortest edge of this tet.
25069  checkedge.tet = chktet->tet;
25070  for (i = 0; i < 6; i++) {
25071  checkedge.ver = edge2ver[i];
25072  e1 = org(checkedge);
25073  e2 = dest(checkedge);
25074  elen[i] = distance(e1, e2);
25075  if (i == 0) {
25076  smlen = elen[i];
25077  j = 0;
25078  } else {
25079  if (elen[i] < smlen) {
25080  smlen = elen[i];
25081  j = i;
25082  }
25083  }
25084  }
25085  // Check if the edge is too short.
25086  checkedge.ver = edge2ver[j];
25087  // Get the smallest rrv of e1 and e2.
25088  // Note: if rrv of e1 and e2 is zero. Do not use it.
25089  e1 = org(checkedge);
25090  smrrv = getpointinsradius(e1);
25091  e2 = dest(checkedge);
25092  rrv = getpointinsradius(e2);
25093  if (rrv > 0) {
25094  if (smrrv > 0) {
25095  if (rrv < smrrv) {
25096  smrrv = rrv;
25097  }
25098  } else {
25099  smrrv = rrv;
25100  }
25101  }
25102  if (smrrv > 0) {
25103  // To avoid rounding error, round smrrv before doing comparison.
25104  if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
25105  smrrv = smlen;
25106  }
25107  if (smrrv > smlen) {
25108  return 0;
25109  }
25110  }
25111  } // if (useinsertradius)
25112 
25113  // Check the radius-edge ratio. Set by -q#.
25114  if (b->minratio > 0) {
25115  // Calculate the circumcenter and radius of this tet.
25116  rhs[0] = 0.5 * dot(vda, vda);
25117  rhs[1] = 0.5 * dot(vdb, vdb);
25118  rhs[2] = 0.5 * dot(vdc, vdc);
25119  lu_solve(A, 3, indx, rhs, 0);
25120  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25121  rd = sqrt(dot(rhs, rhs));
25122  if (!useinsertradius) {
25123  // Calculate the shortest edge length.
25124  elen[0] = dot(vda, vda);
25125  elen[1] = dot(vdb, vdb);
25126  elen[2] = dot(vdc, vdc);
25127  elen[3] = dot(vab, vab);
25128  elen[4] = dot(vbc, vbc);
25129  elen[5] = dot(vca, vca);
25130  smlen = elen[0]; //sidx = 0;
25131  for (i = 1; i < 6; i++) {
25132  if (smlen > elen[i]) {
25133  smlen = elen[i]; //sidx = i;
25134  }
25135  }
25136  smlen = sqrt(smlen);
25137  }
25138  D = rd / smlen;
25139  if (D > b->minratio) {
25140  // A bad radius-edge ratio.
25141  return 1;
25142  }
25143  }
25144 
25145  // Check the minimum dihedral angle. Set by -qq#.
25146  if (b->mindihedral > 0) {
25147  // Compute the 4 face normals (N[0], ..., N[3]).
25148  for (j = 0; j < 3; j++) {
25149  for (i = 0; i < 3; i++) N[j][i] = 0.0;
25150  N[j][j] = 1.0; // Positive means the inside direction
25151  lu_solve(A, 3, indx, N[j], 0);
25152  }
25153  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
25154  // Normalize the normals.
25155  for (i = 0; i < 4; i++) {
25156  L[i] = sqrt(dot(N[i], N[i]));
25157  assert(L[i] > 0);
25158  //if (L[i] > 0.0) {
25159  for (j = 0; j < 3; j++) N[i][j] /= L[i];
25160  //}
25161  }
25162  // Calculate the six dihedral angles.
25163  cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
25164  cosd[1] = -dot(N[0], N[2]);
25165  cosd[2] = -dot(N[0], N[3]);
25166  cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
25167  cosd[4] = -dot(N[1], N[3]);
25168  cosd[5] = -dot(N[2], N[3]); // Edge ab
25169  // Get the smallest dihedral angle.
25170  //maxcosd = mincosd = cosd[0];
25171  maxcosd = cosd[0];
25172  for (i = 1; i < 6; i++) {
25173  //if (cosd[i] > maxcosd) maxcosd = cosd[i];
25174  maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
25175  //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
25176  }
25177  if (maxcosd > cosmindihed) {
25178  // Calculate the circumcenter of this tet.
25179  // A bad dihedral angle.
25180  //if ((b->quality & 1) == 0) {
25181  rhs[0] = 0.5 * dot(vda, vda);
25182  rhs[1] = 0.5 * dot(vdb, vdb);
25183  rhs[2] = 0.5 * dot(vdc, vdc);
25184  lu_solve(A, 3, indx, rhs, 0);
25185  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25186  //*rd = sqrt(dot(rhs, rhs));
25187  //}
25188  return 1;
25189  }
25190  }
25191 
25192  return 0;
25193 }
25194 
25196 // //
25197 // splittetrahedron() Split a tetrahedron. //
25198 // //
25200 
25201 int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
25202  int chkencflag)
25203 {
25204  triface searchtet;
25205  face *paryseg;
25206  point newpt;
25207  badface *bface;
25208  insertvertexflags ivf;
25209  int splitflag;
25210  int i;
25211 
25212 
25213 
25214  REAL rv = 0.; // Insertion radius of 'newpt'.
25215 
25216  makepoint(&newpt, FREEVOLVERTEX);
25217  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
25218 
25219  if (useinsertradius) {
25220  rv = distance(newpt, org(*splittet));
25221  setpointinsradius(newpt, rv);
25222  }
25223 
25224  searchtet = *splittet;
25225  ivf.iloc = (int) OUTSIDE;
25226  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
25227  ivf.bowywat = 3;
25228  ivf.lawson = 2;
25229  ivf.rejflag = 3; // Do check for encroached segments and subfaces.
25230  if (b->metric) {
25231  ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
25232  }
25233  ivf.chkencflag = chkencflag;
25234  ivf.sloc = ivf.sbowywat = 0; // No use.
25235  ivf.splitbdflag = 0; // No use.
25236  ivf.validflag = 1;
25237  ivf.respectbdflag = 1;
25238  ivf.assignmeshsize = b->metric;
25239 
25240  ivf.refineflag = 1;
25241  ivf.refinetet = *splittet;
25242 
25243 
25244  if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
25245  // Vertex is inserted.
25246  st_volref_count++;
25247  if (steinerleft > 0) steinerleft--;
25248  if (flipstack != NULL) {
25249  flipconstraints fc;
25250  fc.chkencflag = chkencflag;
25251  fc.enqflag = 2;
25252  lawsonflip3d(&fc);
25253  unflipqueue->restart();
25254  }
25255  return 1;
25256  } else {
25257  // Point is not inserted.
25258  pointdealloc(newpt);
25259  // Check if there are encroached segments/subfaces.
25260  if (ivf.iloc == (int) ENCSEGMENT) {
25261  splitflag = 0;
25262  //if (!b->nobisect) { // not -Y option
25263  if (!b->nobisect || checkconstraints) {
25264  // Select an encroached segment and split it.
25265  for (i = 0; i < encseglist->objects; i++) {
25266  paryseg = (face *) fastlookup(encseglist, i);
25267  if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag,
25268  chkencflag | 3)) {
25269  splitflag = 1; // A point is inserted on a segment.
25270  break;
25271  }
25272  }
25273  } // if (!b->nobisect)
25274  encseglist->restart();
25275  if (splitflag) {
25276  // Some segments may need to be repaired.
25277  repairencsegs(chkencflag | 3);
25278  // Some subfaces may need to be repaired.
25279  repairencfacs(chkencflag | 2);
25280  // Queue the tet if it is still alive and not queued.
25281  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
25282  enqueuetetrahedron(splittet);
25283  }
25284  }
25285  return splitflag;
25286  } else if (ivf.iloc == (int) ENCSUBFACE) {
25287  splitflag = 0;
25288  //if (!b->nobisect) { // not -Y option
25289  if (!b->nobisect || checkconstraints) {
25290  // Select an encroached subface and split it.
25291  for (i = 0; i < encshlist->objects; i++) {
25292  bface = (badface *) fastlookup(encshlist, i);
25293  if (splitsubface(&(bface->ss), NULL, org(*splittet), qflag,
25294  bface->cent, chkencflag | 2)){
25295  splitflag = 1; // A point is inserted on a subface or a segment.
25296  break;
25297  }
25298  }
25299  } // if (!b->nobisect)
25300  encshlist->restart();
25301  if (splitflag) {
25302  assert(badsubsegs->items == 0l);
25303  // Some subfaces may need to be repaired.
25304  repairencfacs(chkencflag | 2);
25305  // Queue the tet if it is still alive.
25306  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
25307  enqueuetetrahedron(splittet);
25308  }
25309  }
25310  return splitflag;
25311  }
25312  return 0;
25313  }
25314 }
25315 
25317 // //
25318 // repairbadtets() Repair bad quality tetrahedra. //
25319 // //
25321 
25322 void tetgenmesh::repairbadtets(int chkencflag)
25323 {
25324  triface *bface;
25325  REAL ccent[3];
25326  int qflag = 0;
25327 
25328 
25329  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
25330  // if an unlimited number of Steiner points is allowed.
25331  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
25333  bface = (triface *) badtetrahedrons->traverse();
25334  while ((bface != NULL) && (steinerleft != 0)) {
25335  // Skip a deleted element.
25336  if (bface->ver >= 0) {
25337  // A queued tet may have been deleted.
25338  if (!isdeadtet(*bface)) {
25339  // A queued tet may have been processed.
25340  if (marktest2ed(*bface)) {
25341  unmarktest2(*bface);
25342  if (checktet4split(bface, qflag, ccent)) {
25343  splittetrahedron(bface, qflag, ccent, chkencflag);
25344  }
25345  }
25346  }
25347  bface->ver = -1; // Signal it as a deleted element.
25348  badtetrahedrons->dealloc((void *) bface);
25349  }
25350  bface = (triface *) badtetrahedrons->traverse();
25351  }
25352  }
25353 
25354  if (badtetrahedrons->items > 0) {
25355  if (steinerleft == 0) {
25356  if (b->verbose) {
25357  printf("The desired number of Steiner points is reached.\n");
25358  }
25359  } else {
25360  assert(0); // Unknown case.
25361  }
25362  // Unmark all queued tet.
25364  bface = (triface *) badtetrahedrons->traverse();
25365  while (bface != NULL) {
25366  // Skip a deleted element.
25367  if (bface->ver >= 0) {
25368  if (!isdeadtet(*bface)) {
25369  if (marktest2ed(*bface)) {
25370  unmarktest2(*bface);
25371  }
25372  }
25373  }
25374  bface = (triface *) badtetrahedrons->traverse();
25375  }
25376  // Clear the pool.
25378  }
25379 }
25380 
25382 // //
25383 // delaunayrefinement() Refine the mesh by Delaunay refinement. //
25384 // //
25386 
25388 {
25389  triface checktet;
25390  face checksh;
25391  face checkseg;
25392  long steinercount;
25393  int chkencflag;
25394 
25395  long bak_segref_count, bak_facref_count, bak_volref_count;
25396  long bak_flipcount = flip23count + flip32count + flip44count;
25397 
25398  if (!b->quiet) {
25399  printf("Refining mesh...\n");
25400  }
25401 
25402  if (b->verbose) {
25403  printf(" Min radiu-edge ratio = %g.\n", b->minratio);
25404  printf(" Min dihedral angle = %g.\n", b->mindihedral);
25405  //printf(" Min Edge length = %g.\n", b->minedgelength);
25406  }
25407 
25408  steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#).
25409  if (steinerleft > 0) {
25410  // Check if we've already used up the given number of Steiner points.
25411  steinercount = st_segref_count + st_facref_count + st_volref_count;
25412  if (steinercount < steinerleft) {
25413  steinerleft -= steinercount;
25414  } else {
25415  if (!b->quiet) {
25416  printf("\nWarning: ");
25417  printf("The desired number of Steiner points (%d) has reached.\n\n",
25418  b->steinerleft);
25419  }
25420  return; // No more Steiner points.
25421  }
25422  }
25423 
25424  if (useinsertradius) {
25425  if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
25427  }
25429  }
25430 
25431 
25432  encseglist = new arraypool(sizeof(face), 8);
25433  encshlist = new arraypool(sizeof(badface), 8);
25434 
25435 
25436  //if (!b->nobisect) { // if no '-Y' option
25437  if (!b->nobisect || checkconstraints) {
25438  if (b->verbose) {
25439  printf(" Splitting encroached subsegments.\n");
25440  }
25441 
25442  chkencflag = 1; // Only check encroaching subsegments.
25443  steinercount = points->items;
25444 
25445  // Initialize the pool of encroached subsegments.
25446  badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock,
25447  sizeof(void *), 0);
25448 
25449  // Add all segments into the pool.
25451  checkseg.sh = shellfacetraverse(subsegs);
25452  while (checkseg.sh != (shellface *) NULL) {
25453  enqueuesubface(badsubsegs, &checkseg);
25454  checkseg.sh = shellfacetraverse(subsegs);
25455  }
25456 
25457  // Split all encroached segments.
25458  repairencsegs(chkencflag);
25459 
25460  if (b->verbose) {
25461  printf(" Added %ld Steiner points.\n", points->items - steinercount);
25462  }
25463 
25464  if (b->reflevel > 1) { // '-D2' option
25465  if (b->verbose) {
25466  printf(" Splitting encroached subfaces.\n");
25467  }
25468 
25469  chkencflag = 2; // Only check encroaching subfaces.
25470  steinercount = points->items;
25471  bak_segref_count = st_segref_count;
25472  bak_facref_count = st_facref_count;
25473 
25474  // Initialize the pool of encroached subfaces.
25475  badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock,
25476  sizeof(void *), 0);
25477 
25478  // Add all subfaces into the pool.
25480  checksh.sh = shellfacetraverse(subfaces);
25481  while (checksh.sh != (shellface *) NULL) {
25482  enqueuesubface(badsubfacs, &checksh);
25483  checksh.sh = shellfacetraverse(subfaces);
25484  }
25485 
25486  // Split all encroached subfaces.
25487  repairencfacs(chkencflag);
25488 
25489  if (b->verbose) {
25490  printf(" Added %ld (%ld,%ld) Steiner points.\n",
25491  points->items-steinercount, st_segref_count-bak_segref_count,
25492  st_facref_count-bak_facref_count);
25493  }
25494  } // if (b->reflevel > 1)
25495  } // if (!b->nobisect)
25496 
25497  if (b->reflevel > 2) { // '-D3' option (The default option)
25498  if (b->verbose) {
25499  printf(" Splitting bad quality tets.\n");
25500  }
25501 
25502  chkencflag = 4; // Only check tetrahedra.
25503  steinercount = points->items;
25504  bak_segref_count = st_segref_count;
25505  bak_facref_count = st_facref_count;
25506  bak_volref_count = st_volref_count;
25507 
25508  // The cosine value of the min dihedral angle (-qq) for tetrahedra.
25509  cosmindihed = cos(b->mindihedral / 180.0 * PI);
25510 
25511  // Initialize the pool of bad quality tetrahedra.
25513  sizeof(void *), 0);
25514  // Add all tetrahedra (no hull tets) into the pool.
25516  checktet.tet = tetrahedrontraverse();
25517  while (checktet.tet != NULL) {
25518  enqueuetetrahedron(&checktet);
25519  checktet.tet = tetrahedrontraverse();
25520  }
25521 
25522  // Split all bad quality tetrahedra.
25523  repairbadtets(chkencflag);
25524 
25525  if (b->verbose) {
25526  printf(" Added %ld (%ld,%ld,%ld) Steiner points.\n",
25527  points->items - steinercount,
25528  st_segref_count - bak_segref_count,
25529  st_facref_count - bak_facref_count,
25530  st_volref_count - bak_volref_count);
25531  }
25532  } // if (b->reflevel > 2)
25533 
25534  if (b->verbose) {
25535  if (flip23count + flip32count + flip44count > bak_flipcount) {
25536  printf(" Performed %ld flips.\n", flip23count + flip32count +
25537  flip44count - bak_flipcount);
25538  }
25539  }
25540 
25541  if (steinerleft == 0) {
25542  if (!b->quiet) {
25543  printf("\nWarnning: ");
25544  printf("The desired number of Steiner points (%d) is reached.\n\n",
25545  b->steinerleft);
25546  }
25547  }
25548 
25549 
25550  delete encseglist;
25551  delete encshlist;
25552 
25553  //if (!b->nobisect) {
25554  if (!b->nobisect || checkconstraints) {
25556  delete badsubsegs;
25557  if (b->reflevel > 1) {
25559  delete badsubfacs;
25560  }
25561  }
25562  if (b->reflevel > 2) {
25564  delete badtetrahedrons;
25565  }
25566 }
25567 
25571 
25575 
25577 // //
25578 // lawsonflip3d() A three-dimensional Lawson's algorithm. //
25579 // //
25581 
25583 {
25584  triface fliptets[5], neightet, hulltet;
25585  face checksh, casingout;
25586  badface *popface, *bface;
25587  point pd, pe, *pts;
25588  REAL sign, ori;
25589  long flipcount, totalcount = 0l;
25590  long sliver_peels = 0l;
25591  int t1ver;
25592  int i;
25593 
25594 
25595  while (1) {
25596 
25597  if (b->verbose > 2) {
25598  printf(" Lawson flip %ld faces.\n", flippool->items);
25599  }
25600  flipcount = 0l;
25601 
25602  while (flipstack != (badface *) NULL) {
25603  // Pop a face from the stack.
25604  popface = flipstack;
25605  fliptets[0] = popface->tt;
25606  flipstack = flipstack->nextitem; // The next top item in stack.
25607  flippool->dealloc((void *) popface);
25608 
25609  // Skip it if it is a dead tet (destroyed by previous flips).
25610  if (isdeadtet(fliptets[0])) continue;
25611  // Skip it if it is not the same tet as we saved.
25612  if (!facemarked(fliptets[0])) continue;
25613 
25614  unmarkface(fliptets[0]);
25615 
25616  if (ishulltet(fliptets[0])) continue;
25617 
25618  fsym(fliptets[0], fliptets[1]);
25619  if (ishulltet(fliptets[1])) {
25620  if (nonconvex) {
25621  // Check if 'fliptets[0]' it is a hull sliver.
25622  tspivot(fliptets[0], checksh);
25623  for (i = 0; i < 3; i++) {
25624  if (!isshsubseg(checksh)) {
25625  spivot(checksh, casingout);
25626  //assert(casingout.sh != NULL);
25627  if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
25628  stpivot(casingout, neightet);
25629  if (neightet.tet == fliptets[0].tet) {
25630  // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
25631  // [e,d,a] and [d,e,b] are hull faces.
25632  edestoppo(neightet, hulltet); // [a,b,e,d]
25633  fsymself(hulltet); // [b,a,e,#]
25634  if (oppo(hulltet) == dummypoint) {
25635  pe = org(neightet);
25636  if ((pointtype(pe) == FREEFACETVERTEX) ||
25637  (pointtype(pe) == FREESEGVERTEX)) {
25638  removevertexbyflips(pe);
25639  }
25640  } else {
25641  eorgoppo(neightet, hulltet); // [b,a,d,e]
25642  fsymself(hulltet); // [a,b,d,#]
25643  if (oppo(hulltet) == dummypoint) {
25644  pd = dest(neightet);
25645  if ((pointtype(pd) == FREEFACETVERTEX) ||
25646  (pointtype(pd) == FREESEGVERTEX)) {
25647  removevertexbyflips(pd);
25648  }
25649  } else {
25650  // Perform a 3-to-2 flip to remove the sliver.
25651  fliptets[0] = neightet; // [e,d,a,b]
25652  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
25653  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
25654  flip32(fliptets, 1, fc);
25655  // Update counters.
25656  flip32count--;
25657  flip22count--;
25658  sliver_peels++;
25659  if (fc->remove_ndelaunay_edge) {
25660  // Update the volume (must be decreased).
25661  //assert(fc->tetprism_vol_sum <= 0);
25663  fc->tetprism_vol_sum = 0.0; // Clear it.
25664  }
25665  }
25666  }
25667  break;
25668  } // if (neightet.tet == fliptets[0].tet)
25669  } // if (!isshsubseg(checksh))
25670  senextself(checksh);
25671  } // i
25672  } // if (nonconvex)
25673  continue;
25674  }
25675 
25676  if (checksubfaceflag) {
25677  // Do not flip if it is a subface.
25678  if (issubface(fliptets[0])) continue;
25679  }
25680 
25681  // Test whether the face is locally Delaunay or not.
25682  pts = (point *) fliptets[1].tet;
25683  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
25684 
25685  if (sign < 0) {
25686  // A non-Delaunay face. Try to flip it.
25687  pd = oppo(fliptets[0]);
25688  pe = oppo(fliptets[1]);
25689 
25690  // Check the convexity of its three edges. Stop checking either a
25691  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
25692  // encountered, and 'fliptet' represents that edge.
25693  for (i = 0; i < 3; i++) {
25694  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
25695  if (ori <= 0) break;
25696  enextself(fliptets[0]);
25697  }
25698 
25699  if (ori > 0) {
25700  // A 2-to-3 flip is found.
25701  // [0] [a,b,c,d],
25702  // [1] [b,a,c,e]. no dummypoint.
25703  flip23(fliptets, 0, fc);
25704  flipcount++;
25705  if (fc->remove_ndelaunay_edge) {
25706  // Update the volume (must be decreased).
25707  //assert(fc->tetprism_vol_sum <= 0);
25709  fc->tetprism_vol_sum = 0.0; // Clear it.
25710  }
25711  continue;
25712  } else { // ori <= 0
25713  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
25714  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
25715  if (checksubsegflag) {
25716  // Do not flip if it is a segment.
25717  if (issubseg(fliptets[0])) continue;
25718  }
25719  // Check if there are three or four tets sharing at this edge.
25720  esymself(fliptets[0]); // [b,a,d,c]
25721  for (i = 0; i < 3; i++) {
25722  fnext(fliptets[i], fliptets[i+1]);
25723  }
25724  if (fliptets[3].tet == fliptets[0].tet) {
25725  // A 3-to-2 flip is found. (No hull tet.)
25726  flip32(fliptets, 0, fc);
25727  flipcount++;
25728  if (fc->remove_ndelaunay_edge) {
25729  // Update the volume (must be decreased).
25730  //assert(fc->tetprism_vol_sum <= 0);
25732  fc->tetprism_vol_sum = 0.0; // Clear it.
25733  }
25734  continue;
25735  } else {
25736  // There are more than 3 tets at this edge.
25737  fnext(fliptets[3], fliptets[4]);
25738  if (fliptets[4].tet == fliptets[0].tet) {
25739  // There are exactly 4 tets at this edge.
25740  if (nonconvex) {
25741  if (apex(fliptets[3]) == dummypoint) {
25742  // This edge is locally non-convex on the hull.
25743  // It can be removed by a 4-to-4 flip.
25744  ori = 0;
25745  }
25746  } // if (nonconvex)
25747  if (ori == 0) {
25748  // A 4-to-4 flip is found. (Two hull tets may be involved.)
25749  // Current tets in 'fliptets':
25750  // [0] [b,a,d,c] (d may be newpt)
25751  // [1] [b,a,c,e]
25752  // [2] [b,a,e,f] (f may be dummypoint)
25753  // [3] [b,a,f,d]
25754  esymself(fliptets[0]); // [a,b,c,d]
25755  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
25756  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
25757  // It will be removed by the followed 3-to-2 flip.
25758  flip23(fliptets, 0, fc); // No hull tet.
25759  fnext(fliptets[3], fliptets[1]);
25760  fnext(fliptets[1], fliptets[2]);
25761  // Current tets in 'fliptets':
25762  // [0] [...]
25763  // [1] [b,a,d,e] (degenerated, d may be new point).
25764  // [2] [b,a,e,f] (f may be dummypoint)
25765  // [3] [b,a,f,d]
25766  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
25767  // Hull tets may be involved (f may be dummypoint).
25768  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
25769  flipcount++;
25770  flip23count--;
25771  flip32count--;
25772  flip44count++;
25773  if (fc->remove_ndelaunay_edge) {
25774  // Update the volume (must be decreased).
25775  //assert(fc->tetprism_vol_sum <= 0);
25777  fc->tetprism_vol_sum = 0.0; // Clear it.
25778  }
25779  continue;
25780  } // if (ori == 0)
25781  }
25782  }
25783  } // if (ori <= 0)
25784 
25785  // This non-Delaunay face is unflippable. Save it.
25786  unflipqueue->newindex((void **) &bface);
25787  bface->tt = fliptets[0];
25788  bface->forg = org(fliptets[0]);
25789  bface->fdest = dest(fliptets[0]);
25790  bface->fapex = apex(fliptets[0]);
25791  } // if (sign < 0)
25792  } // while (flipstack)
25793 
25794  if (b->verbose > 2) {
25795  if (flipcount > 0) {
25796  printf(" Performed %ld flips.\n", flipcount);
25797  }
25798  }
25799  // Accumulate the counter of flips.
25800  totalcount += flipcount;
25801 
25802  assert(flippool->items == 0l);
25803  // Return if no unflippable faces left.
25804  if (unflipqueue->objects == 0l) break;
25805  // Return if no flip has been performed.
25806  if (flipcount == 0l) break;
25807 
25808  // Try to flip the unflippable faces.
25809  for (i = 0; i < unflipqueue->objects; i++) {
25810  bface = (badface *) fastlookup(unflipqueue, i);
25811  if (!isdeadtet(bface->tt) &&
25812  (org(bface->tt) == bface->forg) &&
25813  (dest(bface->tt) == bface->fdest) &&
25814  (apex(bface->tt) == bface->fapex)) {
25815  flippush(flipstack, &(bface->tt));
25816  }
25817  }
25818  unflipqueue->restart();
25819 
25820  } // while (1)
25821 
25822  if (b->verbose > 2) {
25823  if (totalcount > 0) {
25824  printf(" Performed %ld flips.\n", totalcount);
25825  }
25826  if (sliver_peels > 0) {
25827  printf(" Removed %ld hull slivers.\n", sliver_peels);
25828  }
25829  if (unflipqueue->objects > 0l) {
25830  printf(" %ld unflippable edges remained.\n", unflipqueue->objects);
25831  }
25832  }
25833 
25834  return totalcount + sliver_peels;
25835 }
25836 
25838 // //
25839 // recoverdelaunay() Recovery the locally Delaunay property. //
25840 // //
25842 
25844 {
25845  arraypool *flipqueue, *nextflipqueue, *swapqueue;
25846  triface tetloop, neightet, *parytet;
25847  badface *bface, *parybface;
25848  point *ppt;
25849  flipconstraints fc;
25850  int i, j;
25851 
25852  if (!b->quiet) {
25853  printf("Recovering Delaunayness...\n");
25854  }
25855 
25856  tetprism_vol_sum = 0.0; // Initialize it.
25857 
25858  // Put all interior faces of the mesh into 'flipstack'.
25860  tetloop.tet = tetrahedrontraverse();
25861  while (tetloop.tet != NULL) {
25862  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
25863  decode(tetloop.tet[tetloop.ver], neightet);
25864  if (!facemarked(neightet)) {
25865  flippush(flipstack, &tetloop);
25866  }
25867  }
25868  ppt = (point *) &(tetloop.tet[4]);
25869  tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
25870  tetloop.tet = tetrahedrontraverse();
25871  }
25872 
25873  // Calulate a relatively lower bound for small improvement.
25874  // Used to avoid rounding error in volume calculation.
25876 
25877  if (b->verbose) {
25878  printf(" Initial obj = %.17g\n", tetprism_vol_sum);
25879  }
25880 
25881  if (b->verbose > 1) {
25882  printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items);
25883  }
25884 
25885  // First only use the basic Lawson's flip.
25886  fc.remove_ndelaunay_edge = 1;
25887  fc.enqflag = 2;
25888 
25889  lawsonflip3d(&fc);
25890 
25891  if (b->verbose > 1) {
25892  printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum);
25893  }
25894 
25895  if (unflipqueue->objects == 0l) {
25896  return; // The mesh is Delaunay.
25897  }
25898 
25899  fc.unflip = 1; // Unflip if the edge is not flipped.
25900  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
25901  fc.enqflag = 0;
25902 
25903  autofliplinklevel = 1; // Init level.
25904  b->fliplinklevel = -1; // No fixed level.
25905 
25906  // For efficiency reason, we limit the maximium size of the edge star.
25907  int bakmaxflipstarsize = b->flipstarsize;
25908  b->flipstarsize = 10; // default
25909 
25910  flipqueue = new arraypool(sizeof(badface), 10);
25911  nextflipqueue = new arraypool(sizeof(badface), 10);
25912 
25913  // Swap the two flip queues.
25914  swapqueue = flipqueue;
25915  flipqueue = unflipqueue;
25916  unflipqueue = swapqueue;
25917 
25918  while (flipqueue->objects > 0l) {
25919 
25920  if (b->verbose > 1) {
25921  printf(" Recover Delaunay [level = %2d] #: %ld.\n",
25922  autofliplinklevel, flipqueue->objects);
25923  }
25924 
25925  for (i = 0; i < flipqueue->objects; i++) {
25926  bface = (badface *) fastlookup(flipqueue, i);
25927  if (getedge(bface->forg, bface->fdest, &bface->tt)) {
25928  if (removeedgebyflips(&(bface->tt), &fc) == 2) {
25930  fc.tetprism_vol_sum = 0.0; // Clear it.
25931  // Queue new faces for flips.
25932  for (j = 0; j < cavetetlist->objects; j++) {
25933  parytet = (triface *) fastlookup(cavetetlist, j);
25934  // A queued new tet may be dead.
25935  if (!isdeadtet(*parytet)) {
25936  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
25937  // Avoid queue a face twice.
25938  decode(parytet->tet[parytet->ver], neightet);
25939  if (!facemarked(neightet)) {
25940  flippush(flipstack, parytet);
25941  }
25942  } // parytet->ver
25943  }
25944  } // j
25945  cavetetlist->restart();
25946  // Remove locally non-Delaunay faces. New non-Delaunay edges
25947  // may be found. They are saved in 'unflipqueue'.
25948  fc.enqflag = 2;
25949  lawsonflip3d(&fc);
25950  fc.enqflag = 0;
25951  // There may be unflipable faces. Add them in flipqueue.
25952  for (j = 0; j < unflipqueue->objects; j++) {
25953  bface = (badface *) fastlookup(unflipqueue, j);
25954  flipqueue->newindex((void **) &parybface);
25955  *parybface = *bface;
25956  }
25957  unflipqueue->restart();
25958  } else {
25959  // Unable to remove this edge. Save it.
25960  nextflipqueue->newindex((void **) &parybface);
25961  *parybface = *bface;
25962  // Normally, it should be zero.
25963  //assert(fc.tetprism_vol_sum == 0.0);
25964  // However, due to rounding errors, a tiny value may appear.
25965  fc.tetprism_vol_sum = 0.0;
25966  }
25967  }
25968  } // i
25969 
25970  if (b->verbose > 1) {
25971  printf(" obj (after level %d) = %.17g.\n", autofliplinklevel,
25973  }
25974  flipqueue->restart();
25975 
25976  // Swap the two flip queues.
25977  swapqueue = flipqueue;
25978  flipqueue = nextflipqueue;
25979  nextflipqueue = swapqueue;
25980 
25981  if (flipqueue->objects > 0l) {
25982  // default 'b->delmaxfliplevel' is 1.
25984  // For efficiency reason, we do not search too far.
25985  break;
25986  }
25988  }
25989  } // while (flipqueue->objects > 0l)
25990 
25991  if (flipqueue->objects > 0l) {
25992  if (b->verbose > 1) {
25993  printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects);
25994  }
25995  }
25996 
25997  if (b->verbose) {
25998  printf(" Final obj = %.17g\n", tetprism_vol_sum);
25999  }
26000 
26001  b->flipstarsize = bakmaxflipstarsize;
26002  delete flipqueue;
26003  delete nextflipqueue;
26004 }
26005 
26007 // //
26008 // gettetrahedron() Get a tetrahedron which have the given vertices. //
26009 // //
26011 
26013  triface *searchtet)
26014 {
26015  triface spintet;
26016  int t1ver;
26017 
26018  if (getedge(pa, pb, searchtet)) {
26019  spintet = *searchtet;
26020  while (1) {
26021  if (apex(spintet) == pc) {
26022  *searchtet = spintet;
26023  break;
26024  }
26025  fnextself(spintet);
26026  if (spintet.tet == searchtet->tet) break;
26027  }
26028  if (apex(*searchtet) == pc) {
26029  if (oppo(*searchtet) == pd) {
26030  return 1;
26031  } else {
26032  fsymself(*searchtet);
26033  if (oppo(*searchtet) == pd) {
26034  return 1;
26035  }
26036  }
26037  }
26038  }
26039 
26040  return 0;
26041 }
26042 
26044 // //
26045 // improvequalitybyflips() Improve the mesh quality by flips. //
26046 // //
26048 
26050 {
26051  arraypool *flipqueue, *nextflipqueue, *swapqueue;
26052  badface *bface, *parybface;
26053  triface *parytet;
26054  point *ppt;
26055  flipconstraints fc;
26056  REAL *cosdd, ncosdd[6], maxdd;
26057  long totalremcount, remcount;
26058  int remflag;
26059  int n, i, j, k;
26060 
26061  //assert(unflipqueue->objects > 0l);
26062  flipqueue = new arraypool(sizeof(badface), 10);
26063  nextflipqueue = new arraypool(sizeof(badface), 10);
26064 
26065  // Backup flip edge options.
26066  int bakautofliplinklevel = autofliplinklevel;
26067  int bakfliplinklevel = b->fliplinklevel;
26068  int bakmaxflipstarsize = b->flipstarsize;
26069 
26070  // Set flip edge options.
26071  autofliplinklevel = 1;
26072  b->fliplinklevel = -1;
26073  b->flipstarsize = 10; // b->optmaxflipstarsize;
26074 
26075  fc.remove_large_angle = 1;
26076  fc.unflip = 1;
26077  fc.collectnewtets = 1;
26078  fc.checkflipeligibility = 1;
26079 
26080  totalremcount = 0l;
26081 
26082  // Swap the two flip queues.
26083  swapqueue = flipqueue;
26084  flipqueue = unflipqueue;
26085  unflipqueue = swapqueue;
26086 
26087  while (flipqueue->objects > 0l) {
26088 
26089  remcount = 0l;
26090 
26091  while (flipqueue->objects > 0l) {
26092  if (b->verbose > 1) {
26093  printf(" Improving mesh qualiy by flips [%d]#: %ld.\n",
26094  autofliplinklevel, flipqueue->objects);
26095  }
26096 
26097  for (k = 0; k < flipqueue->objects; k++) {
26098  bface = (badface *) fastlookup(flipqueue, k);
26099  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26100  bface->foppo, &bface->tt)) {
26101  //assert(!ishulltet(bface->tt));
26102  // There are bad dihedral angles in this tet.
26103  if (bface->tt.ver != 11) {
26104  // The dihedral angles are permuted.
26105  // Here we simply re-compute them. Slow!!.
26106  ppt = (point *) & (bface->tt.tet[4]);
26107  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26108  &bface->key, NULL);
26109  bface->forg = ppt[0];
26110  bface->fdest = ppt[1];
26111  bface->fapex = ppt[2];
26112  bface->foppo = ppt[3];
26113  bface->tt.ver = 11;
26114  }
26115  if (bface->key == 0) {
26116  // Re-comput the quality values. Due to smoothing operations.
26117  ppt = (point *) & (bface->tt.tet[4]);
26118  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26119  &bface->key, NULL);
26120  }
26121  cosdd = bface->cent;
26122  remflag = 0;
26123  for (i = 0; (i < 6) && !remflag; i++) {
26124  if (cosdd[i] < cosmaxdihed) {
26125  // Found a large dihedral angle.
26126  bface->tt.ver = edge2ver[i]; // Go to the edge.
26127  fc.cosdihed_in = cosdd[i];
26128  fc.cosdihed_out = 0.0; // 90 degree.
26129  n = removeedgebyflips(&(bface->tt), &fc);
26130  if (n == 2) {
26131  // Edge is flipped.
26132  remflag = 1;
26133  if (fc.cosdihed_out < cosmaxdihed) {
26134  // Queue new bad tets for further improvements.
26135  for (j = 0; j < cavetetlist->objects; j++) {
26136  parytet = (triface *) fastlookup(cavetetlist, j);
26137  if (!isdeadtet(*parytet)) {
26138  ppt = (point *) & (parytet->tet[4]);
26139  // Do not test a hull tet.
26140  if (ppt[3] != dummypoint) {
26141  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
26142  &maxdd, NULL);
26143  if (maxdd < cosmaxdihed) {
26144  // There are bad dihedral angles in this tet.
26145  nextflipqueue->newindex((void **) &parybface);
26146  parybface->tt.tet = parytet->tet;
26147  parybface->tt.ver = 11;
26148  parybface->forg = ppt[0];
26149  parybface->fdest = ppt[1];
26150  parybface->fapex = ppt[2];
26151  parybface->foppo = ppt[3];
26152  parybface->key = maxdd;
26153  for (n = 0; n < 6; n++) {
26154  parybface->cent[n] = ncosdd[n];
26155  }
26156  }
26157  } // if (ppt[3] != dummypoint)
26158  }
26159  } // j
26160  } // if (fc.cosdihed_out < cosmaxdihed)
26161  cavetetlist->restart();
26162  remcount++;
26163  }
26164  }
26165  } // i
26166  if (!remflag) {
26167  // An unremoved bad tet. Queue it again.
26168  unflipqueue->newindex((void **) &parybface);
26169  *parybface = *bface;
26170  }
26171  } // if (gettetrahedron(...))
26172  } // k
26173 
26174  flipqueue->restart();
26175 
26176  // Swap the two flip queues.
26177  swapqueue = flipqueue;
26178  flipqueue = nextflipqueue;
26179  nextflipqueue = swapqueue;
26180  } // while (flipqueues->objects > 0)
26181 
26182  if (b->verbose > 1) {
26183  printf(" Removed %ld bad tets.\n", remcount);
26184  }
26185  totalremcount += remcount;
26186 
26187  if (unflipqueue->objects > 0l) {
26188  //if (autofliplinklevel >= b->optmaxfliplevel) {
26189  if (autofliplinklevel >= b->optlevel) {
26190  break;
26191  }
26193  //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
26194  }
26195 
26196  // Swap the two flip queues.
26197  swapqueue = flipqueue;
26198  flipqueue = unflipqueue;
26199  unflipqueue = swapqueue;
26200  } // while (flipqueues->objects > 0)
26201 
26202  // Restore original flip edge options.
26203  autofliplinklevel = bakautofliplinklevel;
26204  b->fliplinklevel = bakfliplinklevel;
26205  b->flipstarsize = bakmaxflipstarsize;
26206 
26207  delete flipqueue;
26208  delete nextflipqueue;
26209 
26210  return totalremcount;
26211 }
26212 
26214 // //
26215 // smoothpoint() Moving a vertex to improve the mesh quality. //
26216 // //
26217 // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point. //
26218 // It may be not a vertex of the mesh. //
26219 // //
26220 // This routine tries to move 'p' inside its star until a selected objective //
26221 // function over all tetrahedra in the star is improved. The function may be //
26222 // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
26223 // simply the volume of the tetrahedra. //
26224 // //
26225 // 'linkfacelist' contains the list of link faces of 'p'. Since a link face //
26226 // has two orientations, ccw or cw, with respect to 'p'. 'ccw' indicates //
26227 // the orientation is ccw (1) or not (0). //
26228 // //
26229 // 'opm' is a structure contains the parameters of the objective function. //
26230 // It is needed by the evaluation of the function value. //
26231 // //
26232 // The return value indicates weather the point is smoothed or not. //
26233 // //
26234 // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
26235 // no face has 'dummypoint' as its vertex. //
26236 // //
26238 
26239 int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
26240  optparameters *opm)
26241 {
26242  triface *parytet, *parytet1, swaptet;
26243  point pa, pb, pc;
26244  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
26245  REAL oldval, minval = 0.0, val;
26246  REAL maxcosd; // oldang, newang;
26247  REAL ori, diff;
26248  int numdirs, iter;
26249  int i, j, k;
26250 
26251  // Decide the number of moving directions.
26252  numdirs = (int) linkfacelist->objects;
26253  if (numdirs > opm->numofsearchdirs) {
26254  numdirs = opm->numofsearchdirs; // Maximum search directions.
26255  }
26256 
26257  // Set the initial value.
26258  if (!opm->max_min_volume) {
26259  assert(opm->initval >= 0.0);
26260  }
26261  opm->imprval = opm->initval;
26262  iter = 0;
26263 
26264  for (i = 0; i < 3; i++) {
26265  bestpt[i] = startpt[i] = smtpt[i];
26266  }
26267 
26268  // Iterate until the obj function is not improved.
26269  while (1) {
26270 
26271  // Find the best next location.
26272  oldval = opm->imprval;
26273 
26274  for (i = 0; i < numdirs; i++) {
26275  // Randomly pick a link face (0 <= k <= objects - i - 1).
26276  k = (int) randomnation(linkfacelist->objects - i);
26277  parytet = (triface *) fastlookup(linkfacelist, k);
26278  // Calculate a new position from 'p' to the center of this face.
26279  pa = org(*parytet);
26280  pb = dest(*parytet);
26281  pc = apex(*parytet);
26282  for (j = 0; j < 3; j++) {
26283  fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
26284  }
26285  for (j = 0; j < 3; j++) {
26286  nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
26287  }
26288  // Calculate the largest minimum function value for the new location.
26289  for (j = 0; j < linkfacelist->objects; j++) {
26290  parytet = (triface *) fastlookup(linkfacelist, j);
26291  if (ccw) {
26292  pa = org(*parytet);
26293  pb = dest(*parytet);
26294  } else {
26295  pb = org(*parytet);
26296  pa = dest(*parytet);
26297  }
26298  pc = apex(*parytet);
26299  ori = orient3d(pa, pb, pc, nextpt);
26300  if (ori < 0.0) {
26301  // Calcuate the objective function value.
26302  if (opm->max_min_volume) {
26303  //val = -ori;
26304  val = - orient3dfast(pa, pb, pc, nextpt);
26305  } else if (opm->max_min_aspectratio) {
26306  val = tetaspectratio(pa, pb, pc, nextpt);
26307  } else if (opm->min_max_dihedangle) {
26308  tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
26309  if (maxcosd < -1) maxcosd = -1.0; // Rounding.
26310  val = maxcosd + 1.0; // Make it be positive.
26311  } else {
26312  // Unknown objective function.
26313  val = 0.0;
26314  }
26315  } else { // ori >= 0.0;
26316  // An invalid new tet.
26317  // This may happen if the mesh contains inverted elements.
26318  if (opm->max_min_volume) {
26319  //val = -ori;
26320  val = - orient3dfast(pa, pb, pc, nextpt);
26321  } else {
26322  // Discard this point.
26323  break; // j
26324  }
26325  } // if (ori >= 0.0)
26326  // Stop looping when the object value is not improved.
26327  if (val <= opm->imprval) {
26328  break; // j
26329  } else {
26330  // Remember the smallest improved value.
26331  if (j == 0) {
26332  minval = val;
26333  } else {
26334  minval = (val < minval) ? val : minval;
26335  }
26336  }
26337  } // j
26338  if (j == linkfacelist->objects) {
26339  // The function value has been improved.
26340  opm->imprval = minval;
26341  // Save the new location of the point.
26342  for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
26343  }
26344  // Swap k-th and (object-i-1)-th entries.
26345  j = linkfacelist->objects - i - 1;
26346  parytet = (triface *) fastlookup(linkfacelist, k);
26347  parytet1 = (triface *) fastlookup(linkfacelist, j);
26348  swaptet = *parytet1;
26349  *parytet1 = *parytet;
26350  *parytet = swaptet;
26351  } // i
26352 
26353  diff = opm->imprval - oldval;
26354  if (diff > 0.0) {
26355  // Is the function value improved effectively?
26356  if (opm->max_min_volume) {
26357  //if ((diff / oldval) < b->epsilon) diff = 0.0;
26358  } else if (opm->max_min_aspectratio) {
26359  if ((diff / oldval) < 1e-3) diff = 0.0;
26360  } else if (opm->min_max_dihedangle) {
26361  //oldang = acos(oldval - 1.0);
26362  //newang = acos(opm->imprval - 1.0);
26363  //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
26364  } else {
26365  // Unknown objective function.
26366  assert(0); // Not possible.
26367  }
26368  }
26369 
26370  if (diff > 0.0) {
26371  // Yes, move p to the new location and continue.
26372  for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
26373  iter++;
26374  if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
26375  // Maximum smoothing iterations reached.
26376  break;
26377  }
26378  } else {
26379  break;
26380  }
26381 
26382  } // while (1)
26383 
26384  if (iter > 0) {
26385  // The point has been smoothed.
26386  opm->smthiter = iter; // Remember the number of iterations.
26387  // The point has been smoothed. Update it to its new position.
26388  for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
26389  }
26390 
26391  return iter;
26392 }
26393 
26394 
26396 // //
26397 // improvequalitysmoothing() Improve mesh quality by smoothing. //
26398 // //
26400 
26402 {
26403  arraypool *flipqueue, *swapqueue;
26404  triface *parytet;
26405  badface *bface, *parybface;
26406  point *ppt;
26407  long totalsmtcount, smtcount;
26408  int smtflag;
26409  int iter, i, j, k;
26410 
26411  //assert(unflipqueue->objects > 0l);
26412  flipqueue = new arraypool(sizeof(badface), 10);
26413 
26414  // Swap the two flip queues.
26415  swapqueue = flipqueue;
26416  flipqueue = unflipqueue;
26417  unflipqueue = swapqueue;
26418 
26419  totalsmtcount = 0l;
26420  iter = 0;
26421 
26422  while (flipqueue->objects > 0l) {
26423 
26424  smtcount = 0l;
26425 
26426  if (b->verbose > 1) {
26427  printf(" Improving mesh quality by smoothing [%d]#: %ld.\n",
26428  iter, flipqueue->objects);
26429  }
26430 
26431  for (k = 0; k < flipqueue->objects; k++) {
26432  bface = (badface *) fastlookup(flipqueue, k);
26433  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26434  bface->foppo, &bface->tt)) {
26435  // Operate on it if it is not in 'unflipqueue'.
26436  if (!marktested(bface->tt)) {
26437  // Here we simply re-compute the quality. Since other smoothing
26438  // operation may have moved the vertices of this tet.
26439  ppt = (point *) & (bface->tt.tet[4]);
26440  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26441  &bface->key, NULL);
26442  if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
26443  // It is a sliver. Try to smooth its vertices.
26444  smtflag = 0;
26445  opm->initval = bface->key + 1.0;
26446  for (i = 0; (i < 4) && !smtflag; i++) {
26447  if (pointtype(ppt[i]) == FREEVOLVERTEX) {
26448  getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
26449  opm->searchstep = 0.001; // Search step size
26450  smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
26451  if (smtflag) {
26452  while (opm->smthiter == opm->maxiter) {
26453  opm->searchstep *= 10.0; // Increase the step size.
26454  opm->initval = opm->imprval;
26455  opm->smthiter = 0; // reset
26456  smoothpoint(ppt[i], cavetetlist, 1, opm);
26457  }
26458  // This tet is modifed.
26459  smtcount++;
26460  if ((opm->imprval - 1.0) < cossmtdihed) {
26461  // There are slivers in new tets. Queue them.
26462  for (j = 0; j < cavetetlist->objects; j++) {
26463  parytet = (triface *) fastlookup(cavetetlist, j);
26464  assert(!isdeadtet(*parytet));
26465  // Operate it if it is not in 'unflipqueue'.
26466  if (!marktested(*parytet)) {
26467  // Evaluate its quality.
26468  // Re-use ppt, bface->key, bface->cent.
26469  ppt = (point *) & (parytet->tet[4]);
26470  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
26471  bface->cent, &bface->key, NULL);
26472  if (bface->key < cossmtdihed) {
26473  // A new sliver. Queue it.
26474  marktest(*parytet); // It is in unflipqueue.
26475  unflipqueue->newindex((void **) &parybface);
26476  parybface->tt = *parytet;
26477  parybface->forg = ppt[0];
26478  parybface->fdest = ppt[1];
26479  parybface->fapex = ppt[2];
26480  parybface->foppo = ppt[3];
26481  parybface->tt.ver = 11;
26482  parybface->key = 0.0;
26483  }
26484  }
26485  } // j
26486  } // if ((opm->imprval - 1.0) < cossmtdihed)
26487  } // if (smtflag)
26488  cavetetlist->restart();
26489  } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
26490  } // i
26491  if (!smtflag) {
26492  // Didn't smooth. Queue it again.
26493  marktest(bface->tt); // It is in unflipqueue.
26494  unflipqueue->newindex((void **) &parybface);
26495  parybface->tt = bface->tt;
26496  parybface->forg = ppt[0];
26497  parybface->fdest = ppt[1];
26498  parybface->fapex = ppt[2];
26499  parybface->foppo = ppt[3];
26500  parybface->tt.ver = 11;
26501  parybface->key = 0.0;
26502  }
26503  } // if (maxdd < cosslidihed)
26504  } // if (!marktested(...))
26505  } // if (gettetrahedron(...))
26506  } // k
26507 
26508  flipqueue->restart();
26509 
26510  // Unmark the tets in unflipqueue.
26511  for (i = 0; i < unflipqueue->objects; i++) {
26512  bface = (badface *) fastlookup(unflipqueue, i);
26513  unmarktest(bface->tt);
26514  }
26515 
26516  if (b->verbose > 1) {
26517  printf(" Smooth %ld points.\n", smtcount);
26518  }
26519  totalsmtcount += smtcount;
26520 
26521  if (smtcount == 0l) {
26522  // No point has been smoothed.
26523  break;
26524  } else {
26525  iter++;
26526  if (iter == 2) { //if (iter >= b->optpasses) {
26527  break;
26528  }
26529  }
26530 
26531  // Swap the two flip queues.
26532  swapqueue = flipqueue;
26533  flipqueue = unflipqueue;
26534  unflipqueue = swapqueue;
26535  } // while
26536 
26537  delete flipqueue;
26538 
26539  return totalsmtcount;
26540 }
26541 
26543 // //
26544 // splitsliver() Split a sliver. //
26545 // //
26547 
26548 int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
26549 {
26550  triface *abtets;
26551  triface searchtet, spintet, *parytet;
26552  point pa, pb, steinerpt;
26553  optparameters opm;
26554  insertvertexflags ivf;
26555  REAL smtpt[3], midpt[3];
26556  int success;
26557  int t1ver;
26558  int n, i;
26559 
26560  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
26561  // Go to the opposite edge [a,b].
26562  edestoppo(*slitet, searchtet); // [a,b,c,d].
26563 
26564  // Do not split a segment.
26565  if (issubseg(searchtet)) {
26566  return 0;
26567  }
26568 
26569  // Count the number of tets shared at [a,b].
26570  // Do not split it if it is a hull edge.
26571  spintet = searchtet;
26572  n = 0;
26573  while (1) {
26574  if (ishulltet(spintet)) break;
26575  n++;
26576  fnextself(spintet);
26577  if (spintet.tet == searchtet.tet) break;
26578  }
26579  if (ishulltet(spintet)) {
26580  return 0; // It is a hull edge.
26581  }
26582  assert(n >= 3);
26583 
26584  // Get all tets at edge [a,b].
26585  abtets = new triface[n];
26586  spintet = searchtet;
26587  for (i = 0; i < n; i++) {
26588  abtets[i] = spintet;
26589  fnextself(spintet);
26590  }
26591 
26592  // Initialize the list of 2n boundary faces.
26593  for (i = 0; i < n; i++) {
26594  eprev(abtets[i], searchtet);
26595  esymself(searchtet); // [a,p_i,p_i+1].
26596  cavetetlist->newindex((void **) &parytet);
26597  *parytet = searchtet;
26598  enext(abtets[i], searchtet);
26599  esymself(searchtet); // [p_i,b,p_i+1].
26600  cavetetlist->newindex((void **) &parytet);
26601  *parytet = searchtet;
26602  }
26603 
26604  // Init the Steiner point at the midpoint of edge [a,b].
26605  pa = org(abtets[0]);
26606  pb = dest(abtets[0]);
26607  for (i = 0; i < 3; i++) {
26608  smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
26609  }
26610 
26611  // Point smooth options.
26612  opm.min_max_dihedangle = 1;
26613  opm.initval = cosd + 1.0; // Initial volume is zero.
26614  opm.numofsearchdirs = 20;
26615  opm.searchstep = 0.001;
26616  opm.maxiter = 100; // Limit the maximum iterations.
26617 
26618  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
26619 
26620  if (success) {
26621  while (opm.smthiter == opm.maxiter) {
26622  // It was relocated and the prescribed maximum iteration reached.
26623  // Try to increase the search stepsize.
26624  opm.searchstep *= 10.0;
26625  //opm.maxiter = 100; // Limit the maximum iterations.
26626  opm.initval = opm.imprval;
26627  opm.smthiter = 0; // Init.
26628  smoothpoint(smtpt, cavetetlist, 1, &opm);
26629  }
26630  } // if (success)
26631 
26632  cavetetlist->restart();
26633 
26634  if (!success) {
26635  delete [] abtets;
26636  return 0;
26637  }
26638 
26639 
26640  // Insert the Steiner point.
26641  makepoint(&steinerpt, FREEVOLVERTEX);
26642  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
26643 
26644  // Insert the created Steiner point.
26645  for (i = 0; i < n; i++) {
26646  infect(abtets[i]);
26647  caveoldtetlist->newindex((void **) &parytet);
26648  *parytet = abtets[i];
26649  }
26650 
26651  searchtet = abtets[0]; // No need point location.
26652  if (b->metric) {
26653  locate(steinerpt, &searchtet); // For size interpolation.
26654  }
26655 
26656  delete [] abtets;
26657 
26658  ivf.iloc = (int) INSTAR;
26659  ivf.chkencflag = chkencflag;
26660  ivf.assignmeshsize = b->metric;
26661 
26662 
26663  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
26664  // The vertex has been inserted.
26665  st_volref_count++;
26666  if (steinerleft > 0) steinerleft--;
26667  return 1;
26668  } else {
26669  // The Steiner point is too close to an existing vertex. Reject it.
26670  pointdealloc(steinerpt);
26671  return 0;
26672  }
26673 }
26674 
26676 // //
26677 // removeslivers() Remove slivers by adding Steiner points. //
26678 // //
26680 
26681 long tetgenmesh::removeslivers(int chkencflag)
26682 {
26683  arraypool *flipqueue, *swapqueue;
26684  badface *bface, *parybface;
26685  triface slitet, *parytet;
26686  point *ppt;
26687  REAL cosdd[6], maxcosd;
26688  long totalsptcount, sptcount;
26689  int iter, i, j, k;
26690 
26691  //assert(unflipqueue->objects > 0l);
26692  flipqueue = new arraypool(sizeof(badface), 10);
26693 
26694  // Swap the two flip queues.
26695  swapqueue = flipqueue;
26696  flipqueue = unflipqueue;
26697  unflipqueue = swapqueue;
26698 
26699  totalsptcount = 0l;
26700  iter = 0;
26701 
26702  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
26703 
26704  sptcount = 0l;
26705 
26706  if (b->verbose > 1) {
26707  printf(" Splitting bad quality tets [%d]#: %ld.\n",
26708  iter, flipqueue->objects);
26709  }
26710 
26711  for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
26712  bface = (badface *) fastlookup(flipqueue, k);
26713  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26714  bface->foppo, &bface->tt)) {
26715  if ((bface->key == 0) || (bface->tt.ver != 11)) {
26716  // Here we need to re-compute the quality. Since other smoothing
26717  // operation may have moved the vertices of this tet.
26718  ppt = (point *) & (bface->tt.tet[4]);
26719  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26720  &bface->key, NULL);
26721  }
26722  if (bface->key < cosslidihed) {
26723  // It is a sliver. Try to split it.
26724  slitet.tet = bface->tt.tet;
26725  //cosdd = bface->cent;
26726  for (j = 0; j < 6; j++) {
26727  if (bface->cent[j] < cosslidihed) {
26728  // Found a large dihedral angle.
26729  slitet.ver = edge2ver[j]; // Go to the edge.
26730  if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
26731  sptcount++;
26732  break;
26733  }
26734  }
26735  } // j
26736  if (j < 6) {
26737  // A sliver is split. Queue new slivers.
26739  parytet = (triface *) badtetrahedrons->traverse();
26740  while (parytet != NULL) {
26741  unmarktest2(*parytet);
26742  ppt = (point *) & (parytet->tet[4]);
26743  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
26744  &maxcosd, NULL);
26745  if (maxcosd < cosslidihed) {
26746  // A new sliver. Queue it.
26747  unflipqueue->newindex((void **) &parybface);
26748  parybface->forg = ppt[0];
26749  parybface->fdest = ppt[1];
26750  parybface->fapex = ppt[2];
26751  parybface->foppo = ppt[3];
26752  parybface->tt.tet = parytet->tet;
26753  parybface->tt.ver = 11;
26754  parybface->key = maxcosd;
26755  for (i = 0; i < 6; i++) {
26756  parybface->cent[i] = cosdd[i];
26757  }
26758  }
26759  parytet = (triface *) badtetrahedrons->traverse();
26760  }
26762  } else {
26763  // Didn't split. Queue it again.
26764  unflipqueue->newindex((void **) &parybface);
26765  *parybface = *bface;
26766  } // if (j == 6)
26767  } // if (bface->key < cosslidihed)
26768  } // if (gettetrahedron(...))
26769  } // k
26770 
26771  flipqueue->restart();
26772 
26773  if (b->verbose > 1) {
26774  printf(" Split %ld tets.\n", sptcount);
26775  }
26776  totalsptcount += sptcount;
26777 
26778  if (sptcount == 0l) {
26779  // No point has been smoothed.
26780  break;
26781  } else {
26782  iter++;
26783  if (iter == 2) { //if (iter >= b->optpasses) {
26784  break;
26785  }
26786  }
26787 
26788  // Swap the two flip queues.
26789  swapqueue = flipqueue;
26790  flipqueue = unflipqueue;
26791  unflipqueue = swapqueue;
26792  } // while
26793 
26794  delete flipqueue;
26795 
26796  return totalsptcount;
26797 }
26798 
26800 // //
26801 // optimizemesh() Optimize mesh for specified objective functions. //
26802 // //
26804 
26806 {
26807  badface *parybface;
26808  triface checktet;
26809  point *ppt;
26810  int optpasses;
26811  optparameters opm;
26812  REAL ncosdd[6], maxdd;
26813  long totalremcount, remcount;
26814  long totalsmtcount, smtcount;
26815  long totalsptcount, sptcount;
26816  int chkencflag;
26817  int iter;
26818  int n;
26819 
26820  if (!b->quiet) {
26821  printf("Optimizing mesh...\n");
26822  }
26823 
26824  optpasses = ((1 << b->optlevel) - 1);
26825 
26826  if (b->verbose) {
26827  printf(" Optimization level = %d.\n", b->optlevel);
26828  printf(" Optimization scheme = %d.\n", b->optscheme);
26829  printf(" Number of iteration = %d.\n", optpasses);
26830  printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral);
26831  }
26832 
26833  totalsmtcount = totalsptcount = totalremcount = 0l;
26834 
26835  cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
26836  cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
26837  cosslidihed = cos(b->optminslidihed / 180.0 * PI);
26838 
26839  int attrnum = numelemattrib - 1;
26840 
26841  // Put all bad tetrahedra into array.
26843  checktet.tet = tetrahedrontraverse();
26844  while (checktet.tet != NULL) {
26845  if (b->convex) { // -c
26846  // Skip this tet if it lies in the exterior.
26847  if (elemattribute(checktet.tet, attrnum) == -1.0) {
26848  checktet.tet = tetrahedrontraverse();
26849  continue;
26850  }
26851  }
26852  ppt = (point *) & (checktet.tet[4]);
26853  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
26854  if (maxdd < cosmaxdihed) {
26855  // There are bad dihedral angles in this tet.
26856  unflipqueue->newindex((void **) &parybface);
26857  parybface->tt.tet = checktet.tet;
26858  parybface->tt.ver = 11;
26859  parybface->forg = ppt[0];
26860  parybface->fdest = ppt[1];
26861  parybface->fapex = ppt[2];
26862  parybface->foppo = ppt[3];
26863  parybface->key = maxdd;
26864  for (n = 0; n < 6; n++) {
26865  parybface->cent[n] = ncosdd[n];
26866  }
26867  }
26868  checktet.tet = tetrahedrontraverse();
26869  }
26870 
26871  totalremcount = improvequalitybyflips();
26872 
26873  if ((unflipqueue->objects > 0l) &&
26874  ((b->optscheme & 2) || (b->optscheme & 4))) {
26875  // The pool is only used by removeslivers().
26877  sizeof(void *), 0);
26878 
26879  // Smoothing options.
26880  opm.min_max_dihedangle = 1;
26881  opm.numofsearchdirs = 10;
26882  // opm.searchstep = 0.001;
26883  opm.maxiter = 30; // Limit the maximum iterations.
26884  //opm.checkencflag = 4; // Queue affected tets after smoothing.
26885  chkencflag = 4; // Queue affected tets after splitting a sliver.
26886  iter = 0;
26887 
26888  while (iter < optpasses) {
26889  smtcount = sptcount = remcount = 0l;
26890  if (b->optscheme & 2) {
26891  smtcount += improvequalitybysmoothing(&opm);
26892  totalsmtcount += smtcount;
26893  if (smtcount > 0l) {
26894  remcount = improvequalitybyflips();
26895  totalremcount += remcount;
26896  }
26897  }
26898  if (unflipqueue->objects > 0l) {
26899  if (b->optscheme & 4) {
26900  sptcount += removeslivers(chkencflag);
26901  totalsptcount += sptcount;
26902  if (sptcount > 0l) {
26903  remcount = improvequalitybyflips();
26904  totalremcount += remcount;
26905  }
26906  }
26907  }
26908  if (unflipqueue->objects > 0l) {
26909  if (remcount > 0l) {
26910  iter++;
26911  } else {
26912  break;
26913  }
26914  } else {
26915  break;
26916  }
26917  } // while (iter)
26918 
26919  delete badtetrahedrons;
26920 
26921  }
26922 
26923  if (unflipqueue->objects > 0l) {
26924  if (b->verbose > 1) {
26925  printf(" %ld bad tets remained.\n", unflipqueue->objects);
26926  }
26927  unflipqueue->restart();
26928  }
26929 
26930  if (b->verbose) {
26931  if (totalremcount > 0l) {
26932  printf(" Removed %ld edges.\n", totalremcount);
26933  }
26934  if (totalsmtcount > 0l) {
26935  printf(" Smoothed %ld points.\n", totalsmtcount);
26936  }
26937  if (totalsptcount > 0l) {
26938  printf(" Split %ld slivers.\n", totalsptcount);
26939  }
26940  }
26941 }
26942 
26946 
26950 
26952 // //
26953 // printfcomma() Print a (large) number with the 'thousands separator'. //
26954 // //
26955 // The following code was simply copied from "stackoverflow". //
26956 // //
26958 
26959 void tetgenmesh::printfcomma(unsigned long n)
26960 {
26961  unsigned long n2 = 0;
26962  int scale = 1;
26963  while (n >= 1000) {
26964  n2 = n2 + scale * (n % 1000);
26965  n /= 1000;
26966  scale *= 1000;
26967  }
26968  printf ("%ld", n);
26969  while (scale != 1) {
26970  scale /= 1000;
26971  n = n2 / scale;
26972  n2 = n2 % scale;
26973  printf (",%03ld", n);
26974  }
26975 }
26976 
26978 // //
26979 // checkmesh() Test the mesh for topological consistency. //
26980 // //
26981 // If 'topoflag' is set, only check the topological connection of the mesh, //
26982 // i.e., do not report degenerated or inverted elements. //
26983 // //
26985 
26986 int tetgenmesh::checkmesh(int topoflag)
26987 {
26988  triface tetloop, neightet, symtet;
26989  point pa, pb, pc, pd;
26990  REAL ori;
26991  int horrors, i;
26992 
26993  if (!b->quiet) {
26994  printf(" Checking consistency of mesh...\n");
26995  }
26996 
26997  horrors = 0;
26998  tetloop.ver = 0;
26999  // Run through the list of tetrahedra, checking each one.
27001  tetloop.tet = alltetrahedrontraverse();
27002  while (tetloop.tet != (tetrahedron *) NULL) {
27003  // Check all four faces of the tetrahedron.
27004  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27005  pa = org(tetloop);
27006  pb = dest(tetloop);
27007  pc = apex(tetloop);
27008  pd = oppo(tetloop);
27009  if (tetloop.ver == 0) { // Only test for inversion once.
27010  if (!ishulltet(tetloop)) { // Only do test if it is not a hull tet.
27011  if (!topoflag) {
27012  ori = orient3d(pa, pb, pc, pd);
27013  if (ori >= 0.0) {
27014  printf(" !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
27015  printf(" (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
27016  pointmark(pb), pointmark(pc), pointmark(pd), ori);
27017  horrors++;
27018  }
27019  }
27020  }
27021  if (infected(tetloop)) {
27022  // This may be a bug. Report it.
27023  printf(" !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
27024  pointmark(pb), pointmark(pc), pointmark(pd));
27025  horrors++;
27026  }
27027  if (marktested(tetloop)) {
27028  // This may be a bug. Report it.
27029  printf(" !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
27030  pointmark(pb), pointmark(pc), pointmark(pd));
27031  horrors++;
27032  }
27033  }
27034  if (tetloop.tet[tetloop.ver] == NULL) {
27035  printf(" !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
27036  pointmark(pb), pointmark(pc));
27037  horrors++;
27038  } else {
27039  // Find the neighboring tetrahedron on this face.
27040  fsym(tetloop, neightet);
27041  // Check that the tetrahedron's neighbor knows it's a neighbor.
27042  fsym(neightet, symtet);
27043  if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
27044  printf(" !! !! Asymmetric tetra-tetra bond:\n");
27045  if (tetloop.tet == symtet.tet) {
27046  printf(" (Right tetrahedron, wrong orientation)\n");
27047  }
27048  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27049  pointmark(pb), pointmark(pc), pointmark(pd));
27050  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27051  pointmark(dest(neightet)), pointmark(apex(neightet)),
27052  pointmark(oppo(neightet)));
27053  horrors++;
27054  }
27055  // Check if they have the same edge (the bond() operation).
27056  if ((org(neightet) != pb) || (dest(neightet) != pa)) {
27057  printf(" !! !! Wrong edge-edge bond:\n");
27058  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27059  pointmark(pb), pointmark(pc), pointmark(pd));
27060  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27061  pointmark(dest(neightet)), pointmark(apex(neightet)),
27062  pointmark(oppo(neightet)));
27063  horrors++;
27064  }
27065  // Check if they have the same apex.
27066  if (apex(neightet) != pc) {
27067  printf(" !! !! Wrong face-face bond:\n");
27068  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27069  pointmark(pb), pointmark(pc), pointmark(pd));
27070  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27071  pointmark(dest(neightet)), pointmark(apex(neightet)),
27072  pointmark(oppo(neightet)));
27073  horrors++;
27074  }
27075  // Check if they have the same opposite.
27076  if (oppo(neightet) == pd) {
27077  printf(" !! !! Two identical tetra:\n");
27078  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
27079  pointmark(pb), pointmark(pc), pointmark(pd));
27080  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27081  pointmark(dest(neightet)), pointmark(apex(neightet)),
27082  pointmark(oppo(neightet)));
27083  horrors++;
27084  }
27085  }
27086  if (facemarked(tetloop)) {
27087  // This may be a bug. Report it.
27088  printf(" !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
27089  pointmark(pb), pointmark(pc), pointmark(pd));
27090  }
27091  }
27092  // Check the six edges of this tet.
27093  for (i = 0; i < 6; i++) {
27094  tetloop.ver = edge2ver[i];
27095  if (edgemarked(tetloop)) {
27096  // This may be a bug. Report it.
27097  printf(" !! tetedge (%d, %d) %d, %d is marked.\n",
27098  pointmark(org(tetloop)), pointmark(dest(tetloop)),
27099  pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
27100  }
27101  }
27102  tetloop.tet = alltetrahedrontraverse();
27103  }
27104  if (horrors == 0) {
27105  if (!b->quiet) {
27106  printf(" In my studied opinion, the mesh appears to be consistent.\n");
27107  }
27108  } else {
27109  printf(" !! !! !! !! %d %s witnessed.\n", horrors,
27110  horrors > 1 ? "abnormity" : "abnormities");
27111  }
27112 
27113  return horrors;
27114 }
27115 
27117 // //
27118 // checkshells() Test the boundary mesh for topological consistency. //
27119 // //
27121 
27123 {
27124  triface neightet, symtet;
27125  face shloop, spinsh, nextsh;
27126  face checkseg;
27127  point pa, pb;
27128  int bakcount;
27129  int horrors, i;
27130 
27131  if (!b->quiet) {
27132  printf(" Checking consistency of the mesh boundary...\n");
27133  }
27134  horrors = 0;
27135 
27136  void **bakpathblock = subfaces->pathblock;
27137  void *bakpathitem = subfaces->pathitem;
27138  int bakpathitemsleft = subfaces->pathitemsleft;
27139  int bakalignbytes = subfaces->alignbytes;
27140 
27142  shloop.sh = shellfacetraverse(subfaces);
27143  while (shloop.sh != NULL) {
27144  shloop.shver = 0;
27145  for (i = 0; i < 3; i++) {
27146  // Check the face ring at this edge.
27147  pa = sorg(shloop);
27148  pb = sdest(shloop);
27149  spinsh = shloop;
27150  spivot(spinsh, nextsh);
27151  bakcount = horrors;
27152  while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
27153  if (nextsh.sh[3] == NULL) {
27154  printf(" !! !! Wrong subface-subface connection (Dead subface).\n");
27155  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27156  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27157  pointmark(sapex(spinsh)));
27158  printf(" Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
27159  horrors++;
27160  break;
27161  }
27162  // check if they have the same edge.
27163  if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
27164  ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
27165  printf(" !! !! Wrong subface-subface connection.\n");
27166  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27167  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27168  pointmark(sapex(spinsh)));
27169  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27170  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27171  pointmark(sapex(nextsh)));
27172  horrors++;
27173  break;
27174  }
27175  // Check they should not have the same apex.
27176  if (sapex(nextsh) == sapex(spinsh)) {
27177  printf(" !! !! Existing two duplicated subfaces.\n");
27178  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27179  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27180  pointmark(sapex(spinsh)));
27181  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27182  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27183  pointmark(sapex(nextsh)));
27184  horrors++;
27185  break;
27186  }
27187  spinsh = nextsh;
27188  spivot(spinsh, nextsh);
27189  }
27190  // Check subface-subseg bond.
27191  sspivot(shloop, checkseg);
27192  if (checkseg.sh != NULL) {
27193  if (checkseg.sh[3] == NULL) {
27194  printf(" !! !! Wrong subface-subseg connection (Dead subseg).\n");
27195  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27196  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27197  pointmark(sapex(shloop)));
27198  printf(" Sub: x%lx (Dead)\n", (uintptr_t) checkseg.sh);
27199  horrors++;
27200  } else {
27201  if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
27202  ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
27203  printf(" !! !! Wrong subface-subseg connection.\n");
27204  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27205  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27206  pointmark(sapex(shloop)));
27207  printf(" Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
27208  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
27209  horrors++;
27210  }
27211  }
27212  }
27213  if (horrors > bakcount) break; // An error detected.
27214  senextself(shloop);
27215  }
27216  // Check tet-subface connection.
27217  stpivot(shloop, neightet);
27218  if (neightet.tet != NULL) {
27219  if (neightet.tet[4] == NULL) {
27220  printf(" !! !! Wrong sub-to-tet connection (Dead tet)\n");
27221  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27222  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27223  pointmark(sapex(shloop)));
27224  printf(" Tet: x%lx (DEAD)\n", (uintptr_t) neightet.tet);
27225  horrors++;
27226  } else {
27227  if (!((sorg(shloop) == org(neightet)) &&
27228  (sdest(shloop) == dest(neightet)))) {
27229  printf(" !! !! Wrong sub-to-tet connection\n");
27230  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27231  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27232  pointmark(sapex(shloop)));
27233  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
27234  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27235  pointmark(dest(neightet)), pointmark(apex(neightet)),
27236  pointmark(oppo(neightet)));
27237  horrors++;
27238  }
27239  tspivot(neightet, spinsh);
27240  if (!((sorg(spinsh) == org(neightet)) &&
27241  (sdest(spinsh) == dest(neightet)))) {
27242  printf(" !! !! Wrong tet-sub connection.\n");
27243  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27244  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27245  pointmark(sapex(spinsh)));
27246  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
27247  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27248  pointmark(dest(neightet)), pointmark(apex(neightet)),
27249  pointmark(oppo(neightet)));
27250  horrors++;
27251  }
27252  fsym(neightet, symtet);
27253  tspivot(symtet, spinsh);
27254  if (spinsh.sh != NULL) {
27255  if (!((sorg(spinsh) == org(symtet)) &&
27256  (sdest(spinsh) == dest(symtet)))) {
27257  printf(" !! !! Wrong tet-sub connection.\n");
27258  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27259  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27260  pointmark(sapex(spinsh)));
27261  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
27262  (uintptr_t) symtet.tet, pointmark(org(symtet)),
27263  pointmark(dest(symtet)), pointmark(apex(symtet)),
27264  pointmark(oppo(symtet)));
27265  horrors++;
27266  }
27267  } else {
27268  printf(" Warning: Broken tet-sub-tet connection.\n");
27269  }
27270  }
27271  }
27272  if (sinfected(shloop)) {
27273  // This may be a bug. report it.
27274  printf(" !! A infected subface: (%d, %d, %d).\n",
27275  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27276  pointmark(sapex(shloop)));
27277  }
27278  if (smarktested(shloop)) {
27279  // This may be a bug. report it.
27280  printf(" !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)),
27281  pointmark(sdest(shloop)), pointmark(sapex(shloop)));
27282  }
27283  shloop.sh = shellfacetraverse(subfaces);
27284  }
27285 
27286  if (horrors == 0) {
27287  if (!b->quiet) {
27288  printf(" Mesh boundaries connected correctly.\n");
27289  }
27290  } else {
27291  printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
27292  horrors);
27293  }
27294 
27295  subfaces->pathblock = bakpathblock;
27296  subfaces->pathitem = bakpathitem;
27297  subfaces->pathitemsleft = bakpathitemsleft;
27298  subfaces->alignbytes = bakalignbytes;
27299 
27300  return horrors;
27301 }
27302 
27304 // //
27305 // checksegments() Check the connections between tetrahedra and segments. //
27306 // //
27308 
27310 {
27311  triface tetloop, neightet, spintet;
27312  shellface *segs;
27313  face neighsh, spinsh, checksh;
27314  face sseg, checkseg;
27315  point pa, pb;
27316  int miscount;
27317  int t1ver;
27318  int horrors, i;
27319 
27320 
27321  if (!b->quiet) {
27322  printf(" Checking tet->seg connections...\n");
27323  }
27324 
27325  horrors = 0;
27327  tetloop.tet = tetrahedrontraverse();
27328  while (tetloop.tet != NULL) {
27329  // Loop the six edges of the tet.
27330  if (tetloop.tet[8] != NULL) {
27331  segs = (shellface *) tetloop.tet[8];
27332  for (i = 0; i < 6; i++) {
27333  sdecode(segs[i], sseg);
27334  if (sseg.sh != NULL) {
27335  // Get the edge of the tet.
27336  tetloop.ver = edge2ver[i];
27337  // Check if they are the same edge.
27338  pa = (point) sseg.sh[3];
27339  pb = (point) sseg.sh[4];
27340  if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
27341  ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
27342  printf(" !! Wrong tet-seg connection.\n");
27343  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
27344  (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
27345  pointmark(dest(tetloop)), pointmark(apex(tetloop)),
27346  pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
27347  pointmark(pa), pointmark(pb));
27348  horrors++;
27349  } else {
27350  // Loop all tets sharing at this edge.
27351  neightet = tetloop;
27352  do {
27353  tsspivot1(neightet, checkseg);
27354  if (checkseg.sh != sseg.sh) {
27355  printf(" !! Wrong tet->seg connection.\n");
27356  printf(" Tet: x%lx (%d, %d, %d, %d) - ",
27357  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27358  pointmark(dest(neightet)), pointmark(apex(neightet)),
27359  pointmark(oppo(neightet)));
27360  if (checkseg.sh != NULL) {
27361  printf("Seg x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
27362  pointmark(sorg(checkseg)),pointmark(sdest(checkseg)));
27363  } else {
27364  printf("Seg: NULL.\n");
27365  }
27366  horrors++;
27367  }
27368  fnextself(neightet);
27369  } while (neightet.tet != tetloop.tet);
27370  }
27371  // Check the seg->tet pointer.
27372  sstpivot1(sseg, neightet);
27373  if (neightet.tet == NULL) {
27374  printf(" !! Wrong seg->tet connection (A NULL tet).\n");
27375  horrors++;
27376  } else {
27377  if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
27378  ((org(neightet) == pb) && (dest(neightet) == pa)))) {
27379  printf(" !! Wrong seg->tet connection (Wrong edge).\n");
27380  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
27381  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27382  pointmark(dest(neightet)), pointmark(apex(neightet)),
27383  pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
27384  pointmark(pa), pointmark(pb));
27385  horrors++;
27386  }
27387  }
27388  }
27389  }
27390  }
27391  // Loop the six edge of this tet.
27392  neightet.tet = tetloop.tet;
27393  for (i = 0; i < 6; i++) {
27394  neightet.ver = edge2ver[i];
27395  if (edgemarked(neightet)) {
27396  // A possible bug. Report it.
27397  printf(" !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
27398  pointmark(org(neightet)), pointmark(dest(neightet)),
27399  pointmark(apex(neightet)), pointmark(oppo(neightet)),
27400  (uintptr_t) neightet.tet, neightet.ver);
27401  // Check if all tets at the edge are marked.
27402  spintet = neightet;
27403  while (1) {
27404  fnextself(spintet);
27405  if (!edgemarked(spintet)) {
27406  printf(" !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
27407  pointmark(org(spintet)), pointmark(dest(spintet)),
27408  pointmark(apex(spintet)), pointmark(oppo(spintet)),
27409  (uintptr_t) spintet.tet, spintet.ver);
27410  horrors++;
27411  }
27412  if (spintet.tet == neightet.tet) break;
27413  }
27414  }
27415  }
27416  tetloop.tet = tetrahedrontraverse();
27417  }
27418 
27419  if (!b->quiet) {
27420  printf(" Checking seg->tet connections...\n");
27421  }
27422 
27423  miscount = 0; // Count the number of unrecovered segments.
27425  sseg.shver = 0;
27426  sseg.sh = shellfacetraverse(subsegs);
27427  while (sseg.sh != NULL) {
27428  pa = sorg(sseg);
27429  pb = sdest(sseg);
27430  spivot(sseg, neighsh);
27431  if (neighsh.sh != NULL) {
27432  spinsh = neighsh;
27433  while (1) {
27434  // Check seg-subface bond.
27435  if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
27436  ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
27437  // Keep the same rotate direction.
27438  //if (sorg(spinsh) != pa) {
27439  // sesymself(spinsh);
27440  // printf(" !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
27441  // pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27442  // pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27443  // spinsh.shver);
27444  // horrors++;
27445  //}
27446  stpivot(spinsh, spintet);
27447  if (spintet.tet != NULL) {
27448  // Check if all tets at this segment.
27449  while (1) {
27450  tsspivot1(spintet, checkseg);
27451  if (checkseg.sh == NULL) {
27452  printf(" !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
27453  pointmark(org(spintet)), pointmark(dest(spintet)),
27454  pointmark(apex(spintet)), pointmark(oppo(spintet)),
27455  (uintptr_t) spintet.tet, spintet.ver);
27456  horrors++;
27457  }
27458  if (checkseg.sh != sseg.sh) {
27459  printf(" !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
27460  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
27461  pointmark(org(spintet)), pointmark(dest(spintet)),
27462  pointmark(apex(spintet)), pointmark(oppo(spintet)));
27463  horrors++;
27464  }
27465  fnextself(spintet);
27466  // Stop at the next subface.
27467  tspivot(spintet, checksh);
27468  if (checksh.sh != NULL) break;
27469  } // while (1)
27470  }
27471  } else {
27472  printf(" !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
27473  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27474  pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27475  spinsh.shver);
27476  horrors++;
27477  break;
27478  } // if pa, pb
27479  spivotself(spinsh);
27480  if (spinsh.sh == NULL) break; // A dangling segment.
27481  if (spinsh.sh == neighsh.sh) break;
27482  } // while (1)
27483  } // if (neighsh.sh != NULL)
27484  // Count the number of "un-recovered" segments.
27485  sstpivot1(sseg, neightet);
27486  if (neightet.tet == NULL) {
27487  miscount++;
27488  }
27489  sseg.sh = shellfacetraverse(subsegs);
27490  }
27491 
27492  if (!b->quiet) {
27493  printf(" Checking seg->seg connections...\n");
27494  }
27495 
27496  points->traversalinit();
27497  pa = pointtraverse();
27498  while (pa != NULL) {
27499  if (pointtype(pa) == FREESEGVERTEX) {
27500  // There should be two subsegments connected at 'pa'.
27501  // Get a subsegment containing 'pa'.
27502  sdecode(point2sh(pa), sseg);
27503  if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
27504  printf(" !! Dead point-to-seg pointer at point %d.\n",
27505  pointmark(pa));
27506  horrors++;
27507  } else {
27508  sseg.shver = 0;
27509  if (sorg(sseg) != pa) {
27510  if (sdest(sseg) != pa) {
27511  printf(" !! Wrong point-to-seg pointer at point %d.\n",
27512  pointmark(pa));
27513  horrors++;
27514  } else {
27515  // Find the next subsegment at 'pa'.
27516  senext(sseg, checkseg);
27517  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
27518  printf(" !! Dead seg-seg connection at point %d.\n",
27519  pointmark(pa));
27520  horrors++;
27521  } else {
27522  spivotself(checkseg);
27523  checkseg.shver = 0;
27524  if (sorg(checkseg) != pa) {
27525  printf(" !! Wrong seg-seg connection at point %d.\n",
27526  pointmark(pa));
27527  horrors++;
27528  }
27529  }
27530  }
27531  } else {
27532  // Find the previous subsegment at 'pa'.
27533  senext2(sseg, checkseg);
27534  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
27535  printf(" !! Dead seg-seg connection at point %d.\n",
27536  pointmark(pa));
27537  horrors++;
27538  } else {
27539  spivotself(checkseg);
27540  checkseg.shver = 0;
27541  if (sdest(checkseg) != pa) {
27542  printf(" !! Wrong seg-seg connection at point %d.\n",
27543  pointmark(pa));
27544  horrors++;
27545  }
27546  }
27547  }
27548  }
27549  }
27550  pa = pointtraverse();
27551  }
27552 
27553  if (horrors == 0) {
27554  printf(" Segments are connected properly.\n");
27555  } else {
27556  printf(" !! !! !! !! Found %d missing connections.\n", horrors);
27557  }
27558  if (miscount > 0) {
27559  printf(" !! !! Found %d missing segments.\n", miscount);
27560  }
27561 
27562  return horrors;
27563 }
27564 
27566 // //
27567 // checkdelaunay() Ensure that the mesh is (constrained) Delaunay. //
27568 // //
27570 
27572 {
27573  triface tetloop;
27574  triface symtet;
27575  face checksh;
27576  point pa, pb, pc, pd, pe;
27577  REAL sign;
27578  int ndcount; // Count the non-locally Delaunay faces.
27579  int horrors;
27580 
27581  if (!b->quiet) {
27582  printf(" Checking Delaunay property of the mesh...\n");
27583  }
27584 
27585  ndcount = 0;
27586  horrors = 0;
27587  tetloop.ver = 0;
27588  // Run through the list of triangles, checking each one.
27590  tetloop.tet = tetrahedrontraverse();
27591  while (tetloop.tet != (tetrahedron *) NULL) {
27592  // Check all four faces of the tetrahedron.
27593  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27594  fsym(tetloop, symtet);
27595  // Only do test if its adjoining tet is not a hull tet or its pointer
27596  // is larger (to ensure that each pair isn't tested twice).
27597  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27598  pa = org(tetloop);
27599  pb = dest(tetloop);
27600  pc = apex(tetloop);
27601  pd = oppo(tetloop);
27602  pe = oppo(symtet);
27603  sign = insphere_s(pa, pb, pc, pd, pe);
27604  if (sign < 0.0) {
27605  ndcount++;
27606  if (checksubfaceflag) {
27607  tspivot(tetloop, checksh);
27608  }
27609  if (checksh.sh == NULL) {
27610  printf(" !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
27611  pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
27612  pointmark(pe));
27613  horrors++;
27614  }
27615  }
27616  }
27617  }
27618  tetloop.tet = tetrahedrontraverse();
27619  }
27620 
27621  if (horrors == 0) {
27622  if (!b->quiet) {
27623  if (ndcount > 0) {
27624  printf(" The mesh is constrained Delaunay.\n");
27625  } else {
27626  printf(" The mesh is Delaunay.\n");
27627  }
27628  }
27629  } else {
27630  printf(" !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
27631  }
27632 
27633  return horrors;
27634 }
27635 
27637 // //
27638 // Check if the current tetrahedralization is (constrained) regular. //
27639 // //
27640 // The parameter 'type' determines which regularity should be checked: //
27641 // - 0: check the Delaunay property. //
27642 // - 1: check the Delaunay property with symbolic perturbation. //
27643 // - 2: check the regular property, the weights are stored in p[3]. //
27644 // - 3: check the regular property with symbolic perturbation. //
27645 // //
27647 
27649 {
27650  triface tetloop;
27651  triface symtet;
27652  face checksh;
27653  point p[5];
27654  REAL sign;
27655  int ndcount; // Count the non-locally Delaunay faces.
27656  int horrors;
27657 
27658  if (!b->quiet) {
27659  printf(" Checking %s %s property of the mesh...\n",
27660  (type & 2) == 0 ? "Delaunay" : "regular",
27661  (type & 1) == 0 ? " " : "(s)");
27662  }
27663 
27664  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
27665  // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
27666  // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
27667  // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
27668  // p[4] lies below the oriented hyperplane passing through
27669  // p[1], p[0], p[2], p[3].
27670 
27671  ndcount = 0;
27672  horrors = 0;
27673  tetloop.ver = 0;
27674  // Run through the list of triangles, checking each one.
27676  tetloop.tet = tetrahedrontraverse();
27677  while (tetloop.tet != (tetrahedron *) NULL) {
27678  // Check all four faces of the tetrahedron.
27679  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27680  fsym(tetloop, symtet);
27681  // Only do test if its adjoining tet is not a hull tet or its pointer
27682  // is larger (to ensure that each pair isn't tested twice).
27683  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27684  p[0] = org(tetloop); // pa
27685  p[1] = dest(tetloop); // pb
27686  p[2] = apex(tetloop); // pc
27687  p[3] = oppo(tetloop); // pd
27688  p[4] = oppo(symtet); // pe
27689 
27690  if (type == 0) {
27691  sign = insphere(p[1], p[0], p[2], p[3], p[4]);
27692  } else if (type == 1) {
27693  sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
27694  } else if (type == 2) {
27695  sign = orient4d(p[1], p[0], p[2], p[3], p[4],
27696  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27697  } else { // type == 3
27698  sign = orient4d_s(p[1], p[0], p[2], p[3], p[4],
27699  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27700  }
27701 
27702  if (sign > 0.0) {
27703  ndcount++;
27704  if (checksubfaceflag) {
27705  tspivot(tetloop, checksh);
27706  }
27707  if (checksh.sh == NULL) {
27708  printf(" !! Non-locally %s (%d, %d, %d) - %d, %d\n",
27709  (type & 2) == 0 ? "Delaunay" : "regular",
27710  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
27711  pointmark(p[3]), pointmark(p[4]));
27712  horrors++;
27713  }
27714  }
27715  }
27716  }
27717  tetloop.tet = tetrahedrontraverse();
27718  }
27719 
27720  if (horrors == 0) {
27721  if (!b->quiet) {
27722  if (ndcount > 0) {
27723  printf(" The mesh is constrained %s.\n",
27724  (type & 2) == 0 ? "Delaunay" : "regular");
27725  } else {
27726  printf(" The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
27727  }
27728  }
27729  } else {
27730  printf(" !! !! !! !! Found %d non-%s faces.\n", horrors,
27731  (type & 2) == 0 ? "Delaunay" : "regular");
27732  }
27733 
27734  return horrors;
27735 }
27736 
27738 // //
27739 // checkconforming() Ensure that the mesh is conforming Delaunay. //
27740 // //
27741 // If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces. //
27742 // If 'flag' is 3, check both subsegments and subfaces. //
27743 // //
27745 
27747 {
27748  triface searchtet, neightet, spintet;
27749  face shloop;
27750  face segloop;
27751  point eorg, edest, eapex, pa, pb, pc;
27752  REAL cent[3], radius, dist, diff, rd, len;
27753  bool enq;
27754  int encsubsegs, encsubfaces;
27755  int t1ver;
27756  int i;
27757 
27758  REAL A[4][4], rhs[4], D;
27759  int indx[4];
27760  REAL elen[3];
27761 
27762  encsubsegs = 0;
27763 
27764  if (flag & 1) {
27765  if (!b->quiet) {
27766  printf(" Checking conforming property of segments...\n");
27767  }
27768  encsubsegs = 0;
27769 
27770  // Run through the list of subsegments, check each one.
27772  segloop.sh = shellfacetraverse(subsegs);
27773  while (segloop.sh != (shellface *) NULL) {
27774  eorg = (point) segloop.sh[3];
27775  edest = (point) segloop.sh[4];
27776  radius = 0.5 * distance(eorg, edest);
27777  for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
27778 
27779  enq = false;
27780  sstpivot1(segloop, neightet);
27781  if (neightet.tet != NULL) {
27782  spintet = neightet;
27783  while (1) {
27784  eapex= apex(spintet);
27785  if (eapex != dummypoint) {
27786  dist = distance(eapex, cent);
27787  diff = dist - radius;
27788  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
27789  if (diff < 0) {
27790  enq = true; break;
27791  }
27792  }
27793  fnextself(spintet);
27794  if (spintet.tet == neightet.tet) break;
27795  }
27796  }
27797  if (enq) {
27798  printf(" !! !! Non-conforming segment: (%d, %d)\n",
27799  pointmark(eorg), pointmark(edest));
27800  encsubsegs++;
27801  }
27802  segloop.sh = shellfacetraverse(subsegs);
27803  }
27804 
27805  if (encsubsegs == 0) {
27806  if (!b->quiet) {
27807  printf(" The segments are conforming Delaunay.\n");
27808  }
27809  } else {
27810  printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
27811  }
27812  } // if (flag & 1)
27813 
27814  encsubfaces = 0;
27815 
27816  if (flag & 2) {
27817  if (!b->quiet) {
27818  printf(" Checking conforming property of subfaces...\n");
27819  }
27820 
27821  // Run through the list of subfaces, check each one.
27823  shloop.sh = shellfacetraverse(subfaces);
27824  while (shloop.sh != (shellface *) NULL) {
27825  pa = (point) shloop.sh[3];
27826  pb = (point) shloop.sh[4];
27827  pc = (point) shloop.sh[5];
27828 
27829  // Compute the coefficient matrix A (3x3).
27830  A[0][0] = pb[0] - pa[0];
27831  A[0][1] = pb[1] - pa[1];
27832  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
27833  A[1][0] = pc[0] - pa[0];
27834  A[1][1] = pc[1] - pa[1];
27835  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
27836  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
27837 
27838  // Compute the right hand side vector b (3x1).
27839  elen[0] = dot(A[0], A[0]);
27840  elen[1] = dot(A[1], A[1]);
27841  rhs[0] = 0.5 * elen[0];
27842  rhs[1] = 0.5 * elen[1];
27843  rhs[2] = 0.0;
27844 
27845  if (lu_decmp(A, 3, indx, &D, 0)) {
27846  lu_solve(A, 3, indx, rhs, 0);
27847  cent[0] = pa[0] + rhs[0];
27848  cent[1] = pa[1] + rhs[1];
27849  cent[2] = pa[2] + rhs[2];
27850  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
27851 
27852  // Check if this subface is encroached.
27853  for (i = 0; i < 2; i++) {
27854  stpivot(shloop, searchtet);
27855  if (!ishulltet(searchtet)) {
27856  len = distance(oppo(searchtet), cent);
27857  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
27858  if (len < rd) {
27859  printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
27860  pointmark(pa), pointmark(pb), pointmark(pc));
27861  encsubfaces++;
27862  enq = true; break;
27863  }
27864  }
27865  sesymself(shloop);
27866  }
27867  }
27868  shloop.sh = shellfacetraverse(subfaces);
27869  }
27870 
27871  if (encsubfaces == 0) {
27872  if (!b->quiet) {
27873  printf(" The subfaces are conforming Delaunay.\n");
27874  }
27875  } else {
27876  printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
27877  }
27878  } // if (flag & 2)
27879 
27880  return encsubsegs + encsubfaces;
27881 }
27882 
27884 // //
27885 // qualitystatistics() Print statistics about the quality of the mesh. //
27886 // //
27888 
27890 {
27891  triface tetloop, neightet;
27892  point p[4];
27893  char sbuf[128];
27894  REAL radiusratiotable[12];
27895  REAL aspectratiotable[12];
27896  REAL A[4][4], rhs[4], D;
27897  REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
27898  REAL edgelength[6], alldihed[6], faceangle[3];
27899  REAL shortest, longest;
27900  REAL smallestvolume, biggestvolume;
27901  REAL smallestratio, biggestratio;
27902  REAL smallestdiangle, biggestdiangle;
27903  REAL smallestfaangle, biggestfaangle;
27904  REAL total_tet_vol, total_tetprism_vol;
27905  REAL tetvol, minaltitude;
27906  REAL cirradius, minheightinv; // insradius;
27907  REAL shortlen, longlen;
27908  REAL tetaspect, tetradius;
27909  REAL smalldiangle, bigdiangle;
27910  REAL smallfaangle, bigfaangle;
27911  unsigned long radiustable[12];
27912  unsigned long aspecttable[16];
27913  unsigned long dihedangletable[18];
27914  unsigned long faceangletable[18];
27915  int indx[4];
27916  int radiusindex;
27917  int aspectindex;
27918  int tendegree;
27919  int i, j;
27920 
27921  printf("Mesh quality statistics:\n\n");
27922 
27923  shortlen = longlen = 0.0;
27924  smalldiangle = bigdiangle = 0.0;
27925  total_tet_vol = 0.0;
27926  total_tetprism_vol = 0.0;
27927 
27928  radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
27929  radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
27930  radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
27931  radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
27932  radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
27933  radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
27934 
27935  aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
27936  aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
27937  aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
27938  aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
27939  aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
27940  aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
27941 
27942  for (i = 0; i < 12; i++) radiustable[i] = 0l;
27943  for (i = 0; i < 12; i++) aspecttable[i] = 0l;
27944  for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
27945  for (i = 0; i < 18; i++) faceangletable[i] = 0l;
27946 
27947  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
27948  minaltitude = minaltitude * minaltitude;
27949  shortest = minaltitude;
27950  longest = 0.0;
27951  smallestvolume = minaltitude;
27952  biggestvolume = 0.0;
27953  smallestratio = 1e+16; // minaltitude;
27954  biggestratio = 0.0;
27955  smallestdiangle = smallestfaangle = 180.0;
27956  biggestdiangle = biggestfaangle = 0.0;
27957 
27958 
27959  int attrnum = numelemattrib - 1;
27960 
27961  // Loop all elements, calculate quality parameters for each element.
27963  tetloop.tet = tetrahedrontraverse();
27964  while (tetloop.tet != (tetrahedron *) NULL) {
27965 
27966  if (b->convex) {
27967  // Skip tets in the exterior.
27968  if (elemattribute(tetloop.tet, attrnum) == -1.0) {
27969  tetloop.tet = tetrahedrontraverse();
27970  continue;
27971  }
27972  }
27973 
27974  // Get four vertices: p0, p1, p2, p3.
27975  for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
27976 
27977  // Get the tet volume.
27978  tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
27979  total_tet_vol += tetvol;
27980  total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
27981 
27982  // Calculate the largest and smallest volume.
27983  if (tetvol < smallestvolume) {
27984  smallestvolume = tetvol;
27985  }
27986  if (tetvol > biggestvolume) {
27987  biggestvolume = tetvol;
27988  }
27989 
27990  // Set the edge vectors: V[0], ..., V[5]
27991  for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
27992  for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
27993  for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
27994  for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
27995  for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
27996  for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
27997 
27998  // Get the squares of the edge lengths.
27999  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
28000 
28001  // Calculate the longest and shortest edge length.
28002  for (i = 0; i < 6; i++) {
28003  if (i == 0) {
28004  shortlen = longlen = edgelength[i];
28005  } else {
28006  shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
28007  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
28008  }
28009  if (edgelength[i] > longest) {
28010  longest = edgelength[i];
28011  }
28012  if (edgelength[i] < shortest) {
28013  shortest = edgelength[i];
28014  }
28015  }
28016 
28017  // Set the matrix A = [V[0], V[1], V[2]]^T.
28018  for (j = 0; j < 3; j++) {
28019  for (i = 0; i < 3; i++) A[j][i] = V[j][i];
28020  }
28021 
28022  // Decompose A just once.
28023  if (lu_decmp(A, 3, indx, &D, 0)) {
28024  // Get the three faces normals.
28025  for (j = 0; j < 3; j++) {
28026  for (i = 0; i < 3; i++) rhs[i] = 0.0;
28027  rhs[j] = 1.0; // Positive means the inside direction
28028  lu_solve(A, 3, indx, rhs, 0);
28029  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
28030  }
28031  // Get the fourth face normal by summing up the first three.
28032  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
28033  // Get the radius of the circumsphere.
28034  for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
28035  lu_solve(A, 3, indx, rhs, 0);
28036  cirradius = sqrt(dot(rhs, rhs));
28037  // Normalize the face normals.
28038  for (i = 0; i < 4; i++) {
28039  // H[i] is the inverse of height of its corresponding face.
28040  H[i] = sqrt(dot(N[i], N[i]));
28041  for (j = 0; j < 3; j++) N[i][j] /= H[i];
28042  }
28043  // Get the radius of the inscribed sphere.
28044  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
28045  // Get the biggest H[i] (corresponding to the smallest height).
28046  minheightinv = H[0];
28047  for (i = 1; i < 3; i++) {
28048  if (H[i] > minheightinv) minheightinv = H[i];
28049  }
28050  } else {
28051  // A nearly degenerated tet.
28052  if (tetvol <= 0.0) {
28053  // assert(tetvol != 0.0);
28054  printf(" !! Warning: A %s tet (%d,%d,%d,%d).\n",
28055  tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
28056  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
28057  // Skip it.
28058  tetloop.tet = tetrahedrontraverse();
28059  continue;
28060  }
28061  // Calculate the four face normals.
28062  facenormal(p[2], p[1], p[3], N[0], 1, NULL);
28063  facenormal(p[0], p[2], p[3], N[1], 1, NULL);
28064  facenormal(p[1], p[0], p[3], N[2], 1, NULL);
28065  facenormal(p[0], p[1], p[2], N[3], 1, NULL);
28066  // Normalize the face normals.
28067  for (i = 0; i < 4; i++) {
28068  // H[i] is the twice of the area of the face.
28069  H[i] = sqrt(dot(N[i], N[i]));
28070  for (j = 0; j < 3; j++) N[i][j] /= H[i];
28071  }
28072  // Get the biggest H[i] / tetvol (corresponding to the smallest height).
28073  minheightinv = (H[0] / tetvol);
28074  for (i = 1; i < 3; i++) {
28075  if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
28076  }
28077  // Let the circumradius to be the half of its longest edge length.
28078  cirradius = 0.5 * sqrt(longlen);
28079  }
28080 
28081  // Get the dihedrals (in degree) at each edges.
28082  j = 0;
28083  for (i = 1; i < 4; i++) {
28084  alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
28085  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28086  else if (alldihed[j] > 1.0) alldihed[j] = 1;
28087  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28088  j++;
28089  }
28090  for (i = 2; i < 4; i++) {
28091  alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
28092  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28093  else if (alldihed[j] > 1.0) alldihed[j] = 1;
28094  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28095  j++;
28096  }
28097  alldihed[j] = -dot(N[2], N[3]); // Edge ab.
28098  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28099  else if (alldihed[j] > 1.0) alldihed[j] = 1;
28100  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28101 
28102  // Calculate the largest and smallest dihedral angles.
28103  for (i = 0; i < 6; i++) {
28104  if (i == 0) {
28105  smalldiangle = bigdiangle = alldihed[i];
28106  } else {
28107  smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
28108  bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
28109  }
28110  if (alldihed[i] < smallestdiangle) {
28111  smallestdiangle = alldihed[i];
28112  }
28113  if (alldihed[i] > biggestdiangle) {
28114  biggestdiangle = alldihed[i];
28115  }
28116  // Accumulate the corresponding number in the dihedral angle histogram.
28117  if (alldihed[i] < 5.0) {
28118  tendegree = 0;
28119  } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
28120  tendegree = 1;
28121  } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
28122  tendegree = 9; // Angles between 80 to 110 degree are in one entry.
28123  } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
28124  tendegree = 16;
28125  } else if (alldihed[i] >= 175.0) {
28126  tendegree = 17;
28127  } else {
28128  tendegree = (int) (alldihed[i] / 10.);
28129  if (alldihed[i] < 80.0) {
28130  tendegree++; // In the left column.
28131  } else {
28132  tendegree--; // In the right column.
28133  }
28134  }
28135  dihedangletable[tendegree]++;
28136  }
28137 
28138 
28139 
28140  // Calculate the largest and smallest face angles.
28141  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28142  fsym(tetloop, neightet);
28143  // Only do the calulation once for a face.
28144  if (((point) neightet.tet[7] == dummypoint) ||
28145  (tetloop.tet < neightet.tet)) {
28146  p[0] = org(tetloop);
28147  p[1] = dest(tetloop);
28148  p[2] = apex(tetloop);
28149  faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
28150  faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
28151  faceangle[2] = PI - (faceangle[0] + faceangle[1]);
28152  // Translate angles into degrees.
28153  for (i = 0; i < 3; i++) {
28154  faceangle[i] = (faceangle[i] * 180.0) / PI;
28155  }
28156  // Calculate the largest and smallest face angles.
28157  for (i = 0; i < 3; i++) {
28158  if (i == 0) {
28159  smallfaangle = bigfaangle = faceangle[i];
28160  } else {
28161  smallfaangle = faceangle[i] < smallfaangle ?
28162  faceangle[i] : smallfaangle;
28163  bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
28164  }
28165  if (faceangle[i] < smallestfaangle) {
28166  smallestfaangle = faceangle[i];
28167  }
28168  if (faceangle[i] > biggestfaangle) {
28169  biggestfaangle = faceangle[i];
28170  }
28171  tendegree = (int) (faceangle[i] / 10.);
28172  faceangletable[tendegree]++;
28173  }
28174  }
28175  }
28176 
28177  // Calculate aspect ratio and radius-edge ratio for this element.
28178  tetradius = cirradius / sqrt(shortlen);
28179  // tetaspect = sqrt(longlen) / (2.0 * insradius);
28180  tetaspect = sqrt(longlen) * minheightinv;
28181  // Remember the largest and smallest aspect ratio.
28182  if (tetaspect < smallestratio) {
28183  smallestratio = tetaspect;
28184  }
28185  if (tetaspect > biggestratio) {
28186  biggestratio = tetaspect;
28187  }
28188  // Accumulate the corresponding number in the aspect ratio histogram.
28189  aspectindex = 0;
28190  while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
28191  aspectindex++;
28192  }
28193  aspecttable[aspectindex]++;
28194  radiusindex = 0;
28195  while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
28196  radiusindex++;
28197  }
28198  radiustable[radiusindex]++;
28199 
28200  tetloop.tet = tetrahedrontraverse();
28201  }
28202 
28203  shortest = sqrt(shortest);
28204  longest = sqrt(longest);
28205  minaltitude = sqrt(minaltitude);
28206 
28207  printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
28208  smallestvolume, biggestvolume);
28209  printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
28210  shortest, longest);
28211  printf(" Smallest asp.ratio: %13.5g | Largest asp.ratio: %13.5g\n",
28212  smallestratio, biggestratio);
28213  sprintf(sbuf, "%.17g", biggestfaangle);
28214  if (strlen(sbuf) > 8) {
28215  sbuf[8] = '\0';
28216  }
28217  printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
28218  smallestfaangle, sbuf);
28219  sprintf(sbuf, "%.17g", biggestdiangle);
28220  if (strlen(sbuf) > 8) {
28221  sbuf[8] = '\0';
28222  }
28223  printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
28224  smallestdiangle, sbuf);
28225 
28226  printf(" Aspect ratio histogram:\n");
28227  printf(" < %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
28228  aspectratiotable[0], aspecttable[0], aspectratiotable[5],
28229  aspectratiotable[6], aspecttable[6]);
28230  for (i = 1; i < 5; i++) {
28231  printf(" %6.6g - %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
28232  aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
28233  aspectratiotable[i + 5], aspectratiotable[i + 6],
28234  aspecttable[i + 6]);
28235  }
28236  printf(" %6.6g - %-6.6g : %8ld | %6.6g - : %8ld\n",
28237  aspectratiotable[4], aspectratiotable[5], aspecttable[5],
28238  aspectratiotable[10], aspecttable[11]);
28239  printf(" (A tetrahedron's aspect ratio is its longest edge length");
28240  printf(" divided by its\n");
28241  printf(" smallest side height)\n\n");
28242 
28243  printf(" Face angle histogram:\n");
28244  for (i = 0; i < 9; i++) {
28245  printf(" %3d - %3d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28246  i * 10, i * 10 + 10, faceangletable[i],
28247  i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
28248  }
28249  if (minfaceang != PI) {
28250  printf(" Minimum input face angle is %g (degree).\n",
28251  minfaceang / PI * 180.0);
28252  }
28253  printf("\n");
28254 
28255  printf(" Dihedral angle histogram:\n");
28256  // Print the three two rows:
28257  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28258  0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
28259  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28260  5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
28261  // Print the third to seventh rows.
28262  for (i = 2; i < 7; i++) {
28263  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28264  (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
28265  (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
28266  }
28267  // Print the last two rows.
28268  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28269  60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
28270  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
28271  70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
28272  if (minfacetdihed != PI) {
28273  printf(" Minimum input dihedral angle is %g (degree).\n",
28274  minfacetdihed / PI * 180.0);
28275  }
28276  printf("\n");
28277 
28278  printf("\n");
28279 }
28280 
28281 
28283 // //
28284 // memorystatistics() Report the memory usage. //
28285 // //
28287 
28289 {
28290  printf("Memory usage statistics:\n\n");
28291 
28292  // Count the number of blocks of tetrahedra.
28293  int tetblocks = 0;
28295  while (tetrahedrons->pathblock != NULL) {
28296  tetblocks++;
28297  tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);
28298  }
28299 
28300  // Calculate the total memory (in bytes) used by storing meshes.
28301  unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
28302  totalmeshmemory = points->maxitems * points->itembytes +
28304  if (b->plc || b->refine) {
28305  totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
28307  totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
28309  }
28310 
28311  unsigned long totalalgomemory = 0l;
28312  totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
28315  if (b->plc || b->refine) {
28316  totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
28326  }
28327 
28328  printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
28329  printf(" Maximum number of tet blocks (blocksize = %d): %d\n",
28330  b->tetrahedraperblock, tetblocks);
28331  /*
28332  if (b->plc || b->refine) {
28333  printf(" Approximate memory for tetrahedral mesh (bytes): %ld\n",
28334  totalmeshmemory);
28335 
28336  printf(" Approximate memory for extra pointers (bytes): %ld\n",
28337  totalt2shmemory);
28338  } else {
28339  printf(" Approximate memory for tetrahedralization (bytes): %ld\n",
28340  totalmeshmemory);
28341  }
28342  printf(" Approximate memory for algorithms (bytes): %ld\n",
28343  totalalgomemory);
28344  printf(" Approximate memory for working arrays (bytes): %ld\n",
28345  totalworkmemory);
28346  printf(" Approximate total used memory (bytes): %ld\n",
28347  totalmeshmemory + totalt2shmemory + totalalgomemory +
28348  totalworkmemory);
28349  */
28350  if (b->plc || b->refine) {
28351  printf(" Approximate memory for tetrahedral mesh (bytes): ");
28352  printfcomma(totalmeshmemory); printf("\n");
28353 
28354  printf(" Approximate memory for extra pointers (bytes): ");
28355  printfcomma(totalt2shmemory); printf("\n");
28356  } else {
28357  printf(" Approximate memory for tetrahedralization (bytes): ");
28358  printfcomma(totalmeshmemory); printf("\n");
28359  }
28360  printf(" Approximate memory for algorithms (bytes): ");
28361  printfcomma(totalalgomemory); printf("\n");
28362  printf(" Approximate memory for working arrays (bytes): ");
28364  printf(" Approximate total used memory (bytes): ");
28365  printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory +
28366  totalworkmemory);
28367  printf("\n");
28368 
28369  printf("\n");
28370 }
28371 
28373 // //
28374 // statistics() Print all sorts of cool facts. //
28375 // //
28377 
28379 {
28380  long tetnumber, facenumber;
28381 
28382  printf("\nStatistics:\n\n");
28383  printf(" Input points: %d\n", in->numberofpoints);
28384  if (b->refine) {
28385  printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
28386  }
28387  if (b->plc) {
28388  printf(" Input facets: %d\n", in->numberoffacets);
28389  printf(" Input segments: %ld\n", insegments);
28390  printf(" Input holes: %d\n", in->numberofholes);
28391  printf(" Input regions: %d\n", in->numberofregions);
28392  }
28393 
28394  tetnumber = tetrahedrons->items - hullsize;
28395  facenumber = (tetnumber * 4l + hullsize) / 2l;
28396 
28397  if (b->weighted) { // -w option
28398  printf("\n Mesh points: %ld\n", points->items - nonregularcount);
28399  } else {
28400  printf("\n Mesh points: %ld\n", points->items);
28401  }
28402  printf(" Mesh tetrahedra: %ld\n", tetnumber);
28403  printf(" Mesh faces: %ld\n", facenumber);
28404  if (meshedges > 0l) {
28405  printf(" Mesh edges: %ld\n", meshedges);
28406  } else {
28407  if (!nonconvex) {
28408  long vsize = points->items - dupverts - unuverts;
28409  if (b->weighted) vsize -= nonregularcount;
28410  meshedges = vsize + facenumber - tetnumber - 1;
28411  printf(" Mesh edges: %ld\n", meshedges);
28412  }
28413  }
28414 
28415  if (b->plc || b->refine) {
28416  printf(" Mesh faces on facets: %ld\n", subfaces->items);
28417  printf(" Mesh edges on segments: %ld\n", subsegs->items);
28418  if (st_volref_count > 0l) {
28419  printf(" Steiner points inside domain: %ld\n", st_volref_count);
28420  }
28421  if (st_facref_count > 0l) {
28422  printf(" Steiner points on facets: %ld\n", st_facref_count);
28423  }
28424  if (st_segref_count > 0l) {
28425  printf(" Steiner points on segments: %ld\n", st_segref_count);
28426  }
28427  } else {
28428  printf(" Convex hull faces: %ld\n", hullsize);
28429  if (meshhulledges > 0l) {
28430  printf(" Convex hull edges: %ld\n", meshhulledges);
28431  }
28432  }
28433  if (b->weighted) { // -w option
28434  printf(" Skipped non-regular points: %ld\n", nonregularcount);
28435  }
28436  printf("\n");
28437 
28438 
28439  if (b->verbose > 0) {
28440  if (b->plc || b->refine) { // -p or -r
28441  if (tetrahedrons->items > 0l) {
28443  }
28444  }
28445  if (tetrahedrons->items > 0l) {
28446  memorystatistics();
28447  }
28448  }
28449 }
28450 
28454 
28458 
28460 // //
28461 // jettisonnodes() Jettison unused or duplicated vertices. //
28462 // //
28463 // Unused points are those input points which are outside the mesh domain or //
28464 // have no connection (isolated) to the mesh. Duplicated points exist for //
28465 // example if the input PLC is read from a .stl mesh file (marked during the //
28466 // Delaunay tetrahedralization step. This routine remove these points from //
28467 // points list. All existing points are reindexed. //
28468 // //
28470 
28472 {
28473  point pointloop;
28474  bool jetflag;
28475  int oldidx, newidx;
28476  int remcount;
28477 
28478  if (!b->quiet) {
28479  printf("Jettisoning redundant points.\n");
28480  }
28481 
28482  points->traversalinit();
28483  pointloop = pointtraverse();
28484  oldidx = newidx = 0; // in->firstnumber;
28485  remcount = 0;
28486  while (pointloop != (point) NULL) {
28487  jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
28488  (pointtype(pointloop) == UNUSEDVERTEX);
28489  if (jetflag) {
28490  // It is a duplicated or unused point, delete it.
28491  pointdealloc(pointloop);
28492  remcount++;
28493  } else {
28494  // Re-index it.
28495  setpointmark(pointloop, newidx + in->firstnumber);
28496  if (in->pointmarkerlist != (int *) NULL) {
28497  if (oldidx < in->numberofpoints) {
28498  // Re-index the point marker as well.
28499  in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
28500  }
28501  }
28502  newidx++;
28503  }
28504  oldidx++;
28505  pointloop = pointtraverse();
28506  }
28507  if (b->verbose) {
28508  printf(" %ld duplicated vertices are removed.\n", dupverts);
28509  printf(" %ld unused vertices are removed.\n", unuverts);
28510  }
28511  dupverts = 0l;
28512  unuverts = 0l;
28513 
28514  // The following line ensures that dead items in the pool of nodes cannot
28515  // be allocated for the new created nodes. This ensures that the input
28516  // nodes will occur earlier in the output files, and have lower indices.
28517  points->deaditemstack = (void *) NULL;
28518 }
28519 
28521 // //
28522 // highorder() Create extra nodes for quadratic subparametric elements. //
28523 // //
28524 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
28525 // high-order nodes of each tetrahedron. This routine is used only when -o2 //
28526 // switch is used. //
28527 // //
28529 
28531 {
28532  triface tetloop, worktet, spintet;
28533  point *extralist, *adjextralist;
28534  point torg, tdest, newpoint;
28535  int highorderindex;
28536  int t1ver;
28537  int i, j;
28538 
28539  if (!b->quiet) {
28540  printf("Adding vertices for second-order tetrahedra.\n");
28541  }
28542 
28543  // Initialize the 'highordertable'.
28544  highordertable = new point[tetrahedrons->items * 6];
28545  if (highordertable == (point *) NULL) {
28546  terminatetetgen(this, 1);
28547  }
28548 
28549  // This will overwrite the slot for element markers.
28550  highorderindex = 11;
28551 
28552  // The following line ensures that dead items in the pool of nodes cannot
28553  // be allocated for the extra nodes associated with high order elements.
28554  // This ensures that the primary nodes (at the corners of elements) will
28555  // occur earlier in the output files, and have lower indices, than the
28556  // extra nodes.
28557  points->deaditemstack = (void *) NULL;
28558 
28559  // Assign an entry for each tetrahedron to find its extra nodes. At the
28560  // mean while, initialize all extra nodes be NULL.
28561  i = 0;
28563  tetloop.tet = tetrahedrontraverse();
28564  while (tetloop.tet != (tetrahedron *) NULL) {
28565  tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
28566  for (j = 0; j < 6; j++) {
28567  highordertable[i + j] = (point) NULL;
28568  }
28569  i += 6;
28570  tetloop.tet = tetrahedrontraverse();
28571  }
28572 
28573  // To create a unique node on each edge. Loop over all tetrahedra, and
28574  // look at the six edges of each tetrahedron. If the extra node in
28575  // the tetrahedron corresponding to this edge is NULL, create a node
28576  // for this edge, at the same time, set the new node into the extra
28577  // node lists of all other tetrahedra sharing this edge.
28579  tetloop.tet = tetrahedrontraverse();
28580  while (tetloop.tet != (tetrahedron *) NULL) {
28581  // Get the list of extra nodes.
28582  extralist = (point *) tetloop.tet[highorderindex];
28583  worktet.tet = tetloop.tet;
28584  for (i = 0; i < 6; i++) {
28585  if (extralist[i] == (point) NULL) {
28586  // Go to the ith-edge.
28587  worktet.ver = edge2ver[i];
28588  // Create a new point in the middle of this edge.
28589  torg = org(worktet);
28590  tdest = dest(worktet);
28591  makepoint(&newpoint, FREEVOLVERTEX);
28592  for (j = 0; j < 3 + numpointattrib; j++) {
28593  newpoint[j] = 0.5 * (torg[j] + tdest[j]);
28594  }
28595  // Interpolate its metrics.
28596  for (j = 0; j < in->numberofpointmtrs; j++) {
28597  newpoint[pointmtrindex + j] =
28598  0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
28599  }
28600  // Set this point into all extra node lists at this edge.
28601  spintet = worktet;
28602  while (1) {
28603  if (!ishulltet(spintet)) {
28604  adjextralist = (point *) spintet.tet[highorderindex];
28605  adjextralist[ver2edge[spintet.ver]] = newpoint;
28606  }
28607  fnextself(spintet);
28608  if (spintet.tet == worktet.tet) break;
28609  }
28610  } // if (!extralist[i])
28611  } // i
28612  tetloop.tet = tetrahedrontraverse();
28613  }
28614 }
28615 
28617 // //
28618 // numberedges() Count the number of edges, save in "meshedges". //
28619 // //
28620 // This routine is called when '-p' or '-r', and '-E' options are used. The //
28621 // total number of edges depends on the genus of the input surface mesh. //
28622 // //
28623 // NOTE: This routine must be called after outelements(). So all elements //
28624 // have been indexed. //
28625 // //
28627 
28629 {
28630  triface worktet, spintet;
28631  int ishulledge;
28632  int t1ver;
28633  int i;
28634 
28635  meshedges = meshhulledges = 0l;
28636 
28638  worktet.tet = tetrahedrontraverse();
28639  while (worktet.tet != NULL) {
28640  // Count the number of Voronoi faces. Look at the six edges of this
28641  // tet. Count an edge only if this tet's index is smaller than
28642  // those of other non-hull tets which share this edge.
28643  for (i = 0; i < 6; i++) {
28644  worktet.ver = edge2ver[i];
28645  ishulledge = 0;
28646  fnext(worktet, spintet);
28647  do {
28648  if (!ishulltet(spintet)) {
28649  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
28650  } else {
28651  ishulledge = 1;
28652  }
28653  fnextself(spintet);
28654  } while (spintet.tet != worktet.tet);
28655  // Count this edge if no adjacent tets are smaller than this tet.
28656  if (spintet.tet == worktet.tet) {
28657  meshedges++;
28658  if (ishulledge) meshhulledges++;
28659  }
28660  }
28661  worktet.tet = tetrahedrontraverse();
28662  }
28663 }
28664 
28666 // //
28667 // outnodes() Output the points to a .node file or a tetgenio structure. //
28668 // //
28669 // Note: each point has already been numbered on input (the first index is //
28670 // 'in->firstnumber'). //
28671 // //
28673 
28675 {
28676  FILE *outfile = NULL;
28677  char outnodefilename[FILENAMESIZE];
28678  face parentsh;
28679  point pointloop;
28680  int nextras, bmark, marker = 0, weightDT = 0;
28681  int coordindex, attribindex;
28682  int pointnumber, firstindex;
28683  int index, i;
28684 
28685  if (out == (tetgenio *) NULL) {
28686  strcpy(outnodefilename, b->outfilename);
28687  strcat(outnodefilename, ".node");
28688  }
28689 
28690  if (!b->quiet) {
28691  if (out == (tetgenio *) NULL) {
28692  printf("Writing %s.\n", outnodefilename);
28693  } else {
28694  printf("Writing nodes.\n");
28695  }
28696  }
28697 
28698  nextras = numpointattrib;
28699  if (b->weighted) { // -w
28700  if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
28701  }
28702 
28703  bmark = !b->nobound && in->pointmarkerlist;
28704 
28705  if (out == (tetgenio *) NULL) {
28706  outfile = fopen(outnodefilename, "w");
28707  if (outfile == (FILE *) NULL) {
28708  printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
28709  terminatetetgen(this, 1);
28710  }
28711  // Number of points, number of dimensions, number of point attributes,
28712  // and number of boundary markers (zero or one).
28713  fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
28714  } else {
28715  // Allocate space for 'pointlist';
28716  out->pointlist = new REAL[points->items * 3];
28717  if (out->pointlist == (REAL *) NULL) {
28718  printf("Error: Out of memory.\n");
28719  terminatetetgen(this, 1);
28720  }
28721  // Allocate space for 'pointattributelist' if necessary;
28722  if (nextras > 0) {
28723  out->pointattributelist = new REAL[points->items * nextras];
28724  if (out->pointattributelist == (REAL *) NULL) {
28725  printf("Error: Out of memory.\n");
28726  terminatetetgen(this, 1);
28727  }
28728  }
28729  // Allocate space for 'pointmarkerlist' if necessary;
28730  if (bmark) {
28731  out->pointmarkerlist = new int[points->items];
28732  if (out->pointmarkerlist == (int *) NULL) {
28733  printf("Error: Out of memory.\n");
28734  terminatetetgen(this, 1);
28735  }
28736  }
28737  if (b->psc) {
28739  if (out->pointparamlist == NULL) {
28740  printf("Error: Out of memory.\n");
28741  terminatetetgen(this, 1);
28742  }
28743  }
28744  out->numberofpoints = points->items;
28745  out->numberofpointattributes = nextras;
28746  coordindex = 0;
28747  attribindex = 0;
28748  }
28749 
28750  // Determine the first index (0 or 1).
28751  firstindex = b->zeroindex ? 0 : in->firstnumber;
28752 
28753  points->traversalinit();
28754  pointloop = pointtraverse();
28755  pointnumber = firstindex; // in->firstnumber;
28756  index = 0;
28757  while (pointloop != (point) NULL) {
28758  if (bmark) {
28759  // Default the vertex has a zero marker.
28760  marker = 0;
28761  // Is it an input vertex?
28762  if (index < in->numberofpoints) {
28763  // Input point's marker is directly copied to output.
28764  marker = in->pointmarkerlist[index];
28765  } else {
28766  if ((pointtype(pointloop) == FREESEGVERTEX) ||
28767  (pointtype(pointloop) == FREEFACETVERTEX)) {
28768  sdecode(point2sh(pointloop), parentsh);
28769  if (parentsh.sh != NULL) {
28770  marker = shellmark(parentsh);
28771  if (pointtype(pointloop) == FREEFACETVERTEX) {
28772  if (in->facetmarkerlist != NULL) {
28773  marker = in->facetmarkerlist[marker - 1];
28774  }
28775  }
28776  }
28777  } // if (pointtype(...))
28778  }
28779  }
28780  if (out == (tetgenio *) NULL) {
28781  // Point number, x, y and z coordinates.
28782  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
28783  pointloop[0], pointloop[1], pointloop[2]);
28784  for (i = 0; i < nextras; i++) {
28785  // Write an attribute.
28786  if ((i == 0) && weightDT) {
28787  fprintf(outfile, " %.17g", pointloop[0] * pointloop[0] +
28788  pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2]
28789  - pointloop[3 + i]);
28790  } else {
28791  fprintf(outfile, " %.17g", pointloop[3 + i]);
28792  }
28793  }
28794  if (bmark) {
28795  // Write the boundary marker.
28796  fprintf(outfile, " %d", marker);
28797  }
28798  if (b->psc) {
28799  fprintf(outfile, " %.8g %.8g %d", pointgeomuv(pointloop, 0),
28800  pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
28801  if (pointtype(pointloop) == RIDGEVERTEX) {
28802  fprintf(outfile, " 0");
28803  } else if (pointtype(pointloop) == ACUTEVERTEX) {
28804  fprintf(outfile, " 0");
28805  } else if (pointtype(pointloop) == FREESEGVERTEX) {
28806  fprintf(outfile, " 1");
28807  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28808  fprintf(outfile, " 2");
28809  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28810  fprintf(outfile, " 3");
28811  } else {
28812  fprintf(outfile, " -1"); // Unknown type.
28813  }
28814  }
28815  fprintf(outfile, "\n");
28816  } else {
28817  // X, y, and z coordinates.
28818  out->pointlist[coordindex++] = pointloop[0];
28819  out->pointlist[coordindex++] = pointloop[1];
28820  out->pointlist[coordindex++] = pointloop[2];
28821  // Point attributes.
28822  for (i = 0; i < nextras; i++) {
28823  // Output an attribute.
28824  if ((i == 0) && weightDT) {
28825  out->pointattributelist[attribindex++] =
28826  pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] +
28827  pointloop[2] * pointloop[2] - pointloop[3 + i];
28828  } else {
28829  out->pointattributelist[attribindex++] = pointloop[3 + i];
28830  }
28831  }
28832  if (bmark) {
28833  // Output the boundary marker.
28834  out->pointmarkerlist[index] = marker;
28835  }
28836  if (b->psc) {
28837  out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
28838  out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
28839  out->pointparamlist[index].tag = pointgeomtag(pointloop);
28840  if (pointtype(pointloop) == RIDGEVERTEX) {
28841  out->pointparamlist[index].type = 0;
28842  } else if (pointtype(pointloop) == ACUTEVERTEX) {
28843  out->pointparamlist[index].type = 0;
28844  } else if (pointtype(pointloop) == FREESEGVERTEX) {
28845  out->pointparamlist[index].type = 1;
28846  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28847  out->pointparamlist[index].type = 2;
28848  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28849  out->pointparamlist[index].type = 3;
28850  } else {
28851  out->pointparamlist[index].type = -1; // Unknown type.
28852  }
28853  }
28854  }
28855  pointloop = pointtraverse();
28856  pointnumber++;
28857  index++;
28858  }
28859 
28860  if (out == (tetgenio *) NULL) {
28861  fprintf(outfile, "# Generated by %s\n", b->commandline);
28862  fclose(outfile);
28863  }
28864 }
28865 
28867 // //
28868 // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
28869 // //
28871 
28873 {
28874  FILE *outfile = NULL;
28875  char outmtrfilename[FILENAMESIZE];
28876  point ptloop;
28877  int mtrindex;
28878 
28879  if (out == (tetgenio *) NULL) {
28880  strcpy(outmtrfilename, b->outfilename);
28881  strcat(outmtrfilename, ".mtr");
28882  }
28883 
28884  if (!b->quiet) {
28885  if (out == (tetgenio *) NULL) {
28886  printf("Writing %s.\n", outmtrfilename);
28887  } else {
28888  printf("Writing metrics.\n");
28889  }
28890  }
28891 
28892  if (out == (tetgenio *) NULL) {
28893  outfile = fopen(outmtrfilename, "w");
28894  if (outfile == (FILE *) NULL) {
28895  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
28896  terminatetetgen(this, 3);
28897  }
28898  // Number of points, number of point metrices,
28899  // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3);
28900  fprintf(outfile, "%ld %d\n", points->items, 1);
28901  } else {
28902  // Allocate space for 'pointmtrlist' if necessary;
28903  // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
28904  out->pointmtrlist = new REAL[points->items];
28905  if (out->pointmtrlist == (REAL *) NULL) {
28906  terminatetetgen(this, 1);
28907  }
28908  out->numberofpointmtrs = 1; // (sizeoftensor + 3);
28909  mtrindex = 0;
28910  }
28911 
28912  points->traversalinit();
28913  ptloop = pointtraverse();
28914  while (ptloop != (point) NULL) {
28915  if (out == (tetgenio *) NULL) {
28916  // for (i = 0; i < sizeoftensor; i++) {
28917  // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
28918  // }
28919  fprintf(outfile, "%-16.8e\n", ptloop[pointmtrindex]);
28920  } else {
28921  // for (i = 0; i < sizeoftensor; i++) {
28922  // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
28923  // }
28924  out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex];
28925  }
28926  ptloop = pointtraverse();
28927  }
28928 
28929  if (out == (tetgenio *) NULL) {
28930  fprintf(outfile, "# Generated by %s\n", b->commandline);
28931  fclose(outfile);
28932  }
28933 }
28934 
28936 // //
28937 // outelements() Output the tetrahedra to an .ele file or a tetgenio //
28938 // structure. //
28939 // //
28940 // This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
28941 // firstnumber). The total number of mesh edges is counted in 'meshedges'. //
28942 // //
28944 
28946 {
28947  FILE *outfile = NULL;
28948  char outelefilename[FILENAMESIZE];
28949  tetrahedron* tptr;
28950  point p1, p2, p3, p4;
28951  point *extralist;
28952  REAL *talist = NULL;
28953  int *tlist = NULL;
28954  long ntets;
28955  int firstindex, shift;
28956  int pointindex, attribindex;
28957  int highorderindex = 11;
28958  int elementnumber;
28959  int eextras;
28960  int i;
28961 
28962  if (out == (tetgenio *) NULL) {
28963  strcpy(outelefilename, b->outfilename);
28964  strcat(outelefilename, ".ele");
28965  }
28966 
28967  if (!b->quiet) {
28968  if (out == (tetgenio *) NULL) {
28969  printf("Writing %s.\n", outelefilename);
28970  } else {
28971  printf("Writing elements.\n");
28972  }
28973  }
28974 
28975  // The number of tets excluding hull tets.
28976  ntets = tetrahedrons->items - hullsize;
28977 
28978  eextras = numelemattrib;
28979  if (out == (tetgenio *) NULL) {
28980  outfile = fopen(outelefilename, "w");
28981  if (outfile == (FILE *) NULL) {
28982  printf("File I/O Error: Cannot create file %s.\n", outelefilename);
28983  terminatetetgen(this, 1);
28984  }
28985  // Number of tetras, points per tetra, attributes per tetra.
28986  fprintf(outfile, "%ld %d %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
28987  } else {
28988  // Allocate memory for output tetrahedra.
28989  out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
28990  if (out->tetrahedronlist == (int *) NULL) {
28991  printf("Error: Out of memory.\n");
28992  terminatetetgen(this, 1);
28993  }
28994  // Allocate memory for output tetrahedron attributes if necessary.
28995  if (eextras > 0) {
28996  out->tetrahedronattributelist = new REAL[ntets * eextras];
28997  if (out->tetrahedronattributelist == (REAL *) NULL) {
28998  printf("Error: Out of memory.\n");
28999  terminatetetgen(this, 1);
29000  }
29001  }
29002  out->numberoftetrahedra = ntets;
29003  out->numberofcorners = b->order == 1 ? 4 : 10;
29004  out->numberoftetrahedronattributes = eextras;
29005  tlist = out->tetrahedronlist;
29006  talist = out->tetrahedronattributelist;
29007  pointindex = 0;
29008  attribindex = 0;
29009  }
29010 
29011  // Determine the first index (0 or 1).
29012  firstindex = b->zeroindex ? 0 : in->firstnumber;
29013  shift = 0; // Default no shift.
29014  if ((in->firstnumber == 1) && (firstindex == 0)) {
29015  shift = 1; // Shift the output indices by 1.
29016  }
29017 
29019  tptr = tetrahedrontraverse();
29020  elementnumber = firstindex; // in->firstnumber;
29021  while (tptr != (tetrahedron *) NULL) {
29022  if (!b->reversetetori) {
29023  p1 = (point) tptr[4];
29024  p2 = (point) tptr[5];
29025  } else {
29026  p1 = (point) tptr[5];
29027  p2 = (point) tptr[4];
29028  }
29029  p3 = (point) tptr[6];
29030  p4 = (point) tptr[7];
29031  if (out == (tetgenio *) NULL) {
29032  // Tetrahedron number, indices for four points.
29033  fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
29034  pointmark(p1) - shift, pointmark(p2) - shift,
29035  pointmark(p3) - shift, pointmark(p4) - shift);
29036  if (b->order == 2) {
29037  extralist = (point *) tptr[highorderindex];
29038  // indices for six extra points.
29039  fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
29040  pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
29041  pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
29042  pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
29043  }
29044  for (i = 0; i < eextras; i++) {
29045  fprintf(outfile, " %.17g", elemattribute(tptr, i));
29046  }
29047  fprintf(outfile, "\n");
29048  } else {
29049  tlist[pointindex++] = pointmark(p1) - shift;
29050  tlist[pointindex++] = pointmark(p2) - shift;
29051  tlist[pointindex++] = pointmark(p3) - shift;
29052  tlist[pointindex++] = pointmark(p4) - shift;
29053  if (b->order == 2) {
29054  extralist = (point *) tptr[highorderindex];
29055  tlist[pointindex++] = pointmark(extralist[0]) - shift;
29056  tlist[pointindex++] = pointmark(extralist[1]) - shift;
29057  tlist[pointindex++] = pointmark(extralist[2]) - shift;
29058  tlist[pointindex++] = pointmark(extralist[3]) - shift;
29059  tlist[pointindex++] = pointmark(extralist[4]) - shift;
29060  tlist[pointindex++] = pointmark(extralist[5]) - shift;
29061  }
29062  for (i = 0; i < eextras; i++) {
29063  talist[attribindex++] = elemattribute(tptr, i);
29064  }
29065  }
29066  // Remember the index of this element (for counting edges).
29067  setelemindex(tptr, elementnumber);
29068  tptr = tetrahedrontraverse();
29069  elementnumber++;
29070  }
29071 
29072 
29073  if (out == (tetgenio *) NULL) {
29074  fprintf(outfile, "# Generated by %s\n", b->commandline);
29075  fclose(outfile);
29076  }
29077 }
29078 
29080 // //
29081 // outfaces() Output all faces to a .face file or a tetgenio object. //
29082 // //
29084 
29086 {
29087  FILE *outfile = NULL;
29088  char facefilename[FILENAMESIZE];
29089  triface tface, tsymface;
29090  face checkmark;
29091  point torg, tdest, tapex;
29092  long ntets, faces;
29093  int *elist = NULL, *emlist = NULL;
29094  int neigh1 = 0, neigh2 = 0;
29095  int faceid, marker = 0;
29096  int firstindex, shift;
29097  int facenumber;
29098  int index = 0;
29099 
29100  // For -o2 option.
29101  triface workface;
29102  point *extralist, pp[3] = {0,0,0};
29103  int highorderindex = 11;
29104  int o2index = 0, i;
29105 
29106  if (out == (tetgenio *) NULL) {
29107  strcpy(facefilename, b->outfilename);
29108  strcat(facefilename, ".face");
29109  }
29110 
29111  if (!b->quiet) {
29112  if (out == (tetgenio *) NULL) {
29113  printf("Writing %s.\n", facefilename);
29114  } else {
29115  printf("Writing faces.\n");
29116  }
29117  }
29118 
29119  ntets = tetrahedrons->items - hullsize;
29120  faces = (ntets * 4l + hullsize) / 2l;
29121 
29122  if (out == (tetgenio *) NULL) {
29123  outfile = fopen(facefilename, "w");
29124  if (outfile == (FILE *) NULL) {
29125  printf("File I/O Error: Cannot create file %s.\n", facefilename);
29126  terminatetetgen(this, 1);
29127  }
29128  fprintf(outfile, "%ld %d\n", faces, !b->nobound);
29129  } else {
29130  // Allocate memory for 'trifacelist'.
29131  out->trifacelist = new int[faces * 3];
29132  if (out->trifacelist == (int *) NULL) {
29133  printf("Error: Out of memory.\n");
29134  terminatetetgen(this, 1);
29135  }
29136  if (b->order == 2) {
29137  out->o2facelist = new int[faces * 3];
29138  }
29139  // Allocate memory for 'trifacemarkerlist' if necessary.
29140  if (!b->nobound) {
29141  out->trifacemarkerlist = new int[faces];
29142  if (out->trifacemarkerlist == (int *) NULL) {
29143  printf("Error: Out of memory.\n");
29144  terminatetetgen(this, 1);
29145  }
29146  }
29147  if (b->neighout > 1) {
29148  // '-nn' switch.
29149  out->adjtetlist = new int[faces * 2];
29150  if (out->adjtetlist == (int *) NULL) {
29151  printf("Error: Out of memory.\n");
29152  terminatetetgen(this, 1);
29153  }
29154  }
29155  out->numberoftrifaces = faces;
29156  elist = out->trifacelist;
29157  emlist = out->trifacemarkerlist;
29158  }
29159 
29160  // Determine the first index (0 or 1).
29161  firstindex = b->zeroindex ? 0 : in->firstnumber;
29162  shift = 0; // Default no shiftment.
29163  if ((in->firstnumber == 1) && (firstindex == 0)) {
29164  shift = 1; // Shift the output indices by 1.
29165  }
29166 
29168  tface.tet = tetrahedrontraverse();
29169  facenumber = firstindex; // in->firstnumber;
29170  // To loop over the set of faces, loop over all tetrahedra, and look at
29171  // the four faces of each one. If its adjacent tet is a hull tet,
29172  // operate on the face, otherwise, operate on the face only if the
29173  // current tet has a smaller index than its neighbor.
29174  while (tface.tet != (tetrahedron *) NULL) {
29175  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
29176  fsym(tface, tsymface);
29177  if (ishulltet(tsymface) ||
29178  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
29179  torg = org(tface);
29180  tdest = dest(tface);
29181  tapex = apex(tface);
29182  if (b->order == 2) { // -o2
29183  // Get the three extra vertices on edges.
29184  extralist = (point *) (tface.tet[highorderindex]);
29185  // The extra vertices are on edges opposite the corners.
29186  enext(tface, workface);
29187  for (i = 0; i < 3; i++) {
29188  pp[i] = extralist[ver2edge[workface.ver]];
29189  enextself(workface);
29190  }
29191  }
29192  if (!b->nobound) {
29193  // Get the boundary marker of this face.
29194  if (b->plc || b->refine) {
29195  // Shell face is used.
29196  tspivot(tface, checkmark);
29197  if (checkmark.sh == NULL) {
29198  marker = 0; // It is an inner face. It's marker is 0.
29199  } else {
29200  if (in->facetmarkerlist) {
29201  // The facet marker is given, get it.
29202  faceid = shellmark(checkmark) - 1;
29203  marker = in->facetmarkerlist[faceid];
29204  } else {
29205  marker = 1; // The default marker for subface is 1.
29206  }
29207  }
29208  } else {
29209  // Shell face is not used, only distinguish outer and inner face.
29210  marker = (int) ishulltet(tsymface);
29211  }
29212  }
29213  if (b->neighout > 1) {
29214  // '-nn' switch. Output adjacent tets indices.
29215  neigh1 = elemindex(tface.tet);
29216  if (!ishulltet(tsymface)) {
29217  neigh2 = elemindex(tsymface.tet);
29218  } else {
29219  neigh2 = -1;
29220  }
29221  }
29222  if (out == (tetgenio *) NULL) {
29223  // Face number, indices of three vertices.
29224  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29225  pointmark(torg) - shift, pointmark(tdest) - shift,
29226  pointmark(tapex) - shift);
29227  if (b->order == 2) { // -o2
29228  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
29229  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29230  }
29231  if (!b->nobound) {
29232  // Output a boundary marker.
29233  fprintf(outfile, " %d", marker);
29234  }
29235  if (b->neighout > 1) {
29236  fprintf(outfile, " %5d %5d", neigh1, neigh2);
29237  }
29238  fprintf(outfile, "\n");
29239  } else {
29240  // Output indices of three vertices.
29241  elist[index++] = pointmark(torg) - shift;
29242  elist[index++] = pointmark(tdest) - shift;
29243  elist[index++] = pointmark(tapex) - shift;
29244  if (b->order == 2) { // -o2
29245  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29246  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29247  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29248  }
29249  if (!b->nobound) {
29250  emlist[facenumber - in->firstnumber] = marker;
29251  }
29252  if (b->neighout > 1) {
29253  out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1;
29254  out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
29255  }
29256  }
29257  facenumber++;
29258  }
29259  }
29260  tface.tet = tetrahedrontraverse();
29261  }
29262 
29263  if (out == (tetgenio *) NULL) {
29264  fprintf(outfile, "# Generated by %s\n", b->commandline);
29265  fclose(outfile);
29266  }
29267 }
29268 
29270 // //
29271 // outhullfaces() Output hull faces to a .face file or a tetgenio object. //
29272 // //
29273 // The normal of each face is pointing to the outside of the domain. //
29274 // //
29276 
29278 {
29279  FILE *outfile = NULL;
29280  char facefilename[FILENAMESIZE];
29281  triface hulltet;
29282  point torg, tdest, tapex;
29283  int *elist = NULL;
29284  int firstindex, shift;
29285  int facenumber;
29286  int index;
29287 
29288  if (out == (tetgenio *) NULL) {
29289  strcpy(facefilename, b->outfilename);
29290  strcat(facefilename, ".face");
29291  }
29292 
29293  if (!b->quiet) {
29294  if (out == (tetgenio *) NULL) {
29295  printf("Writing %s.\n", facefilename);
29296  } else {
29297  printf("Writing faces.\n");
29298  }
29299  }
29300 
29301  if (out == (tetgenio *) NULL) {
29302  outfile = fopen(facefilename, "w");
29303  if (outfile == (FILE *) NULL) {
29304  printf("File I/O Error: Cannot create file %s.\n", facefilename);
29305  terminatetetgen(this, 1);
29306  }
29307  fprintf(outfile, "%ld 0\n", hullsize);
29308  } else {
29309  // Allocate memory for 'trifacelist'.
29310  out->trifacelist = new int[hullsize * 3];
29311  if (out->trifacelist == (int *) NULL) {
29312  printf("Error: Out of memory.\n");
29313  terminatetetgen(this, 1);
29314  }
29315  out->numberoftrifaces = hullsize;
29316  elist = out->trifacelist;
29317  index = 0;
29318  }
29319 
29320  // Determine the first index (0 or 1).
29321  firstindex = b->zeroindex ? 0 : in->firstnumber;
29322  shift = 0; // Default no shiftment.
29323  if ((in->firstnumber == 1) && (firstindex == 0)) {
29324  shift = 1; // Shift the output indices by 1.
29325  }
29326 
29328  hulltet.tet = alltetrahedrontraverse();
29329  facenumber = firstindex;
29330  while (hulltet.tet != (tetrahedron *) NULL) {
29331  if (ishulltet(hulltet)) {
29332  torg = (point) hulltet.tet[4];
29333  tdest = (point) hulltet.tet[5];
29334  tapex = (point) hulltet.tet[6];
29335  if (out == (tetgenio *) NULL) {
29336  // Face number, indices of three vertices.
29337  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29338  pointmark(torg) - shift, pointmark(tdest) - shift,
29339  pointmark(tapex) - shift);
29340  fprintf(outfile, "\n");
29341  } else {
29342  // Output indices of three vertices.
29343  elist[index++] = pointmark(torg) - shift;
29344  elist[index++] = pointmark(tdest) - shift;
29345  elist[index++] = pointmark(tapex) - shift;
29346  }
29347  facenumber++;
29348  }
29349  hulltet.tet = alltetrahedrontraverse();
29350  }
29351 
29352  if (out == (tetgenio *) NULL) {
29353  fprintf(outfile, "# Generated by %s\n", b->commandline);
29354  fclose(outfile);
29355  }
29356 }
29357 
29359 // //
29360 // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
29361 // a tetgenio structure. //
29362 // //
29363 // The boundary faces are found in 'subfaces'. For listing triangle vertices //
29364 // in the same sense for all triangles in the mesh, the direction determined //
29365 // by right-hand rule is pointer to the inside of the volume. //
29366 // //
29368 
29370 {
29371  FILE *outfile = NULL;
29372  char facefilename[FILENAMESIZE];
29373  int *elist = NULL;
29374  int *emlist = NULL;
29375  int index = 0, index1 = 0, index2 = 0;
29376  triface abuttingtet;
29377  face faceloop;
29378  point torg, tdest, tapex;
29379  int faceid = 0, marker = 0;
29380  int firstindex, shift;
29381  int neigh1 = 0, neigh2 = 0;
29382  int facenumber;
29383 
29384  // For -o2 option.
29385  triface workface;
29386  point *extralist, pp[3] = {0,0,0};
29387  int highorderindex = 11;
29388  int o2index = 0, i;
29389 
29390  int t1ver; // used by fsymself()
29391 
29392  if (out == (tetgenio *) NULL) {
29393  strcpy(facefilename, b->outfilename);
29394  strcat(facefilename, ".face");
29395  }
29396 
29397  if (!b->quiet) {
29398  if (out == (tetgenio *) NULL) {
29399  printf("Writing %s.\n", facefilename);
29400  } else {
29401  printf("Writing faces.\n");
29402  }
29403  }
29404 
29405  if (out == (tetgenio *) NULL) {
29406  outfile = fopen(facefilename, "w");
29407  if (outfile == (FILE *) NULL) {
29408  printf("File I/O Error: Cannot create file %s.\n", facefilename);
29409  terminatetetgen(this, 3);
29410  }
29411  // Number of subfaces.
29412  fprintf(outfile, "%ld %d\n", subfaces->items, !b->nobound);
29413  } else {
29414  // Allocate memory for 'trifacelist'.
29415  out->trifacelist = new int[subfaces->items * 3];
29416  if (out->trifacelist == (int *) NULL) {
29417  terminatetetgen(this, 1);
29418  }
29419  if (b->order == 2) {
29420  out->o2facelist = new int[subfaces->items * 3];
29421  }
29422  if (!b->nobound) {
29423  // Allocate memory for 'trifacemarkerlist'.
29424  out->trifacemarkerlist = new int[subfaces->items];
29425  if (out->trifacemarkerlist == (int *) NULL) {
29426  terminatetetgen(this, 1);
29427  }
29428  }
29429  if (b->neighout > 1) {
29430  // '-nn' switch.
29431  out->adjtetlist = new int[subfaces->items * 2];
29432  if (out->adjtetlist == (int *) NULL) {
29433  terminatetetgen(this, 1);
29434  }
29435  }
29437  elist = out->trifacelist;
29438  emlist = out->trifacemarkerlist;
29439  }
29440 
29441  // Determine the first index (0 or 1).
29442  firstindex = b->zeroindex ? 0 : in->firstnumber;
29443  shift = 0; // Default no shiftment.
29444  if ((in->firstnumber == 1) && (firstindex == 0)) {
29445  shift = 1; // Shift the output indices by 1.
29446  }
29447 
29449  faceloop.sh = shellfacetraverse(subfaces);
29450  facenumber = firstindex; // in->firstnumber;
29451  while (faceloop.sh != (shellface *) NULL) {
29452  stpivot(faceloop, abuttingtet);
29453  // If there is a tetrahedron containing this subface, orient it so
29454  // that the normal of this face points to inside of the volume by
29455  // right-hand rule.
29456  if (abuttingtet.tet != NULL) {
29457  if (ishulltet(abuttingtet)) {
29458  fsymself(abuttingtet);
29459  assert(!ishulltet(abuttingtet));
29460  }
29461  }
29462  if (abuttingtet.tet != NULL) {
29463  torg = org(abuttingtet);
29464  tdest = dest(abuttingtet);
29465  tapex = apex(abuttingtet);
29466  if (b->order == 2) { // -o2
29467  // Get the three extra vertices on edges.
29468  extralist = (point *) (abuttingtet.tet[highorderindex]);
29469  workface = abuttingtet;
29470  for (i = 0; i < 3; i++) {
29471  pp[i] = extralist[ver2edge[workface.ver]];
29472  enextself(workface);
29473  }
29474  }
29475  } else {
29476  // This may happen when only a surface mesh be generated.
29477  torg = sorg(faceloop);
29478  tdest = sdest(faceloop);
29479  tapex = sapex(faceloop);
29480  if (b->order == 2) { // -o2
29481  // There is no extra node list available.
29482  pp[0] = torg;
29483  pp[1] = tdest;
29484  pp[2] = tapex;
29485  }
29486  }
29487  if (!b->nobound) {
29488  if (b->refine) { // -r option.
29489  if (in->trifacemarkerlist) {
29490  marker = shellmark(faceloop);
29491  } else {
29492  marker = 1; // Default marker for a subface is 1.
29493  }
29494  } else {
29495  if (in->facetmarkerlist) {
29496  faceid = shellmark(faceloop) - 1;
29497  marker = in->facetmarkerlist[faceid];
29498  } else {
29499  marker = 1; // Default marker for a subface is 1.
29500  }
29501  }
29502  }
29503  if (b->neighout > 1) {
29504  // '-nn' switch. Output adjacent tets indices.
29505  neigh1 = -1;
29506  neigh2 = -1;
29507  stpivot(faceloop, abuttingtet);
29508  if (abuttingtet.tet != NULL) {
29509  neigh1 = elemindex(abuttingtet.tet);
29510  fsymself(abuttingtet);
29511  if (!ishulltet(abuttingtet)) {
29512  neigh2 = elemindex(abuttingtet.tet);
29513  }
29514  }
29515  }
29516  if (out == (tetgenio *) NULL) {
29517  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
29518  pointmark(torg) - shift, pointmark(tdest) - shift,
29519  pointmark(tapex) - shift);
29520  if (b->order == 2) { // -o2
29521  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
29522  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29523  }
29524  if (!b->nobound) {
29525  fprintf(outfile, " %d", marker);
29526  }
29527  if (b->neighout > 1) {
29528  fprintf(outfile, " %5d %5d", neigh1, neigh2);
29529  }
29530  fprintf(outfile, "\n");
29531  } else {
29532  // Output three vertices of this face;
29533  elist[index++] = pointmark(torg) - shift;
29534  elist[index++] = pointmark(tdest) - shift;
29535  elist[index++] = pointmark(tapex) - shift;
29536  if (b->order == 2) { // -o2
29537  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29538  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29539  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29540  }
29541  if (!b->nobound) {
29542  emlist[index1++] = marker;
29543  }
29544  if (b->neighout > 1) {
29545  out->adjtetlist[index2++] = neigh1;
29546  out->adjtetlist[index2++] = neigh2;
29547  }
29548  }
29549  facenumber++;
29550  faceloop.sh = shellfacetraverse(subfaces);
29551  }
29552 
29553  if (out == (tetgenio *) NULL) {
29554  fprintf(outfile, "# Generated by %s\n", b->commandline);
29555  fclose(outfile);
29556  }
29557 }
29558 
29560 // //
29561 // outedges() Output all edges to a .edge file or a tetgenio object. //
29562 // //
29563 // Note: This routine must be called after outelements(), so that the total //
29564 // number of edges 'meshedges' has been counted. //
29565 // //
29567 
29569 {
29570  FILE *outfile = NULL;
29571  char edgefilename[FILENAMESIZE];
29572  triface tetloop, worktet, spintet;
29573  face checkseg;
29574  point torg, tdest;
29575  int *elist = NULL, *emlist = NULL;
29576  int ishulledge;
29577  int firstindex, shift;
29578  int edgenumber, marker;
29579  int index = 0, index1 = 0, index2 = 0;
29580  int t1ver;
29581  int i;
29582 
29583  // For -o2 option.
29584  point *extralist, pp = NULL;
29585  int highorderindex = 11;
29586  int o2index = 0;
29587 
29588  if (out == (tetgenio *) NULL) {
29589  strcpy(edgefilename, b->outfilename);
29590  strcat(edgefilename, ".edge");
29591  }
29592 
29593  if (!b->quiet) {
29594  if (out == (tetgenio *) NULL) {
29595  printf("Writing %s.\n", edgefilename);
29596  } else {
29597  printf("Writing edges.\n");
29598  }
29599  }
29600 
29601  if (meshedges == 0l) {
29602  if (nonconvex) {
29603  numberedges(); // Count the edges.
29604  } else {
29605  // Use Euler's characteristic to get the numbe of edges.
29606  // It states V - E + F - C = 1, hence E = V + F - C - 1.
29607  long tsize = tetrahedrons->items - hullsize;
29608  long fsize = (tsize * 4l + hullsize) / 2l;
29609  long vsize = points->items - dupverts - unuverts;
29610  if (b->weighted) vsize -= nonregularcount;
29611  meshedges = vsize + fsize - tsize - 1;
29612  }
29613  }
29614 
29615  if (out == (tetgenio *) NULL) {
29616  outfile = fopen(edgefilename, "w");
29617  if (outfile == (FILE *) NULL) {
29618  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
29619  terminatetetgen(this, 1);
29620  }
29621  // Write the number of edges, boundary markers (0 or 1).
29622  fprintf(outfile, "%ld %d\n", meshedges, !b->nobound);
29623  } else {
29624  // Allocate memory for 'edgelist'.
29625  out->edgelist = new int[meshedges * 2];
29626  if (out->edgelist == (int *) NULL) {
29627  printf("Error: Out of memory.\n");
29628  terminatetetgen(this, 1);
29629  }
29630  if (b->order == 2) { // -o2 switch
29631  out->o2edgelist = new int[meshedges];
29632  }
29633  if (!b->nobound) {
29634  out->edgemarkerlist = new int[meshedges];
29635  }
29636  if (b->neighout > 1) { // '-nn' switch.
29637  out->edgeadjtetlist = new int[meshedges];
29638  }
29639  out->numberofedges = meshedges;
29640  elist = out->edgelist;
29641  emlist = out->edgemarkerlist;
29642  }
29643 
29644  // Determine the first index (0 or 1).
29645  firstindex = b->zeroindex ? 0 : in->firstnumber;
29646  shift = 0; // Default no shiftment.
29647  if ((in->firstnumber == 1) && (firstindex == 0)) {
29648  shift = 1; // Shift (reduce) the output indices by 1.
29649  }
29650 
29652  tetloop.tet = tetrahedrontraverse();
29653  edgenumber = firstindex; // in->firstnumber;
29654  while (tetloop.tet != (tetrahedron *) NULL) {
29655  // Count the number of Voronoi faces.
29656  worktet.tet = tetloop.tet;
29657  for (i = 0; i < 6; i++) {
29658  worktet.ver = edge2ver[i];
29659  ishulledge = 0;
29660  fnext(worktet, spintet);
29661  do {
29662  if (!ishulltet(spintet)) {
29663  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
29664  } else {
29665  ishulledge = 1;
29666  }
29667  fnextself(spintet);
29668  } while (spintet.tet != worktet.tet);
29669  // Count this edge if no adjacent tets are smaller than this tet.
29670  if (spintet.tet == worktet.tet) {
29671  torg = org(worktet);
29672  tdest = dest(worktet);
29673  if (b->order == 2) { // -o2
29674  // Get the extra vertex on this edge.
29675  extralist = (point *) worktet.tet[highorderindex];
29676  pp = extralist[ver2edge[worktet.ver]];
29677  }
29678  if (out == (tetgenio *) NULL) {
29679  fprintf(outfile, "%5d %4d %4d", edgenumber,
29680  pointmark(torg) - shift, pointmark(tdest) - shift);
29681  if (b->order == 2) { // -o2
29682  fprintf(outfile, " %4d", pointmark(pp) - shift);
29683  }
29684  } else {
29685  // Output three vertices of this face;
29686  elist[index++] = pointmark(torg) - shift;
29687  elist[index++] = pointmark(tdest) - shift;
29688  if (b->order == 2) { // -o2
29689  out->o2edgelist[o2index++] = pointmark(pp) - shift;
29690  }
29691  }
29692  if (!b->nobound) {
29693  if (b->plc || b->refine) {
29694  // Check if the edge is a segment.
29695  tsspivot1(worktet, checkseg);
29696  if (checkseg.sh != NULL) {
29697  marker = shellmark(checkseg);
29698  if (marker == 0) { // Does it have no marker?
29699  marker = 1; // Set the default marker for this segment.
29700  }
29701  } else {
29702  marker = 0; // It's not a segment.
29703  }
29704  } else {
29705  // Mark it if it is a hull edge.
29706  marker = ishulledge ? 1 : 0;
29707  }
29708  if (out == (tetgenio *) NULL) {
29709  fprintf(outfile, " %d", marker);
29710  } else {
29711  emlist[index1++] = marker;
29712  }
29713  }
29714  if (b->neighout > 1) { // '-nn' switch.
29715  if (out == (tetgenio *) NULL) {
29716  fprintf(outfile, " %d", elemindex(tetloop.tet));
29717  } else {
29718  out->edgeadjtetlist[index2++] = elemindex(tetloop.tet);
29719  }
29720  }
29721  if (out == (tetgenio *) NULL) {
29722  fprintf(outfile, "\n");
29723  }
29724  edgenumber++;
29725  }
29726  }
29727  tetloop.tet = tetrahedrontraverse();
29728  }
29729 
29730  if (out == (tetgenio *) NULL) {
29731  fprintf(outfile, "# Generated by %s\n", b->commandline);
29732  fclose(outfile);
29733  }
29734 }
29735 
29737 // //
29738 // outsubsegments() Output segments to a .edge file or a structure. //
29739 // //
29741 
29743 {
29744  FILE *outfile = NULL;
29745  char edgefilename[FILENAMESIZE];
29746  int *elist = NULL;
29747  int index, i;
29748  face edgeloop;
29749  point torg, tdest;
29750  int firstindex, shift;
29751  int marker;
29752  int edgenumber;
29753 
29754  // For -o2 option.
29755  triface workface, spintet;
29756  point *extralist, pp = NULL;
29757  int highorderindex = 11;
29758  int o2index = 0;
29759 
29760  // For -nn option.
29761  int neigh = -1;
29762  int index2 = 0;
29763 
29764  int t1ver; // used by fsymself()
29765 
29766  if (out == (tetgenio *) NULL) {
29767  strcpy(edgefilename, b->outfilename);
29768  strcat(edgefilename, ".edge");
29769  }
29770 
29771  if (!b->quiet) {
29772  if (out == (tetgenio *) NULL) {
29773  printf("Writing %s.\n", edgefilename);
29774  } else {
29775  printf("Writing edges.\n");
29776  }
29777  }
29778 
29779  if (out == (tetgenio *) NULL) {
29780  outfile = fopen(edgefilename, "w");
29781  if (outfile == (FILE *) NULL) {
29782  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
29783  terminatetetgen(this, 3);
29784  }
29785  // Number of subsegments.
29786  fprintf(outfile, "%ld 1\n", subsegs->items);
29787  } else {
29788  // Allocate memory for 'edgelist'.
29789  out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
29790  if (out->edgelist == (int *) NULL) {
29791  terminatetetgen(this, 1);
29792  }
29793  if (b->order == 2) {
29794  out->o2edgelist = new int[subsegs->items];
29795  }
29796  out->edgemarkerlist = new int[subsegs->items];
29797  if (out->edgemarkerlist == (int *) NULL) {
29798  terminatetetgen(this, 1);
29799  }
29800  if (b->neighout > 1) {
29801  out->edgeadjtetlist = new int[subsegs->items];
29802  }
29803  out->numberofedges = subsegs->items;
29804  elist = out->edgelist;
29805  }
29806 
29807  // Determine the first index (0 or 1).
29808  firstindex = b->zeroindex ? 0 : in->firstnumber;
29809  shift = 0; // Default no shiftment.
29810  if ((in->firstnumber == 1) && (firstindex == 0)) {
29811  shift = 1; // Shift the output indices by 1.
29812  }
29813  index = 0;
29814  i = 0;
29815 
29817  edgeloop.sh = shellfacetraverse(subsegs);
29818  edgenumber = firstindex; // in->firstnumber;
29819  while (edgeloop.sh != (shellface *) NULL) {
29820  torg = sorg(edgeloop);
29821  tdest = sdest(edgeloop);
29822  if ((b->order == 2) || (b->neighout > 1)) {
29823  sstpivot1(edgeloop, workface);
29824  if (workface.tet != NULL) {
29825  // We must find a non-hull tet.
29826  if (ishulltet(workface)) {
29827  spintet = workface;
29828  while (1) {
29829  fnextself(spintet);
29830  if (!ishulltet(spintet)) break;
29831  if (spintet.tet == workface.tet) break;
29832  }
29833  assert(!ishulltet(spintet));
29834  workface = spintet;
29835  }
29836  }
29837  }
29838  if (b->order == 2) { // -o2
29839  // Get the extra vertex on this edge.
29840  if (workface.tet != NULL) {
29841  extralist = (point *) workface.tet[highorderindex];
29842  pp = extralist[ver2edge[workface.ver]];
29843  } else {
29844  pp = torg; // There is no extra node available.
29845  }
29846  }
29847  if (b->neighout > 1) { // -nn
29848  if (workface.tet != NULL) {
29849  neigh = elemindex(workface.tet);
29850  } else {
29851  neigh = -1;
29852  }
29853  }
29854  marker = shellmark(edgeloop);
29855  if (marker == 0) {
29856  marker = 1; // Default marker of a boundary edge is 1.
29857  }
29858  if (out == (tetgenio *) NULL) {
29859  fprintf(outfile, "%5d %4d %4d", edgenumber,
29860  pointmark(torg) - shift, pointmark(tdest) - shift);
29861  if (b->order == 2) { // -o2
29862  fprintf(outfile, " %4d", pointmark(pp) - shift);
29863  }
29864  fprintf(outfile, " %d", marker);
29865  if (b->neighout > 1) { // -nn
29866  fprintf(outfile, " %4d", neigh);
29867  }
29868  fprintf(outfile, "\n");
29869  } else {
29870  // Output three vertices of this face;
29871  elist[index++] = pointmark(torg) - shift;
29872  elist[index++] = pointmark(tdest) - shift;
29873  if (b->order == 2) { // -o2
29874  out->o2edgelist[o2index++] = pointmark(pp) - shift;
29875  }
29876  out->edgemarkerlist[i++] = marker;
29877  if (b->neighout > 1) { // -nn
29878  out->edgeadjtetlist[index2++] = neigh;
29879  }
29880  }
29881  edgenumber++;
29882  edgeloop.sh = shellfacetraverse(subsegs);
29883  }
29884 
29885  if (out == (tetgenio *) NULL) {
29886  fprintf(outfile, "# Generated by %s\n", b->commandline);
29887  fclose(outfile);
29888  }
29889 }
29890 
29892 // //
29893 // outneighbors() Output tet neighbors to a .neigh file or a structure. //
29894 // //
29896 
29898 {
29899  FILE *outfile = NULL;
29900  char neighborfilename[FILENAMESIZE];
29901  int *nlist = NULL;
29902  int index = 0;
29903  triface tetloop, tetsym;
29904  int neighbori[4];
29905  int firstindex;
29906  int elementnumber;
29907  long ntets;
29908 
29909  if (out == (tetgenio *) NULL) {
29910  strcpy(neighborfilename, b->outfilename);
29911  strcat(neighborfilename, ".neigh");
29912  }
29913 
29914  if (!b->quiet) {
29915  if (out == (tetgenio *) NULL) {
29916  printf("Writing %s.\n", neighborfilename);
29917  } else {
29918  printf("Writing neighbors.\n");
29919  }
29920  }
29921 
29922  ntets = tetrahedrons->items - hullsize;
29923 
29924  if (out == (tetgenio *) NULL) {
29925  outfile = fopen(neighborfilename, "w");
29926  if (outfile == (FILE *) NULL) {
29927  printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
29928  terminatetetgen(this, 1);
29929  }
29930  // Number of tetrahedra, four faces per tetrahedron.
29931  fprintf(outfile, "%ld %d\n", ntets, 4);
29932  } else {
29933  // Allocate memory for 'neighborlist'.
29934  out->neighborlist = new int[ntets * 4];
29935  if (out->neighborlist == (int *) NULL) {
29936  printf("Error: Out of memory.\n");
29937  terminatetetgen(this, 1);
29938  }
29939  nlist = out->neighborlist;
29940  }
29941 
29942  // Determine the first index (0 or 1).
29943  firstindex = b->zeroindex ? 0 : in->firstnumber;
29944 
29946  tetloop.tet = tetrahedrontraverse();
29947  elementnumber = firstindex; // in->firstnumber;
29948  while (tetloop.tet != (tetrahedron *) NULL) {
29949  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
29950  fsym(tetloop, tetsym);
29951  if (!ishulltet(tetsym)) {
29952  neighbori[tetloop.ver] = elemindex(tetsym.tet);
29953  } else {
29954  neighbori[tetloop.ver] = -1;
29955  }
29956  }
29957  if (out == (tetgenio *) NULL) {
29958  // Tetrahedra number, neighboring tetrahedron numbers.
29959  fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
29960  neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
29961  } else {
29962  nlist[index++] = neighbori[0];
29963  nlist[index++] = neighbori[1];
29964  nlist[index++] = neighbori[2];
29965  nlist[index++] = neighbori[3];
29966  }
29967  tetloop.tet = tetrahedrontraverse();
29968  elementnumber++;
29969  }
29970 
29971  if (out == (tetgenio *) NULL) {
29972  fprintf(outfile, "# Generated by %s\n", b->commandline);
29973  fclose(outfile);
29974  }
29975 }
29976 
29978 // //
29979 // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
29980 // and .v.cell. //
29981 // //
29982 // The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
29983 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
29984 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
29985 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
29986 // A Voronoi face is the convex hull of all Voronoi vertices around a common //
29987 // Delaunay edge. It is a closed polygon for any internal Delaunay edge. At a//
29988 // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
29989 // onoi vertices around a common Delaunay vertex. It is a polytope for any //
29990 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
29991 // vertex belonging to the convex hull. //
29992 // //
29993 // NOTE: This routine is only used when the input is only a set of point. //
29994 // Comment: Special thanks to Victor Liu for finding and fixing few bugs. //
29995 // //
29997 
29999 {
30000  FILE *outfile = NULL;
30001  char outfilename[FILENAMESIZE];
30002  tetgenio::voroedge *vedge = NULL;
30003  tetgenio::vorofacet *vfacet = NULL;
30004  arraypool *tetlist, *ptlist;
30005  triface tetloop, worktet, spintet, firsttet;
30006  point pt[4], ploop, neipt;
30007  REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
30008  long ntets, faces, edges;
30009  int *indexarray, *fidxs, *eidxs;
30010  int arraysize, *vertarray = NULL;
30011  int vpointcount, vedgecount, vfacecount, tcount;
30012  int ishullvert, ishullface;
30013  int index, shift, end1, end2;
30014  int i, j;
30015 
30016  int t1ver; // used by fsymself()
30017 
30018  // Output Voronoi vertices to .v.node file.
30019  if (out == (tetgenio *) NULL) {
30020  strcpy(outfilename, b->outfilename);
30021  strcat(outfilename, ".v.node");
30022  }
30023 
30024  if (!b->quiet) {
30025  if (out == (tetgenio *) NULL) {
30026  printf("Writing %s.\n", outfilename);
30027  } else {
30028  printf("Writing Voronoi vertices.\n");
30029  }
30030  }
30031 
30032  // Determine the first index (0 or 1).
30033  shift = (b->zeroindex ? 0 : in->firstnumber);
30034 
30035  // Each face and edge of the tetrahedral mesh will be indexed for indexing
30036  // the Voronoi edges and facets. Indices of faces and edges are saved in
30037  // each tetrahedron (including hull tets).
30038 
30039  // Allocate the total space once.
30040  indexarray = new int[tetrahedrons->items * 10];
30041 
30042  // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
30043  // for element markers, flags.
30044  i = 0;
30046  tetloop.tet = alltetrahedrontraverse();
30047  while (tetloop.tet != NULL) {
30048  tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
30049  i++;
30050  tetloop.tet = alltetrahedrontraverse();
30051  }
30052 
30053  // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
30054  ntets = tetrahedrons->items - hullsize;
30055  // The number of Delaunay faces (Voronoi edges).
30056  faces = (4l * ntets + hullsize) / 2l;
30057  // The number of Delaunay edges (Voronoi faces).
30058  long vsize = points->items - dupverts - unuverts;
30059  if (b->weighted) vsize -= nonregularcount;
30060  edges = vsize + faces - ntets - 1;
30061 
30062  if (out == (tetgenio *) NULL) {
30063  outfile = fopen(outfilename, "w");
30064  if (outfile == (FILE *) NULL) {
30065  printf("File I/O Error: Cannot create file %s.\n", outfilename);
30066  terminatetetgen(this, 3);
30067  }
30068  // Number of voronoi points, 3 dim, no attributes, no marker.
30069  fprintf(outfile, "%ld 3 0 0\n", ntets);
30070  } else {
30071  // Allocate space for 'vpointlist'.
30072  out->numberofvpoints = (int) ntets;
30073  out->vpointlist = new REAL[out->numberofvpoints * 3];
30074  if (out->vpointlist == (REAL *) NULL) {
30075  terminatetetgen(this, 1);
30076  }
30077  }
30078 
30079  // Output Voronoi vertices (the circumcenters of tetrahedra).
30081  tetloop.tet = tetrahedrontraverse();
30082  vpointcount = 0; // The (internal) v-index always starts from 0.
30083  index = 0;
30084  while (tetloop.tet != (tetrahedron *) NULL) {
30085  for (i = 0; i < 4; i++) {
30086  pt[i] = (point) tetloop.tet[4 + i];
30087  setpoint2tet(pt[i], encode(tetloop));
30088  }
30089  if (b->weighted) {
30090  orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3],
30091  pt[3][3], ccent, NULL);
30092  } else {
30093  circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
30094  }
30095  if (out == (tetgenio *) NULL) {
30096  fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
30097  ccent[0], ccent[1], ccent[2]);
30098  } else {
30099  out->vpointlist[index++] = ccent[0];
30100  out->vpointlist[index++] = ccent[1];
30101  out->vpointlist[index++] = ccent[2];
30102  }
30103  setelemindex(tetloop.tet, vpointcount);
30104  vpointcount++;
30105  tetloop.tet = tetrahedrontraverse();
30106  }
30107 
30108  if (out == (tetgenio *) NULL) {
30109  fprintf(outfile, "# Generated by %s\n", b->commandline);
30110  fclose(outfile);
30111  }
30112 
30113  // Output Voronoi edges to .v.edge file.
30114  if (out == (tetgenio *) NULL) {
30115  strcpy(outfilename, b->outfilename);
30116  strcat(outfilename, ".v.edge");
30117  }
30118 
30119  if (!b->quiet) {
30120  if (out == (tetgenio *) NULL) {
30121  printf("Writing %s.\n", outfilename);
30122  } else {
30123  printf("Writing Voronoi edges.\n");
30124  }
30125  }
30126 
30127  if (out == (tetgenio *) NULL) {
30128  outfile = fopen(outfilename, "w");
30129  if (outfile == (FILE *) NULL) {
30130  printf("File I/O Error: Cannot create file %s.\n", outfilename);
30131  terminatetetgen(this, 3);
30132  }
30133  // Number of Voronoi edges, no marker.
30134  fprintf(outfile, "%ld 0\n", faces);
30135  } else {
30136  // Allocate space for 'vpointlist'.
30137  out->numberofvedges = (int) faces;
30138  out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
30139  }
30140 
30141  // Output the Voronoi edges.
30143  tetloop.tet = tetrahedrontraverse();
30144  vedgecount = 0; // D-Face (V-edge) index (from zero).
30145  index = 0; // The Delaunay-face index.
30146  while (tetloop.tet != (tetrahedron *) NULL) {
30147  // Count the number of Voronoi edges. Look at the four faces of each
30148  // tetrahedron. Count the face if the tetrahedron's index is
30149  // smaller than its neighbor's or the neighbor is outside.
30150  end1 = elemindex(tetloop.tet);
30151  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
30152  fsym(tetloop, worktet);
30153  if (ishulltet(worktet) ||
30154  (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
30155  // Found a Voronoi edge. Operate on it.
30156  if (out == (tetgenio *) NULL) {
30157  fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
30158  } else {
30159  vedge = &(out->vedgelist[index++]);
30160  vedge->v1 = end1 + shift;
30161  }
30162  if (!ishulltet(worktet)) {
30163  end2 = elemindex(worktet.tet);
30164  } else {
30165  end2 = -1;
30166  }
30167  // Note that end2 may be -1 (worktet.tet is outside).
30168  if (end2 == -1) {
30169  // Calculate the out normal of this hull face.
30170  pt[0] = dest(worktet);
30171  pt[1] = org(worktet);
30172  pt[2] = apex(worktet);
30173  for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
30174  for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
30175  cross(vec1, vec2, infvec);
30176  // Normalize it.
30177  L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
30178  + infvec[2] * infvec[2]);
30179  if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
30180  if (out == (tetgenio *) NULL) {
30181  fprintf(outfile, " -1");
30182  fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
30183  } else {
30184  vedge->v2 = -1;
30185  vedge->vnormal[0] = infvec[0];
30186  vedge->vnormal[1] = infvec[1];
30187  vedge->vnormal[2] = infvec[2];
30188  }
30189  } else {
30190  if (out == (tetgenio *) NULL) {
30191  fprintf(outfile, " %4d\n", end2 + shift);
30192  } else {
30193  vedge->v2 = end2 + shift;
30194  vedge->vnormal[0] = 0.0;
30195  vedge->vnormal[1] = 0.0;
30196  vedge->vnormal[2] = 0.0;
30197  }
30198  }
30199  // Save the V-edge index in this tet and its neighbor.
30200  fidxs = (int *) (tetloop.tet[11]);
30201  fidxs[tetloop.ver] = vedgecount;
30202  fidxs = (int *) (worktet.tet[11]);
30203  fidxs[worktet.ver & 3] = vedgecount;
30204  vedgecount++;
30205  }
30206  } // tetloop.ver
30207  tetloop.tet = tetrahedrontraverse();
30208  }
30209 
30210  if (out == (tetgenio *) NULL) {
30211  fprintf(outfile, "# Generated by %s\n", b->commandline);
30212  fclose(outfile);
30213  }
30214 
30215  // Output Voronoi faces to .v.face file.
30216  if (out == (tetgenio *) NULL) {
30217  strcpy(outfilename, b->outfilename);
30218  strcat(outfilename, ".v.face");
30219  }
30220 
30221  if (!b->quiet) {
30222  if (out == (tetgenio *) NULL) {
30223  printf("Writing %s.\n", outfilename);
30224  } else {
30225  printf("Writing Voronoi faces.\n");
30226  }
30227  }
30228 
30229  if (out == (tetgenio *) NULL) {
30230  outfile = fopen(outfilename, "w");
30231  if (outfile == (FILE *) NULL) {
30232  printf("File I/O Error: Cannot create file %s.\n", outfilename);
30233  terminatetetgen(this, 3);
30234  }
30235  // Number of Voronoi faces.
30236  fprintf(outfile, "%ld 0\n", edges);
30237  } else {
30238  out->numberofvfacets = edges;
30240  if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
30241  terminatetetgen(this, 1);
30242  }
30243  }
30244 
30245  // Output the Voronoi facets.
30247  tetloop.tet = tetrahedrontraverse();
30248  vfacecount = 0; // D-edge (V-facet) index (from zero).
30249  while (tetloop.tet != (tetrahedron *) NULL) {
30250  // Count the number of Voronoi faces. Look at the six edges of each
30251  // tetrahedron. Count the edge only if the tetrahedron's index is
30252  // smaller than those of all other tetrahedra that share the edge.
30253  worktet.tet = tetloop.tet;
30254  for (i = 0; i < 6; i++) {
30255  worktet.ver = edge2ver[i];
30256  // Count the number of faces at this edge. If the edge is a hull edge,
30257  // the face containing dummypoint is also counted.
30258  //ishulledge = 0; // Is it a hull edge.
30259  tcount = 0;
30260  firsttet = worktet;
30261  spintet = worktet;
30262  while (1) {
30263  tcount++;
30264  fnextself(spintet);
30265  if (spintet.tet == worktet.tet) break;
30266  if (!ishulltet(spintet)) {
30267  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
30268  } else {
30269  //ishulledge = 1;
30270  if (apex(spintet) == dummypoint) {
30271  // We make this V-edge appear in the end of the edge list.
30272  fnext(spintet, firsttet);
30273  }
30274  }
30275  } // while (1)
30276  if (spintet.tet == worktet.tet) {
30277  // Found a Voronoi facet. Operate on it.
30278  pt[0] = org(worktet);
30279  pt[1] = dest(worktet);
30280  end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
30281  end2 = pointmark(pt[1]) - in->firstnumber;
30282  if (out == (tetgenio *) NULL) {
30283  fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
30284  end1 + shift, end2 + shift, tcount);
30285  } else {
30286  vfacet = &(out->vfacetlist[vfacecount]);
30287  vfacet->c1 = end1 + shift;
30288  vfacet->c2 = end2 + shift;
30289  vfacet->elist = new int[tcount + 1];
30290  vfacet->elist[0] = tcount;
30291  index = 1;
30292  }
30293  // Output V-edges of this V-facet.
30294  spintet = firsttet; //worktet;
30295  while (1) {
30296  fidxs = (int *) (spintet.tet[11]);
30297  if (apex(spintet) != dummypoint) {
30298  vedgecount = fidxs[spintet.ver & 3];
30299  ishullface = 0;
30300  } else {
30301  ishullface = 1; // It's not a real face.
30302  }
30303  if (out == (tetgenio *) NULL) {
30304  fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1);
30305  } else {
30306  vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
30307  }
30308  // Save the V-facet index in this tet at this edge.
30309  eidxs = &(fidxs[4]);
30310  eidxs[ver2edge[spintet.ver]] = vfacecount;
30311  // Go to the next face.
30312  fnextself(spintet);
30313  if (spintet.tet == firsttet.tet) break;
30314  } // while (1)
30315  if (out == (tetgenio *) NULL) {
30316  fprintf(outfile, "\n");
30317  }
30318  vfacecount++;
30319  } // if (spintet.tet == worktet.tet)
30320  } // if (i = 0; i < 6; i++)
30321  tetloop.tet = tetrahedrontraverse();
30322  }
30323 
30324  if (out == (tetgenio *) NULL) {
30325  fprintf(outfile, "# Generated by %s\n", b->commandline);
30326  fclose(outfile);
30327  }
30328 
30329  // Output Voronoi cells to .v.cell file.
30330  if (out == (tetgenio *) NULL) {
30331  strcpy(outfilename, b->outfilename);
30332  strcat(outfilename, ".v.cell");
30333  }
30334 
30335  if (!b->quiet) {
30336  if (out == (tetgenio *) NULL) {
30337  printf("Writing %s.\n", outfilename);
30338  } else {
30339  printf("Writing Voronoi cells.\n");
30340  }
30341  }
30342 
30343  if (out == (tetgenio *) NULL) {
30344  outfile = fopen(outfilename, "w");
30345  if (outfile == (FILE *) NULL) {
30346  printf("File I/O Error: Cannot create file %s.\n", outfilename);
30347  terminatetetgen(this, 3);
30348  }
30349  // Number of Voronoi cells.
30350  fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
30351  } else {
30352  out->numberofvcells = points->items - unuverts - dupverts;
30353  out->vcelllist = new int*[out->numberofvcells];
30354  if (out->vcelllist == (int **) NULL) {
30355  terminatetetgen(this, 1);
30356  }
30357  }
30358 
30359  // Output Voronoi cells.
30360  tetlist = cavetetlist;
30361  ptlist = cavetetvertlist;
30362  points->traversalinit();
30363  ploop = pointtraverse();
30364  vpointcount = 0;
30365  while (ploop != (point) NULL) {
30366  if ((pointtype(ploop) != UNUSEDVERTEX) &&
30367  (pointtype(ploop) != DUPLICATEDVERTEX) &&
30368  (pointtype(ploop) != NREGULARVERTEX)) {
30369  getvertexstar(1, ploop, tetlist, ptlist, NULL);
30370  // Mark all vertices. Check if it is a hull vertex.
30371  ishullvert = 0;
30372  for (i = 0; i < ptlist->objects; i++) {
30373  neipt = * (point *) fastlookup(ptlist, i);
30374  if (neipt != dummypoint) {
30375  pinfect(neipt);
30376  } else {
30377  ishullvert = 1;
30378  }
30379  }
30380  tcount = (int) ptlist->objects;
30381  if (out == (tetgenio *) NULL) {
30382  fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
30383  } else {
30384  arraysize = tcount;
30385  vertarray = new int[arraysize + 1];
30386  out->vcelllist[vpointcount] = vertarray;
30387  vertarray[0] = tcount;
30388  index = 1;
30389  }
30390  // List Voronoi facets bounding this cell.
30391  for (i = 0; i < tetlist->objects; i++) {
30392  worktet = * (triface *) fastlookup(tetlist, i);
30393  // Let 'worktet' be [a,b,c,d] where d = ploop.
30394  for (j = 0; j < 3; j++) {
30395  neipt = org(worktet); // neipt is a, or b, or c
30396  // Skip the dummypoint.
30397  if (neipt != dummypoint) {
30398  if (pinfected(neipt)) {
30399  // It's not processed yet.
30400  puninfect(neipt);
30401  // Go to the DT edge [a,d], or [b,d], or [c,d].
30402  esym(worktet, spintet);
30403  enextself(spintet);
30404  // Get the V-face dual to this edge.
30405  eidxs = (int *) spintet.tet[11];
30406  vfacecount = eidxs[4 + ver2edge[spintet.ver]];
30407  if (out == (tetgenio *) NULL) {
30408  fprintf(outfile, " %d", vfacecount + shift);
30409  } else {
30410  vertarray[index++] = vfacecount + shift;
30411  }
30412  }
30413  }
30414  enextself(worktet);
30415  } // j
30416  } // i
30417  if (ishullvert) {
30418  // Add a hull facet (-1) to the facet list.
30419  if (out == (tetgenio *) NULL) {
30420  fprintf(outfile, " -1");
30421  } else {
30422  vertarray[index++] = -1;
30423  }
30424  }
30425  if (out == (tetgenio *) NULL) {
30426  fprintf(outfile, "\n");
30427  }
30428  tetlist->restart();
30429  ptlist->restart();
30430  vpointcount++;
30431  }
30432  ploop = pointtraverse();
30433  }
30434 
30435  // Delete the space for face/edge indices.
30436  delete [] indexarray;
30437 
30438  if (out == (tetgenio *) NULL) {
30439  fprintf(outfile, "# Generated by %s\n", b->commandline);
30440  fclose(outfile);
30441  }
30442 }
30443 
30445 // //
30446 // outsmesh() Write surface mesh to a .smesh file, which can be read and //
30447 // tetrahedralized by TetGen. //
30448 // //
30449 // You can specify a filename (without suffix) in 'smfilename'. If you don't //
30450 // supply a filename (let smfilename be NULL), the default name stored in //
30451 // 'tetgenbehavior' will be used. //
30452 // //
30454 
30455 void tetgenmesh::outsmesh(char* smfilename)
30456 {
30457  FILE *outfile;
30458  char nodfilename[FILENAMESIZE];
30459  char smefilename[FILENAMESIZE];
30460  face faceloop;
30461  point p1, p2, p3;
30462  int firstindex, shift;
30463  int bmark;
30464  int faceid, marker;
30465  int i;
30466 
30467  if (smfilename != (char *) NULL && smfilename[0] != '\0') {
30468  strcpy(smefilename, smfilename);
30469  } else if (b->outfilename[0] != '\0') {
30470  strcpy(smefilename, b->outfilename);
30471  } else {
30472  strcpy(smefilename, "unnamed");
30473  }
30474  strcpy(nodfilename, smefilename);
30475  strcat(smefilename, ".smesh");
30476  strcat(nodfilename, ".node");
30477 
30478  if (!b->quiet) {
30479  printf("Writing %s.\n", smefilename);
30480  }
30481  outfile = fopen(smefilename, "w");
30482  if (outfile == (FILE *) NULL) {
30483  printf("File I/O Error: Cannot create file %s.\n", smefilename);
30484  return;
30485  }
30486 
30487  // Determine the first index (0 or 1).
30488  firstindex = b->zeroindex ? 0 : in->firstnumber;
30489  shift = 0; // Default no shiftment.
30490  if ((in->firstnumber == 1) && (firstindex == 0)) {
30491  shift = 1; // Shift the output indices by 1.
30492  }
30493 
30494  fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
30495  fprintf(outfile, "\n# part 1: node list.\n");
30496  fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
30497 
30498  marker = 0; // avoid compile warning.
30499  bmark = !b->nobound && in->facetmarkerlist;
30500 
30501  fprintf(outfile, "\n# part 2: facet list.\n");
30502  // Number of facets, boundary marker.
30503  fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
30504 
30506  faceloop.sh = shellfacetraverse(subfaces);
30507  while (faceloop.sh != (shellface *) NULL) {
30508  p1 = sorg(faceloop);
30509  p2 = sdest(faceloop);
30510  p3 = sapex(faceloop);
30511  if (bmark) {
30512  faceid = shellmark(faceloop) - 1;
30513  if (faceid >= 0) {
30514  marker = in->facetmarkerlist[faceid];
30515  } else {
30516  marker = 0; // This subface must be added manually later.
30517  }
30518  }
30519  fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
30520  pointmark(p2) - shift, pointmark(p3) - shift);
30521  if (bmark) {
30522  fprintf(outfile, " %d", marker);
30523  }
30524  fprintf(outfile, "\n");
30525  faceloop.sh = shellfacetraverse(subfaces);
30526  }
30527 
30528  // Copy input holelist.
30529  fprintf(outfile, "\n# part 3: hole list.\n");
30530  fprintf(outfile, "%d\n", in->numberofholes);
30531  for (i = 0; i < in->numberofholes; i++) {
30532  fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
30533  in->holelist[i * 3], in->holelist[i * 3 + 1],
30534  in->holelist[i * 3 + 2]);
30535  }
30536 
30537  // Copy input regionlist.
30538  fprintf(outfile, "\n# part 4: region list.\n");
30539  fprintf(outfile, "%d\n", in->numberofregions);
30540  for (i = 0; i < in->numberofregions; i++) {
30541  fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
30542  in->regionlist[i * 5], in->regionlist[i * 5 + 1],
30543  in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
30544  in->regionlist[i * 5 + 4]);
30545  }
30546 
30547  fprintf(outfile, "# Generated by %s\n", b->commandline);
30548  fclose(outfile);
30549 }
30550 
30552 // //
30553 // outmesh2medit() Write mesh to a .mesh file, which can be read and //
30554 // rendered by Medit (a free mesh viewer from INRIA). //
30555 // //
30556 // You can specify a filename (without suffix) in 'mfilename'. If you don't //
30557 // supply a filename (let mfilename be NULL), the default name stored in //
30558 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
30559 // //
30561 
30562 void tetgenmesh::outmesh2medit(char* mfilename)
30563 {
30564  FILE *outfile;
30565  char mefilename[FILENAMESIZE];
30566  tetrahedron* tetptr;
30567  triface tface, tsymface;
30568  face segloop, checkmark;
30569  point ptloop, p1, p2, p3, p4;
30570  long ntets, faces;
30571  int pointnumber;
30572  int faceid, marker;
30573  int i;
30574 
30575  if (mfilename != (char *) NULL && mfilename[0] != '\0') {
30576  strcpy(mefilename, mfilename);
30577  } else if (b->outfilename[0] != '\0') {
30578  strcpy(mefilename, b->outfilename);
30579  } else {
30580  strcpy(mefilename, "unnamed");
30581  }
30582  strcat(mefilename, ".mesh");
30583 
30584  if (!b->quiet) {
30585  printf("Writing %s.\n", mefilename);
30586  }
30587  outfile = fopen(mefilename, "w");
30588  if (outfile == (FILE *) NULL) {
30589  printf("File I/O Error: Cannot create file %s.\n", mefilename);
30590  return;
30591  }
30592 
30593  fprintf(outfile, "MeshVersionFormatted 1\n");
30594  fprintf(outfile, "\n");
30595  fprintf(outfile, "Dimension\n");
30596  fprintf(outfile, "3\n");
30597  fprintf(outfile, "\n");
30598 
30599  fprintf(outfile, "\n# Set of mesh vertices\n");
30600  fprintf(outfile, "Vertices\n");
30601  fprintf(outfile, "%ld\n", points->items);
30602 
30603  points->traversalinit();
30604  ptloop = pointtraverse();
30605  pointnumber = 1; // Medit need start number form 1.
30606  while (ptloop != (point) NULL) {
30607  // Point coordinates.
30608  fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
30609  if (in->numberofpointattributes > 0) {
30610  // Write an attribute, ignore others if more than one.
30611  fprintf(outfile, " %.17g\n", ptloop[3]);
30612  } else {
30613  fprintf(outfile, " 0\n");
30614  }
30615  setpointmark(ptloop, pointnumber);
30616  ptloop = pointtraverse();
30617  pointnumber++;
30618  }
30619 
30620  // Compute the number of faces.
30621  ntets = tetrahedrons->items - hullsize;
30622  faces = (ntets * 4l + hullsize) / 2l;
30623 
30624  fprintf(outfile, "\n# Set of Triangles\n");
30625  fprintf(outfile, "Triangles\n");
30626  fprintf(outfile, "%ld\n", faces);
30627 
30629  tface.tet = tetrahedrontraverse();
30630  while (tface.tet != (tetrahedron *) NULL) {
30631  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
30632  fsym(tface, tsymface);
30633  if (ishulltet(tsymface) ||
30634  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
30635  p1 = org (tface);
30636  p2 = dest(tface);
30637  p3 = apex(tface);
30638  fprintf(outfile, "%5d %5d %5d",
30639  pointmark(p1), pointmark(p2), pointmark(p3));
30640  // Check if it is a subface.
30641  tspivot(tface, checkmark);
30642  if (checkmark.sh == NULL) {
30643  marker = 0; // It is an inner face. It's marker is 0.
30644  } else {
30645  if (in->facetmarkerlist) {
30646  // The facet marker is given, get it.
30647  faceid = shellmark(checkmark) - 1;
30648  marker = in->facetmarkerlist[faceid];
30649  } else {
30650  marker = 1; // The default marker for subface is 1.
30651  }
30652  }
30653  fprintf(outfile, " %d\n", marker);
30654  }
30655  }
30656  tface.tet = tetrahedrontraverse();
30657  }
30658 
30659  fprintf(outfile, "\n# Set of Tetrahedra\n");
30660  fprintf(outfile, "Tetrahedra\n");
30661  fprintf(outfile, "%ld\n", ntets);
30662 
30664  tetptr = tetrahedrontraverse();
30665  while (tetptr != (tetrahedron *) NULL) {
30666  if (!b->reversetetori) {
30667  p1 = (point) tetptr[4];
30668  p2 = (point) tetptr[5];
30669  } else {
30670  p1 = (point) tetptr[5];
30671  p2 = (point) tetptr[4];
30672  }
30673  p3 = (point) tetptr[6];
30674  p4 = (point) tetptr[7];
30675  fprintf(outfile, "%5d %5d %5d %5d",
30676  pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
30677  if (numelemattrib > 0) {
30678  fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
30679  } else {
30680  fprintf(outfile, " 0");
30681  }
30682  fprintf(outfile, "\n");
30683  tetptr = tetrahedrontraverse();
30684  }
30685 
30686  fprintf(outfile, "\nCorners\n");
30687  fprintf(outfile, "%d\n", in->numberofpoints);
30688 
30689  for (i = 0; i < in->numberofpoints; i++) {
30690  fprintf(outfile, "%4d\n", i + 1);
30691  }
30692 
30693  if (b->plc || b->refine) {
30694  fprintf(outfile, "\nEdges\n");
30695  fprintf(outfile, "%ld\n", subsegs->items);
30696 
30698  segloop.sh = shellfacetraverse(subsegs);
30699  while (segloop.sh != (shellface *) NULL) {
30700  p1 = sorg(segloop);
30701  p2 = sdest(segloop);
30702  fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
30703  marker = shellmark(segloop);
30704  fprintf(outfile, " %d\n", marker);
30705  segloop.sh = shellfacetraverse(subsegs);
30706  }
30707  }
30708 
30709  fprintf(outfile, "\nEnd\n");
30710  fclose(outfile);
30711 }
30712 
30713 
30714 
30716 // //
30717 // outmesh2vtk() Save mesh to file in VTK Legacy format. //
30718 // //
30719 // This function was contributed by Bryn Llyod from ETH, 2007. //
30720 // //
30722 
30723 void tetgenmesh::outmesh2vtk(char* ofilename)
30724 {
30725  FILE *outfile;
30726  char vtkfilename[FILENAMESIZE];
30727  point pointloop, p1, p2, p3, p4;
30728  tetrahedron* tptr;
30729  double x, y, z;
30730  int n1, n2, n3, n4;
30731  int nnodes = 4;
30732  int celltype = 10;
30733 
30734  if (b->order == 2) {
30735  printf(" Write VTK not implemented for order 2 elements \n");
30736  return;
30737  }
30738 
30739  int NEL = tetrahedrons->items - hullsize;
30740  int NN = points->items;
30741 
30742  if (ofilename != (char *) NULL && ofilename[0] != '\0') {
30743  strcpy(vtkfilename, ofilename);
30744  } else if (b->outfilename[0] != '\0') {
30745  strcpy(vtkfilename, b->outfilename);
30746  } else {
30747  strcpy(vtkfilename, "unnamed");
30748  }
30749  strcat(vtkfilename, ".vtk");
30750 
30751  if (!b->quiet) {
30752  printf("Writing %s.\n", vtkfilename);
30753  }
30754  outfile = fopen(vtkfilename, "w");
30755  if (outfile == (FILE *) NULL) {
30756  printf("File I/O Error: Cannot create file %s.\n", vtkfilename);
30757  return;
30758  }
30759 
30760  //always write big endian
30761  //bool ImALittleEndian = !testIsBigEndian();
30762 
30763  fprintf(outfile, "# vtk DataFile Version 2.0\n");
30764  fprintf(outfile, "Unstructured Grid\n");
30765  fprintf(outfile, "ASCII\n"); // BINARY
30766  fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
30767  fprintf(outfile, "POINTS %d double\n", NN);
30768 
30769  points->traversalinit();
30770  pointloop = pointtraverse();
30771  for(int id=0; id<NN && pointloop != (point) NULL; id++){
30772  x = pointloop[0];
30773  y = pointloop[1];
30774  z = pointloop[2];
30775  fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
30776  pointloop = pointtraverse();
30777  }
30778  fprintf(outfile, "\n");
30779 
30780  fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
30781  //NEL rows, each has 1 type id + 4 node id's
30782 
30784  tptr = tetrahedrontraverse();
30785  //elementnumber = firstindex; // in->firstnumber;
30786  while (tptr != (tetrahedron *) NULL) {
30787  if (!b->reversetetori) {
30788  p1 = (point) tptr[4];
30789  p2 = (point) tptr[5];
30790  } else {
30791  p1 = (point) tptr[5];
30792  p2 = (point) tptr[4];
30793  }
30794  p3 = (point) tptr[6];
30795  p4 = (point) tptr[7];
30796  n1 = pointmark(p1) - in->firstnumber;
30797  n2 = pointmark(p2) - in->firstnumber;
30798  n3 = pointmark(p3) - in->firstnumber;
30799  n4 = pointmark(p4) - in->firstnumber;
30800  fprintf(outfile, "%d %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
30801  tptr = tetrahedrontraverse();
30802  }
30803  fprintf(outfile, "\n");
30804 
30805  fprintf(outfile, "CELL_TYPES %d\n", NEL);
30806  for(int tid=0; tid<NEL; tid++){
30807  fprintf(outfile, "%d\n", celltype);
30808  }
30809  fprintf(outfile, "\n");
30810 
30811  if (numelemattrib > 0) {
30812  // Output tetrahedra region attributes.
30813  fprintf(outfile, "CELL_DATA %d\n", NEL);
30814  fprintf(outfile, "SCALARS cell_scalars int 1\n");
30815  fprintf(outfile, "LOOKUP_TABLE default\n");
30817  tptr = tetrahedrontraverse();
30818  while (tptr != (tetrahedron *) NULL) {
30819  fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
30820  tptr = tetrahedrontraverse();
30821  }
30822  fprintf(outfile, "\n");
30823  }
30824 
30825  fclose(outfile);
30826 }
30827 
30831 
30835 
30837 // //
30838 // tetrahedralize() The interface for users using TetGen library to //
30839 // generate tetrahedral meshes with all features. //
30840 // //
30841 // The sequence is roughly as follows. Many of these steps can be skipped, //
30842 // depending on the command line switches. //
30843 // //
30844 // - Initialize constants and parse the command line. //
30845 // - Read the vertices from a file and either //
30846 // - tetrahedralize them (no -r), or //
30847 // - read an old mesh from files and reconstruct it (-r). //
30848 // - Insert the boundary segments and facets (-p or -Y). //
30849 // - Read the holes (-p), regional attributes (-pA), and regional volume //
30850 // constraints (-pa). Carve the holes and concavities, and spread the //
30851 // regional attributes and volume constraints. //
30852 // - Enforce the constraints on minimum quality bound (-q) and maximum //
30853 // volume (-a), and a mesh size function (-m). //
30854 // - Optimize the mesh wrt. specified quality measures (-O and -o). //
30855 // - Write the output files and print the statistics. //
30856 // - Check the consistency of the mesh (-C). //
30857 // //
30859 
30861  tetgenio *addin, tetgenio *bgmin)
30862 {
30863  tetgenmesh m;
30864  clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
30865  REAL cps = (REAL) CLOCKS_PER_SEC;
30866 
30867  tv[0] = clock();
30868 
30869  m.b = b;
30870  m.in = in;
30871  m.addin = addin;
30872 
30873  if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
30874  m.bgm = new tetgenmesh(); // Create an empty background mesh.
30875  m.bgm->b = b;
30876  m.bgm->in = bgmin;
30877  }
30878 
30879  m.initializepools();
30880  m.transfernodes();
30881 
30883  m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
30884 
30885  tv[1] = clock();
30886 
30887  if (b->refine) { // -r
30888  m.reconstructmesh();
30889  } else { // -p
30890  m.incrementaldelaunay(ts[0]);
30891  }
30892 
30893  tv[2] = clock();
30894 
30895  if (!b->quiet) {
30896  if (b->refine) {
30897  printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30898  } else {
30899  printf("Delaunay seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30900  if (b->verbose) {
30901  printf(" Point sorting seconds: %g\n", ((REAL)(ts[0]-tv[1])) / cps);
30902  }
30903  }
30904  }
30905 
30906  if (b->plc && !b->refine) { // -p
30907  m.meshsurface();
30908 
30909  ts[0] = clock();
30910 
30911  if (!b->quiet) {
30912  printf("Surface mesh seconds: %g\n", ((REAL)(ts[0]-tv[2])) / cps);
30913  }
30914 
30915  if (b->diagnose) { // -d
30916  m.detectinterfaces();
30917 
30918  ts[1] = clock();
30919 
30920  if (!b->quiet) {
30921  printf("Self-intersection seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30922  }
30923 
30924  // Only output when self-intersecting faces exist.
30925  if (m.subfaces->items > 0l) {
30926  m.outnodes(out);
30927  m.outsubfaces(out);
30928  }
30929 
30930  return;
30931  }
30932  }
30933 
30934  tv[3] = clock();
30935 
30936  if ((b->metric) && (m.bgm != NULL)) { // -m
30937  m.bgm->initializepools();
30938  m.bgm->transfernodes();
30939  m.bgm->reconstructmesh();
30940 
30941  ts[0] = clock();
30942 
30943  if (!b->quiet) {
30944  printf("Background mesh reconstruct seconds: %g\n",
30945  ((REAL)(ts[0] - tv[3])) / cps);
30946  }
30947 
30948  if (b->metric) { // -m
30949  m.interpolatemeshsize();
30950 
30951  ts[1] = clock();
30952 
30953  if (!b->quiet) {
30954  printf("Size interpolating seconds: %g\n",((REAL)(ts[1]-ts[0])) / cps);
30955  }
30956  }
30957  }
30958 
30959  tv[4] = clock();
30960 
30961  if (b->plc && !b->refine) { // -p
30962  if (b->nobisect) { // -Y
30963  m.recoverboundary(ts[0]);
30964  } else {
30965  m.constraineddelaunay(ts[0]);
30966  }
30967 
30968  ts[1] = clock();
30969 
30970  if (!b->quiet) {
30971  if (b->nobisect) {
30972  printf("Boundary recovery ");
30973  } else {
30974  printf("Constrained Delaunay ");
30975  }
30976  printf("seconds: %g\n", ((REAL)(ts[1] - tv[4])) / cps);
30977  if (b->verbose) {
30978  printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps);
30979  printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30980  }
30981  }
30982 
30983  m.carveholes();
30984 
30985  ts[2] = clock();
30986 
30987  if (!b->quiet) {
30988  printf("Exterior tets removal seconds: %g\n",((REAL)(ts[2]-ts[1]))/cps);
30989  }
30990 
30991  if (b->nobisect) { // -Y
30992  if (m.subvertstack->objects > 0l) {
30994 
30995  ts[3] = clock();
30996 
30997  if (!b->quiet) {
30998  printf("Steiner suppression seconds: %g\n",
30999  ((REAL)(ts[3]-ts[2]))/cps);
31000  }
31001  }
31002  }
31003  }
31004 
31005  tv[5] = clock();
31006 
31007  if (b->coarsen) { // -R
31008  m.meshcoarsening();
31009  }
31010 
31011  tv[6] = clock();
31012 
31013  if (!b->quiet) {
31014  if (b->coarsen) {
31015  printf("Mesh coarsening seconds: %g\n", ((REAL)(tv[6] - tv[5])) / cps);
31016  }
31017  }
31018 
31019  if ((b->plc && b->nobisect) || b->coarsen) {
31020  m.recoverdelaunay();
31021  }
31022 
31023  tv[7] = clock();
31024 
31025  if (!b->quiet) {
31026  if ((b->plc && b->nobisect) || b->coarsen) {
31027  printf("Delaunay recovery seconds: %g\n", ((REAL)(tv[7] - tv[6]))/cps);
31028  }
31029  }
31030 
31031  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
31032  if ((addin != NULL) && (addin->numberofpoints > 0)) {
31033  m.insertconstrainedpoints(addin);
31034  }
31035  }
31036 
31037  tv[8] = clock();
31038 
31039  if (!b->quiet) {
31040  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
31041  if ((addin != NULL) && (addin->numberofpoints > 0)) {
31042  printf("Constrained points seconds: %g\n", ((REAL)(tv[8]-tv[7]))/cps);
31043  }
31044  }
31045  }
31046 
31047  if (b->quality) {
31048  m.delaunayrefinement();
31049  }
31050 
31051  tv[9] = clock();
31052 
31053  if (!b->quiet) {
31054  if (b->quality) {
31055  printf("Refinement seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps);
31056  }
31057  }
31058 
31059  if ((b->plc || b->refine) && (b->optlevel > 0)) {
31060  m.optimizemesh();
31061  }
31062 
31063  tv[10] = clock();
31064 
31065  if (!b->quiet) {
31066  if ((b->plc || b->refine) && (b->optlevel > 0)) {
31067  printf("Optimization seconds: %g\n", ((REAL)(tv[10] - tv[9])) / cps);
31068  }
31069  }
31070 
31071  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
31072  || (b->refine && (in->numberofcorners == 10)))) {
31073  m.jettisonnodes();
31074  }
31075 
31076  if ((b->order == 2) && !b->convex) {
31077  m.highorder();
31078  }
31079 
31080  if (!b->quiet) {
31081  printf("\n");
31082  }
31083 
31084  if (out != (tetgenio *) NULL) {
31085  out->firstnumber = in->firstnumber;
31086  out->mesh_dim = in->mesh_dim;
31087  }
31088 
31089  if (b->nonodewritten || b->noiterationnum) {
31090  if (!b->quiet) {
31091  printf("NOT writing a .node file.\n");
31092  }
31093  } else {
31094  m.outnodes(out);
31095  }
31096 
31097  if (b->noelewritten) {
31098  if (!b->quiet) {
31099  printf("NOT writing an .ele file.\n");
31100  }
31101  } else {
31102  if (m.tetrahedrons->items > 0l) {
31103  m.outelements(out);
31104  }
31105  }
31106 
31107  if (b->nofacewritten) {
31108  if (!b->quiet) {
31109  printf("NOT writing an .face file.\n");
31110  }
31111  } else {
31112  if (b->facesout) {
31113  if (m.tetrahedrons->items > 0l) {
31114  m.outfaces(out); // Output all faces.
31115  }
31116  } else {
31117  if (b->plc || b->refine) {
31118  if (m.subfaces->items > 0l) {
31119  m.outsubfaces(out); // Output boundary faces.
31120  }
31121  } else {
31122  if (m.tetrahedrons->items > 0l) {
31123  m.outhullfaces(out); // Output convex hull faces.
31124  }
31125  }
31126  }
31127  }
31128 
31129 
31130  if (b->nofacewritten) {
31131  if (!b->quiet) {
31132  printf("NOT writing an .edge file.\n");
31133  }
31134  } else {
31135  if (b->edgesout) { // -e
31136  m.outedges(out); // output all mesh edges.
31137  } else {
31138  if (b->plc || b->refine) {
31139  m.outsubsegments(out); // output subsegments.
31140  }
31141  }
31142  }
31143 
31144  if ((b->plc || b->refine) && b->metric) { // -m
31145  m.outmetrics(out);
31146  }
31147 
31148  if (!out && b->plc &&
31149  ((b->object == tetgenbehavior::OFF) ||
31150  (b->object == tetgenbehavior::PLY) ||
31151  (b->object == tetgenbehavior::STL))) {
31152  m.outsmesh(b->outfilename);
31153  }
31154 
31155  if (!out && b->meditview) {
31156  m.outmesh2medit(b->outfilename);
31157  }
31158 
31159 
31160  if (!out && b->vtkview) {
31161  m.outmesh2vtk(b->outfilename);
31162  }
31163 
31164  if (b->neighout) {
31165  m.outneighbors(out);
31166  }
31167 
31168  if ((!(b->plc || b->refine)) && b->voroout) {
31169  m.outvoronoi(out);
31170  }
31171 
31172 
31173  tv[11] = clock();
31174 
31175  if (!b->quiet) {
31176  printf("\nOutput seconds: %g\n", ((REAL)(tv[11] - tv[10])) / cps);
31177  printf("Total running seconds: %g\n", ((REAL)(tv[11] - tv[0])) / cps);
31178  }
31179 
31180  if (b->docheck) {
31181  m.checkmesh(0);
31182  if (b->plc || b->refine) {
31183  m.checkshells();
31184  m.checksegments();
31185  }
31186  if (b->docheck > 1) {
31187  m.checkdelaunay();
31188  }
31189  }
31190 
31191  if (!b->quiet) {
31192  m.statistics();
31193  }
31194 }
31195 
31196 #ifndef TETLIBRARY
31197 
31199 // //
31200 // main() The command line interface of TetGen. //
31201 // //
31203 
31204 int main(int argc, char *argv[])
31205 
31206 #else // with TETLIBRARY
31207 
31209 // //
31210 // tetrahedralize() The library interface of TetGen. //
31211 // //
31213 
31214 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
31215  tetgenio *addin, tetgenio *bgmin)
31216 
31217 #endif // not TETLIBRARY
31218 
31219 {
31220  tetgenbehavior b;
31221 
31222 #ifndef TETLIBRARY
31223 
31224  tetgenio in, addin, bgmin;
31225 
31226  if (!b.parse_commandline(argc, argv)) {
31227  terminatetetgen(NULL, 10);
31228  }
31229 
31230  // Read input files.
31231  if (b.refine) { // -r
31232  if (!in.load_tetmesh(b.infilename, (int) b.object)) {
31233  terminatetetgen(NULL, 10);
31234  }
31235  } else { // -p
31236  if (!in.load_plc(b.infilename, (int) b.object)) {
31237  terminatetetgen(NULL, 10);
31238  }
31239  }
31240  if (b.insertaddpoints) { // -i
31241  // Try to read a .a.node file.
31242  addin.load_node(b.addinfilename);
31243  }
31244  if (b.metric) { // -m
31245  // Try to read a background mesh in files .b.node, .b.ele.
31246  bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
31247  }
31248 
31249  tetrahedralize(&b, &in, NULL, &addin, &bgmin);
31250 
31251  return 0;
31252 
31253 #else // with TETLIBRARY
31254 
31255  if (!b.parse_commandline(switches)) {
31256  terminatetetgen(NULL, 10);
31257  }
31258  tetrahedralize(&b, in, out, addin, bgmin);
31259 
31260 #endif // not TETLIBRARY
31261 }
31262 
31266