1 ///////////////////////////////////////////////////////////////////////////////
2 //                                                                           //
3 // TetGen                                                                    //
4 //                                                                           //
5 // A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator       //
6 //                                                                           //
7 // Version 1.5                                                               //
8 // (June 21, 2013)                                                           //
9 //                                                                           //
10 // Copyright (C) 2002--2013                                                  //
11 // Hang Si                                                                   //
12 // Research Group: Numerical Mathematics and Scientific Computing            //
13 // Weierstrass Institute for Applied Analysis and Stochastics (WIAS)         //
14 // Mohrenstr. 39, 10117 Berlin, Germany                                      //
15 // si@wias-berlin.de                                                         //
16 //                                                                           //
17 // TetGen is freely available through the website: http://www.tetgen.org.    //
18 //   It may be copied, modified, and redistributed for non-commercial use.   //
19 //   Please consult the file LICENSE for the detailed copyright notices.     //
20 //                                                                           //
21 ///////////////////////////////////////////////////////////////////////////////
22 
23 #include "tetgen.h"
24 
25 // [Laurent Alonso, Bruno] replaced all instance of NULL by nullptr
26 
27 // [Bruno] redirected output into Geogram terminal
28 #include <geogram/basic/logger.h>
29 #define printf geogram_printf
30 
31 // [Bruno] using PCK predicates
32 #define USE_PCK
33 
34 // [Bruno] disable some warnings for ICC
35 #ifdef __ICC
36 #pragma warning disable 869 593
37 #endif
38 
39 namespace GEO_3rdParty { // [Bruno]
40 
41 //// io_cxx ///////////////////////////////////////////////////////////////////
42 ////                                                                       ////
43 ////                                                                       ////
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 //                                                                           //
47 // load_node_call()    Read a list of points from a file.                    //
48 //                                                                           //
49 // 'infile' is the file handle contains the node list.  It may point to a    //
50 // .node, or .poly or .smesh file. 'markers' indicates each node contains an //
51 // additional marker (integer) or not. 'uvflag' indicates each node contains //
52 // u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
53 // of the file being read,  it is only used in error messages.               //
54 //                                                                           //
55 // The 'firstnumber' (0 or 1) is automatically determined by the number of   //
56 // the first index of the first point.                                       //
57 //                                                                           //
58 ///////////////////////////////////////////////////////////////////////////////
59 
load_node_call(FILE * infile,int markers,int uvflag,char * infilename)60 bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
61                               char* infilename)
62 {
63   char inputline[INPUTLINESIZE];
64   char *stringptr;
65   REAL x, y, z, attrib;
66   int firstnode, currentmarker;
67   int index, attribindex;
68   int i, j;
69 
70   // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
71   pointlist = new REAL[numberofpoints * 3];
72   if (pointlist == (REAL *) nullptr) {
73     terminatetetgen(1);
74   }
75   if (numberofpointattributes > 0) {
76     pointattributelist = new REAL[numberofpoints * numberofpointattributes];
77     if (pointattributelist == (REAL *) nullptr) {
78       terminatetetgen(1);
79     }
80   }
81   if (markers) {
82     pointmarkerlist = new int[numberofpoints];
83     if (pointmarkerlist == (int *) nullptr) {
84       terminatetetgen(1);
85     }
86   }
87   if (uvflag) {
88     pointparamlist = new pointparam[numberofpoints];
89     if (pointparamlist == nullptr) {
90       terminatetetgen(1);
91     }
92   }
93 
94   // Read the point section.
95   index = 0;
96   attribindex = 0;
97   for (i = 0; i < numberofpoints; i++) {
98     stringptr = readnumberline(inputline, infile, infilename);
99     if (useindex) {
100       if (i == 0) {
101         firstnode = (int) strtol (stringptr, &stringptr, 0);
102         if ((firstnode == 0) || (firstnode == 1)) {
103           firstnumber = firstnode;
104         }
105       }
106       stringptr = findnextnumber(stringptr);
107     } // if (useindex)
108     if (*stringptr == '\0') {
109       printf("Error:  Point %d has no x coordinate.\n", firstnumber + i);
110       break;
111     }
112     x = (REAL) strtod(stringptr, &stringptr);
113     stringptr = findnextnumber(stringptr);
114     if (*stringptr == '\0') {
115       printf("Error:  Point %d has no y coordinate.\n", firstnumber + i);
116       break;
117     }
118     y = (REAL) strtod(stringptr, &stringptr);
119     if (mesh_dim == 3) {
120       stringptr = findnextnumber(stringptr);
121       if (*stringptr == '\0') {
122         printf("Error:  Point %d has no z coordinate.\n", firstnumber + i);
123         break;
124       }
125       z = (REAL) strtod(stringptr, &stringptr);
126     } else {
127       z = 0.0; // mesh_dim == 2;
128     }
129     pointlist[index++] = x;
130     pointlist[index++] = y;
131     pointlist[index++] = z;
132     // Read the point attributes.
133     for (j = 0; j < numberofpointattributes; j++) {
134       stringptr = findnextnumber(stringptr);
135       if (*stringptr == '\0') {
136         attrib = 0.0;
137       } else {
138         attrib = (REAL) strtod(stringptr, &stringptr);
139       }
140       pointattributelist[attribindex++] = attrib;
141     }
142     if (markers) {
143       // Read a point marker.
144       stringptr = findnextnumber(stringptr);
145       if (*stringptr == '\0') {
146         currentmarker = 0;
147       } else {
148         currentmarker = (int) strtol (stringptr, &stringptr, 0);
149       }
150       pointmarkerlist[i] = currentmarker;
151     }
152     if (uvflag) {
153       // Read point paramteters.
154       stringptr = findnextnumber(stringptr);
155       if (*stringptr == '\0') {
156         printf("Error:  Point %d has no uv[0].\n", firstnumber + i);
157         break;
158       }
159       pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
160       stringptr = findnextnumber(stringptr);
161       if (*stringptr == '\0') {
162         printf("Error:  Point %d has no uv[1].\n", firstnumber + i);
163         break;
164       }
165       pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
166       stringptr = findnextnumber(stringptr);
167       if (*stringptr == '\0') {
168         printf("Error:  Point %d has no tag.\n", firstnumber + i);
169         break;
170       }
171       pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
172       stringptr = findnextnumber(stringptr);
173       if (*stringptr == '\0') {
174         printf("Error:  Point %d has no type.\n", firstnumber + i);
175         break;
176       }
177       pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
178       if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
179         printf("Error:  Point %d has an invalid type.\n", firstnumber + i);
180         break;
181       }
182     }
183   }
184   if (i < numberofpoints) {
185     // Failed to read points due to some error.
186     delete [] pointlist;
187     pointlist = (REAL *) nullptr;
188     if (markers) {
189       delete [] pointmarkerlist;
190       pointmarkerlist = (int *) nullptr;
191     }
192     if (numberofpointattributes > 0) {
193       delete [] pointattributelist;
194       pointattributelist = (REAL *) nullptr;
195     }
196     if (uvflag) {
197       delete [] pointparamlist;
198       pointparamlist = nullptr;
199     }
200     numberofpoints = 0;
201     return false;
202   }
203   return true;
204 }
205 
206 ///////////////////////////////////////////////////////////////////////////////
207 //                                                                           //
208 // load_node()    Load a list of points from a .node file.                   //
209 //                                                                           //
210 ///////////////////////////////////////////////////////////////////////////////
211 
load_node(char * filebasename)212 bool tetgenio::load_node(char* filebasename)
213 {
214   FILE *infile;
215   char innodefilename[FILENAMESIZE];
216   char inputline[INPUTLINESIZE];
217   char *stringptr;
218   bool okflag;
219   int markers;
220   int uvflag; // for psc input.
221 
222   // Assembling the actual file names we want to open.
223   strcpy(innodefilename, filebasename);
224   strcat(innodefilename, ".node");
225 
226   // Try to open a .node file.
227   infile = fopen(innodefilename, "r");
228   if (infile == (FILE *) nullptr) {
229     printf("  Cannot access file %s.\n", innodefilename);
230     return false;
231   }
232   printf("Opening %s.\n", innodefilename);
233 
234   // Set initial flags.
235   mesh_dim = 3;
236   numberofpointattributes = 0;  // no point attribute.
237   markers = 0;  // no boundary marker.
238   uvflag = 0; // no uv parameters (reuqired by a PSC).
239 
240   // Read the first line of the file.
241   stringptr = readnumberline(inputline, infile, innodefilename);
242   // Does this file contain an index colume?
243   stringptr = strstr(inputline, "rbox");
244   if (stringptr == nullptr) {
245     // Read number of points, number of dimensions, number of point
246     //   attributes, and number of boundary markers.
247     stringptr = inputline;
248     numberofpoints = (int) strtol (stringptr, &stringptr, 0);
249     stringptr = findnextnumber(stringptr);
250     if (*stringptr != '\0') {
251       mesh_dim = (int) strtol (stringptr, &stringptr, 0);
252     }
253     stringptr = findnextnumber(stringptr);
254     if (*stringptr != '\0') {
255       numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
256     }
257     stringptr = findnextnumber(stringptr);
258     if (*stringptr != '\0') {
259       markers = (int) strtol (stringptr, &stringptr, 0);
260     }
261     stringptr = findnextnumber(stringptr);
262     if (*stringptr != '\0') {
263       uvflag = (int) strtol (stringptr, &stringptr, 0);
264     }
265   } else {
266     // It is a rbox (qhull) input file.
267     stringptr = inputline;
268     // Get the dimension.
269     mesh_dim = (int) strtol (stringptr, &stringptr, 0);
270     // Get the number of points.
271     stringptr = readnumberline(inputline, infile, innodefilename);
272     numberofpoints = (int) strtol (stringptr, &stringptr, 0);
273     // There is no index column.
274     useindex = 0;
275   }
276 
277   // Load the list of nodes.
278   okflag = load_node_call(infile, markers, uvflag, innodefilename);
279 
280   fclose(infile);
281   return okflag;
282 }
283 
284 ///////////////////////////////////////////////////////////////////////////////
285 //                                                                           //
286 // load_edge()    Load a list of edges from a .edge file.                    //
287 //                                                                           //
288 ///////////////////////////////////////////////////////////////////////////////
289 
load_edge(char * filebasename)290 bool tetgenio::load_edge(char* filebasename)
291 {
292   FILE *infile;
293   char inedgefilename[FILENAMESIZE];
294   char inputline[INPUTLINESIZE];
295   char *stringptr;
296   int markers, corner;
297   int index;
298   int i, j;
299 
300   strcpy(inedgefilename, filebasename);
301   strcat(inedgefilename, ".edge");
302 
303   infile = fopen(inedgefilename, "r");
304   if (infile != (FILE *) nullptr) {
305     printf("Opening %s.\n", inedgefilename);
306   } else {
307     //printf("  Cannot access file %s.\n", inedgefilename);
308     return false;
309   }
310 
311   // Read number of boundary edges.
312   stringptr = readnumberline(inputline, infile, inedgefilename);
313   numberofedges = (int) strtol (stringptr, &stringptr, 0);
314   if (numberofedges > 0) {
315     edgelist = new int[numberofedges * 2];
316     if (edgelist == (int *) nullptr) {
317       terminatetetgen(1);
318     }
319     stringptr = findnextnumber(stringptr);
320     if (*stringptr == '\0') {
321       markers = 0;  // Default value.
322     } else {
323       markers = (int) strtol (stringptr, &stringptr, 0);
324     }
325     if (markers > 0) {
326       edgemarkerlist = new int[numberofedges];
327     }
328   }
329 
330   // Read the list of edges.
331   index = 0;
332   for (i = 0; i < numberofedges; i++) {
333     // Read edge index and the edge's two endpoints.
334     stringptr = readnumberline(inputline, infile, inedgefilename);
335     for (j = 0; j < 2; j++) {
336       stringptr = findnextnumber(stringptr);
337       if (*stringptr == '\0') {
338         printf("Error:  Edge %d is missing vertex %d in %s.\n",
339                i + firstnumber, j + 1, inedgefilename);
340         terminatetetgen(1);
341       }
342       corner = (int) strtol(stringptr, &stringptr, 0);
343       if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
344         printf("Error:  Edge %d has an invalid vertex index.\n",
345                i + firstnumber);
346         terminatetetgen(1);
347       }
348       edgelist[index++] = corner;
349     }
350     if (numberofcorners == 10) {
351       // Skip an extra vertex (generated by a previous -o2 option).
352       stringptr = findnextnumber(stringptr);
353     }
354     // Read the edge marker if it has.
355     if (markers) {
356       stringptr = findnextnumber(stringptr);
357       edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
358     }
359   }
360 
361   fclose(infile);
362   return true;
363 }
364 
365 ///////////////////////////////////////////////////////////////////////////////
366 //                                                                           //
367 // load_face()    Load a list of faces (triangles) from a .face file.        //
368 //                                                                           //
369 ///////////////////////////////////////////////////////////////////////////////
370 
load_face(char * filebasename)371 bool tetgenio::load_face(char* filebasename)
372 {
373   FILE *infile;
374   char infilename[FILENAMESIZE];
375   char inputline[INPUTLINESIZE];
376   char *stringptr;
377   REAL attrib;
378   int markers, corner;
379   int index;
380   int i, j;
381 
382   strcpy(infilename, filebasename);
383   strcat(infilename, ".face");
384 
385   infile = fopen(infilename, "r");
386   if (infile != (FILE *) nullptr) {
387     printf("Opening %s.\n", infilename);
388   } else {
389     return false;
390   }
391 
392   // Read number of faces, boundary markers.
393   stringptr = readnumberline(inputline, infile, infilename);
394   numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
395   stringptr = findnextnumber(stringptr);
396   if (mesh_dim == 2) {
397     // Skip a number.
398     stringptr = findnextnumber(stringptr);
399   }
400   if (*stringptr == '\0') {
401     markers = 0;  // Default there is no marker per face.
402   } else {
403     markers = (int) strtol (stringptr, &stringptr, 0);
404   }
405   if (numberoftrifaces > 0) {
406     trifacelist = new int[numberoftrifaces * 3];
407     if (trifacelist == (int *) nullptr) {
408       terminatetetgen(1);
409     }
410     if (markers) {
411       trifacemarkerlist = new int[numberoftrifaces];
412       if (trifacemarkerlist == (int *) nullptr) {
413         terminatetetgen(1);
414       }
415     }
416   }
417 
418   // Read the list of faces.
419   index = 0;
420   for (i = 0; i < numberoftrifaces; i++) {
421     // Read face index and the face's three corners.
422     stringptr = readnumberline(inputline, infile, infilename);
423     for (j = 0; j < 3; j++) {
424       stringptr = findnextnumber(stringptr);
425       if (*stringptr == '\0') {
426         printf("Error:  Face %d is missing vertex %d in %s.\n",
427                i + firstnumber, j + 1, infilename);
428         terminatetetgen(1);
429       }
430       corner = (int) strtol(stringptr, &stringptr, 0);
431       if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
432         printf("Error:  Face %d has an invalid vertex index.\n",
433                i + firstnumber);
434         terminatetetgen(1);
435       }
436       trifacelist[index++] = corner;
437     }
438     if (numberofcorners == 10) {
439       // Skip 3 extra vertices (generated by a previous -o2 option).
440       for (j = 0; j < 3; j++) {
441         stringptr = findnextnumber(stringptr);
442       }
443     }
444     // Read the boundary marker if it exists.
445     if (markers) {
446       stringptr = findnextnumber(stringptr);
447       if (*stringptr == '\0') {
448         attrib = 0.0;
449       } else {
450         attrib = (REAL) strtod(stringptr, &stringptr);
451       }
452       trifacemarkerlist[i] = (int) attrib;
453     }
454   }
455 
456   fclose(infile);
457 
458   return true;
459 }
460 
461 ///////////////////////////////////////////////////////////////////////////////
462 //                                                                           //
463 // load_tet()    Load a list of tetrahedra from a .ele file.                 //
464 //                                                                           //
465 ///////////////////////////////////////////////////////////////////////////////
466 
load_tet(char * filebasename)467 bool tetgenio::load_tet(char* filebasename)
468 {
469   FILE *infile;
470   char infilename[FILENAMESIZE];
471   char inputline[INPUTLINESIZE];
472   char *stringptr;
473   REAL attrib;
474   int corner;
475   int index, attribindex;
476   int i, j;
477 
478   strcpy(infilename, filebasename);
479   strcat(infilename, ".ele");
480 
481   infile = fopen(infilename, "r");
482   if (infile != (FILE *) nullptr) {
483     printf("Opening %s.\n", infilename);
484   } else {
485     return false;
486   }
487 
488   // Read number of elements, number of corners (4 or 10), number of
489   //   element attributes.
490   stringptr = readnumberline(inputline, infile, infilename);
491   numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
492   if (numberoftetrahedra <= 0) {
493     printf("Error:  Invalid number of tetrahedra.\n");
494     fclose(infile);
495     return false;
496   }
497   stringptr = findnextnumber(stringptr);
498   if (*stringptr == '\0') {
499     numberofcorners = 4;  // Default read 4 nodes per element.
500   } else {
501     numberofcorners = (int) strtol(stringptr, &stringptr, 0);
502   }
503   stringptr = findnextnumber(stringptr);
504   if (*stringptr == '\0') {
505     numberoftetrahedronattributes = 0; // Default no attribute.
506   } else {
507     numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
508   }
509   if (numberofcorners != 4 && numberofcorners != 10) {
510     printf("Error:  Wrong number of corners %d (should be 4 or 10).\n",
511            numberofcorners);
512     fclose(infile);
513     return false;
514   }
515 
516   // Allocate memory for tetrahedra.
517   tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
518   if (tetrahedronlist == (int *) nullptr) {
519     terminatetetgen(1);
520   }
521   // Allocate memory for output tetrahedron attributes if necessary.
522   if (numberoftetrahedronattributes > 0) {
523     tetrahedronattributelist = new REAL[numberoftetrahedra *
524                                         numberoftetrahedronattributes];
525     if (tetrahedronattributelist == (REAL *) nullptr) {
526       terminatetetgen(1);
527     }
528   }
529 
530   // Read the list of tetrahedra.
531   index = 0;
532   attribindex = 0;
533   for (i = 0; i < numberoftetrahedra; i++) {
534     // Read tetrahedron index and the tetrahedron's corners.
535     stringptr = readnumberline(inputline, infile, infilename);
536     for (j = 0; j < numberofcorners; j++) {
537       stringptr = findnextnumber(stringptr);
538       if (*stringptr == '\0') {
539         printf("Error:  Tetrahedron %d is missing vertex %d in %s.\n",
540                i + firstnumber, j + 1, infilename);
541         terminatetetgen(1);
542       }
543       corner = (int) strtol(stringptr, &stringptr, 0);
544       if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
545         printf("Error:  Tetrahedron %d has an invalid vertex index.\n",
546                i + firstnumber);
547         terminatetetgen(1);
548       }
549       tetrahedronlist[index++] = corner;
550     }
551     // Read the tetrahedron's attributes.
552     for (j = 0; j < numberoftetrahedronattributes; j++) {
553       stringptr = findnextnumber(stringptr);
554       if (*stringptr == '\0') {
555         attrib = 0.0;
556       } else {
557         attrib = (REAL) strtod(stringptr, &stringptr);
558       }
559       tetrahedronattributelist[attribindex++] = attrib;
560     }
561   }
562 
563   fclose(infile);
564 
565   return true;
566 }
567 
568 ///////////////////////////////////////////////////////////////////////////////
569 //                                                                           //
570 // load_vol()    Load a list of volume constraints from a .vol file.         //
571 //                                                                           //
572 ///////////////////////////////////////////////////////////////////////////////
573 
load_vol(char * filebasename)574 bool tetgenio::load_vol(char* filebasename)
575 {
576   FILE *infile;
577   char inelefilename[FILENAMESIZE];
578   char infilename[FILENAMESIZE];
579   char inputline[INPUTLINESIZE];
580   char *stringptr;
581   REAL volume;
582   int volelements;
583   int i;
584 
585   strcpy(infilename, filebasename);
586   strcat(infilename, ".vol");
587 
588   infile = fopen(infilename, "r");
589   if (infile != (FILE *) nullptr) {
590     printf("Opening %s.\n", infilename);
591   } else {
592     return false;
593   }
594 
595   // Read number of tetrahedra.
596   stringptr = readnumberline(inputline, infile, infilename);
597   volelements = (int) strtol (stringptr, &stringptr, 0);
598   if (volelements != numberoftetrahedra) {
599     strcpy(inelefilename, filebasename);
600     strcat(infilename, ".ele");
601     printf("Warning:  %s and %s disagree on number of tetrahedra.\n",
602            inelefilename, infilename);
603     fclose(infile);
604     return false;
605   }
606 
607   tetrahedronvolumelist = new REAL[volelements];
608   if (tetrahedronvolumelist == (REAL *) nullptr) {
609     terminatetetgen(1);
610   }
611 
612   // Read the list of volume constraints.
613   for (i = 0; i < volelements; i++) {
614     stringptr = readnumberline(inputline, infile, infilename);
615     stringptr = findnextnumber(stringptr);
616     if (*stringptr == '\0') {
617       volume = -1.0; // No constraint on this tetrahedron.
618     } else {
619       volume = (REAL) strtod(stringptr, &stringptr);
620     }
621     tetrahedronvolumelist[i] = volume;
622   }
623 
624   fclose(infile);
625 
626   return true;
627 }
628 
629 ///////////////////////////////////////////////////////////////////////////////
630 //                                                                           //
631 // load_var()    Load constraints applied on facets, segments, and nodes     //
632 //               from a .var file.                                           //
633 //                                                                           //
634 ///////////////////////////////////////////////////////////////////////////////
635 
load_var(char * filebasename)636 bool tetgenio::load_var(char* filebasename)
637 {
638   FILE *infile;
639   char varfilename[FILENAMESIZE];
640   char inputline[INPUTLINESIZE];
641   char *stringptr;
642   int index;
643   int i;
644 
645   // Variant constraints are saved in file "filename.var".
646   strcpy(varfilename, filebasename);
647   strcat(varfilename, ".var");
648   infile = fopen(varfilename, "r");
649   if (infile != (FILE *) nullptr) {
650     printf("Opening %s.\n", varfilename);
651   } else {
652     return false;
653   }
654 
655   // Read the facet constraint section.
656   stringptr = readnumberline(inputline, infile, varfilename);
657   if (*stringptr != '\0') {
658     numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
659   } else {
660     numberoffacetconstraints = 0;
661   }
662   if (numberoffacetconstraints > 0) {
663     // Initialize 'facetconstraintlist'.
664     facetconstraintlist = new REAL[numberoffacetconstraints * 2];
665     index = 0;
666     for (i = 0; i < numberoffacetconstraints; i++) {
667       stringptr = readnumberline(inputline, infile, varfilename);
668       stringptr = findnextnumber(stringptr);
669       if (*stringptr == '\0') {
670         printf("Error:  facet constraint %d has no facet marker.\n",
671                firstnumber + i);
672         break;
673       } else {
674         facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
675       }
676       stringptr = findnextnumber(stringptr);
677       if (*stringptr == '\0') {
678         printf("Error:  facet constraint %d has no maximum area bound.\n",
679                firstnumber + i);
680         break;
681       } else {
682         facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
683       }
684     }
685     if (i < numberoffacetconstraints) {
686       // This must be caused by an error.
687       fclose(infile);
688       return false;
689     }
690   }
691 
692   // Read the segment constraint section.
693   stringptr = readnumberline(inputline, infile, varfilename);
694   if (*stringptr != '\0') {
695     numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
696   } else {
697     numberofsegmentconstraints = 0;
698   }
699   if (numberofsegmentconstraints > 0) {
700     // Initialize 'segmentconstraintlist'.
701     segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
702     index = 0;
703     for (i = 0; i < numberofsegmentconstraints; i++) {
704       stringptr = readnumberline(inputline, infile, varfilename);
705       stringptr = findnextnumber(stringptr);
706       if (*stringptr == '\0') {
707         printf("Error:  segment constraint %d has no frist endpoint.\n",
708                firstnumber + i);
709         break;
710       } else {
711         segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
712       }
713       stringptr = findnextnumber(stringptr);
714       if (*stringptr == '\0') {
715         printf("Error:  segment constraint %d has no second endpoint.\n",
716                firstnumber + i);
717         break;
718       } else {
719         segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
720       }
721       stringptr = findnextnumber(stringptr);
722       if (*stringptr == '\0') {
723         printf("Error:  segment constraint %d has no maximum length bound.\n",
724                firstnumber + i);
725         break;
726       } else {
727         segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
728       }
729     }
730     if (i < numberofsegmentconstraints) {
731       // This must be caused by an error.
732       fclose(infile);
733       return false;
734     }
735   }
736 
737   fclose(infile);
738   return true;
739 }
740 
741 ///////////////////////////////////////////////////////////////////////////////
742 //                                                                           //
743 // load_mtr()    Load a size specification map from a .mtr file.             //
744 //                                                                           //
745 ///////////////////////////////////////////////////////////////////////////////
746 
load_mtr(char * filebasename)747 bool tetgenio::load_mtr(char* filebasename)
748 {
749   FILE *infile;
750   char mtrfilename[FILENAMESIZE];
751   char inputline[INPUTLINESIZE];
752   char *stringptr;
753   REAL mtr;
754   int ptnum;
755   int mtrindex;
756   int i, j;
757 
758   strcpy(mtrfilename, filebasename);
759   strcat(mtrfilename, ".mtr");
760   infile = fopen(mtrfilename, "r");
761   if (infile != (FILE *) nullptr) {
762     printf("Opening %s.\n", mtrfilename);
763   } else {
764     return false;
765   }
766 
767   // Read the number of points.
768   stringptr = readnumberline(inputline, infile, mtrfilename);
769   ptnum = (int) strtol (stringptr, &stringptr, 0);
770   if (ptnum != numberofpoints) {
771     printf("  !! Point numbers are not equal. Ignored.\n");
772     fclose(infile);
773     return false;
774   }
775   // Read the number of columns (1, 3, or 6).
776   stringptr = findnextnumber(stringptr); // Skip number of points.
777   if (*stringptr != '\0') {
778     numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
779   }
780   if (numberofpointmtrs == 0) {
781     // Column number doesn't match. Set a default number (1).
782     numberofpointmtrs = 1;
783   }
784 
785   // Allocate space for pointmtrlist.
786   pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
787   if (pointmtrlist == (REAL *) nullptr) {
788     terminatetetgen(1);
789   }
790   mtrindex = 0;
791   for (i = 0; i < numberofpoints; i++) {
792     // Read metrics.
793     stringptr = readnumberline(inputline, infile, mtrfilename);
794     for (j = 0; j < numberofpointmtrs; j++) {
795       if (*stringptr == '\0') {
796         printf("Error:  Metric %d is missing value #%d in %s.\n",
797                i + firstnumber, j + 1, mtrfilename);
798         terminatetetgen(1);
799       }
800       mtr = (REAL) strtod(stringptr, &stringptr);
801       pointmtrlist[mtrindex++] = mtr;
802       stringptr = findnextnumber(stringptr);
803     }
804   }
805 
806   fclose(infile);
807   return true;
808 }
809 
810 ///////////////////////////////////////////////////////////////////////////////
811 //                                                                           //
812 // load_poly()    Load a PL complex from a .poly or a .smesh file.           //
813 //                                                                           //
814 ///////////////////////////////////////////////////////////////////////////////
815 
load_poly(char * filebasename)816 bool tetgenio::load_poly(char* filebasename)
817 {
818   FILE *infile;
819   char inpolyfilename[FILENAMESIZE];
820   char insmeshfilename[FILENAMESIZE];
821   char inputline[INPUTLINESIZE];
822   char *stringptr, *infilename;
823   int smesh, markers, uvflag, currentmarker;
824   int index;
825   int i, j, k;
826 
827   // Assembling the actual file names we want to open.
828   strcpy(inpolyfilename, filebasename);
829   strcpy(insmeshfilename, filebasename);
830   strcat(inpolyfilename, ".poly");
831   strcat(insmeshfilename, ".smesh");
832 
833   // First assume it is a .poly file.
834   smesh = 0;
835   // Try to open a .poly file.
836   infile = fopen(inpolyfilename, "r");
837   if (infile == (FILE *) nullptr) {
838     // .poly doesn't exist! Try to open a .smesh file.
839     infile = fopen(insmeshfilename, "r");
840     if (infile == (FILE *) nullptr) {
841       printf("  Cannot access file %s and %s.\n",
842              inpolyfilename, insmeshfilename);
843       return false;
844     } else {
845       printf("Opening %s.\n", insmeshfilename);
846       infilename = insmeshfilename;
847     }
848     smesh = 1;
849   } else {
850     printf("Opening %s.\n", inpolyfilename);
851     infilename = inpolyfilename;
852   }
853 
854   // Initialize the default values.
855   mesh_dim = 3;  // Three-dimemsional accoordinates.
856   numberofpointattributes = 0;  // no point attribute.
857   markers = 0;  // no boundary marker.
858   uvflag = 0; // no uv parameters (reuqired by a PSC).
859 
860   // Read number of points, number of dimensions, number of point
861   //   attributes, and number of boundary markers.
862   stringptr = readnumberline(inputline, infile, infilename);
863   numberofpoints = (int) strtol (stringptr, &stringptr, 0);
864   stringptr = findnextnumber(stringptr);
865   if (*stringptr != '\0') {
866     mesh_dim = (int) strtol (stringptr, &stringptr, 0);
867   }
868   stringptr = findnextnumber(stringptr);
869   if (*stringptr != '\0') {
870     numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
871   }
872   stringptr = findnextnumber(stringptr);
873   if (*stringptr != '\0') {
874     markers = (int) strtol (stringptr, &stringptr, 0);
875   }
876   if (*stringptr != '\0') {
877     uvflag = (int) strtol (stringptr, &stringptr, 0);
878   }
879 
880   if (numberofpoints > 0) {
881     // Load the list of nodes.
882     if (!load_node_call(infile, markers, uvflag, infilename)) {
883       fclose(infile);
884       return false;
885     }
886   } else {
887     // If the .poly or .smesh file claims there are zero points, that
888     //   means the points should be read from a separate .node file.
889     if (!load_node(filebasename)) {
890       fclose(infile);
891       return false;
892     }
893   }
894 
895   if ((mesh_dim != 3) && (mesh_dim != 2)) {
896     printf("Input error:  TetGen only works for 2D & 3D point sets.\n");
897     fclose(infile);
898     return false;
899   }
900   if (numberofpoints < (mesh_dim + 1)) {
901     printf("Input error:  TetGen needs at least %d points.\n", mesh_dim + 1);
902     fclose(infile);
903     return false;
904   }
905 
906   facet *f;
907   polygon *p;
908 
909   if (mesh_dim == 3) {
910 
911     // Read number of facets and number of boundary markers.
912     stringptr = readnumberline(inputline, infile, infilename);
913     if (stringptr == nullptr) {
914       // No facet list, return.
915       fclose(infile);
916       return true;
917     }
918     numberoffacets = (int) strtol (stringptr, &stringptr, 0);
919     if (numberoffacets <= 0) {
920       // No facet list, return.
921       fclose(infile);
922       return true;
923     }
924     stringptr = findnextnumber(stringptr);
925     if (*stringptr == '\0') {
926       markers = 0;  // no boundary marker.
927     } else {
928       markers = (int) strtol (stringptr, &stringptr, 0);
929     }
930 
931     // Initialize the 'facetlist', 'facetmarkerlist'.
932     facetlist = new facet[numberoffacets];
933     if (markers == 1) {
934       facetmarkerlist = new int[numberoffacets];
935     }
936 
937     // Read data into 'facetlist', 'facetmarkerlist'.
938     if (smesh == 0) {
939       // Facets are in .poly file format.
940       for (i = 1; i <= numberoffacets; i++) {
941         f = &(facetlist[i - 1]);
942         init(f);
943         f->numberofholes = 0;
944         currentmarker = 0;
945         // Read number of polygons, number of holes, and a boundary marker.
946         stringptr = readnumberline(inputline, infile, infilename);
947         f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
948         stringptr = findnextnumber(stringptr);
949         if (*stringptr != '\0') {
950           f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
951           if (markers == 1) {
952             stringptr = findnextnumber(stringptr);
953             if (*stringptr != '\0') {
954               currentmarker = (int) strtol(stringptr, &stringptr, 0);
955             }
956           }
957         }
958         // Initialize facetmarker if it needs.
959         if (markers == 1) {
960           facetmarkerlist[i - 1] = currentmarker;
961         }
962         // Each facet should has at least one polygon.
963         if (f->numberofpolygons <= 0) {
964           printf("Error:  Wrong number of polygon in %d facet.\n", i);
965           break;
966         }
967         // Initialize the 'f->polygonlist'.
968         f->polygonlist = new polygon[f->numberofpolygons];
969         // Go through all polygons, read in their vertices.
970         for (j = 1; j <= f->numberofpolygons; j++) {
971           p = &(f->polygonlist[j - 1]);
972           init(p);
973           // Read number of vertices of this polygon.
974           stringptr = readnumberline(inputline, infile, infilename);
975           p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
976           if (p->numberofvertices < 1) {
977             printf("Error:  Wrong polygon %d in facet %d\n", j, i);
978             break;
979           }
980           // Initialize 'p->vertexlist'.
981           p->vertexlist = new int[p->numberofvertices];
982           // Read all vertices of this polygon.
983           for (k = 1; k <= p->numberofvertices; k++) {
984             stringptr = findnextnumber(stringptr);
985             if (*stringptr == '\0') {
986               // Try to load another non-empty line and continue to read the
987               //   rest of vertices.
988               stringptr = readnumberline(inputline, infile, infilename);
989               if (*stringptr == '\0') {
990                 printf("Error: Missing %d endpoints of polygon %d in facet %d",
991                        p->numberofvertices - k, j, i);
992                 break;
993               }
994             }
995             p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
996           }
997         }
998         if (j <= f->numberofpolygons) {
999           // This must be caused by an error. However, there're j - 1
1000           //   polygons have been read. Reset the 'f->numberofpolygon'.
1001           if (j == 1) {
1002             // This is the first polygon.
1003             delete [] f->polygonlist;
1004           }
1005           f->numberofpolygons = j - 1;
1006           // No hole will be read even it exists.
1007           f->numberofholes = 0;
1008           break;
1009         }
1010         // If this facet has hole pints defined, read them.
1011         if (f->numberofholes > 0) {
1012           // Initialize 'f->holelist'.
1013           f->holelist = new REAL[f->numberofholes * 3];
1014           // Read the holes' coordinates.
1015           index = 0;
1016           for (j = 1; j <= f->numberofholes; j++) {
1017             stringptr = readnumberline(inputline, infile, infilename);
1018             for (k = 1; k <= 3; k++) {
1019               stringptr = findnextnumber(stringptr);
1020               if (*stringptr == '\0') {
1021                 printf("Error:  Hole %d in facet %d has no coordinates", j, i);
1022                 break;
1023               }
1024               f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1025             }
1026             if (k <= 3) {
1027               // This must be caused by an error.
1028               break;
1029             }
1030           }
1031           if (j <= f->numberofholes) {
1032             // This must be caused by an error.
1033             break;
1034           }
1035         }
1036       }
1037       if (i <= numberoffacets) {
1038         // This must be caused by an error.
1039         numberoffacets = i - 1;
1040         fclose(infile);
1041         return false;
1042       }
1043     } else { // poly == 0
1044       // Read the facets from a .smesh file.
1045       for (i = 1; i <= numberoffacets; i++) {
1046         f = &(facetlist[i - 1]);
1047         init(f);
1048         // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1049         //   contains exactly one polygon, no hole.
1050         f->numberofpolygons = 1;
1051         f->polygonlist = new polygon[f->numberofpolygons];
1052         p = &(f->polygonlist[0]);
1053         init(p);
1054         // Read number of vertices of this polygon.
1055         stringptr = readnumberline(inputline, infile, insmeshfilename);
1056         p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1057         if (p->numberofvertices < 1) {
1058           printf("Error:  Wrong number of vertex in facet %d\n", i);
1059           break;
1060         }
1061         // Initialize 'p->vertexlist'.
1062         p->vertexlist = new int[p->numberofvertices];
1063         for (k = 1; k <= p->numberofvertices; k++) {
1064           stringptr = findnextnumber(stringptr);
1065           if (*stringptr == '\0') {
1066             // Try to load another non-empty line and continue to read the
1067             //   rest of vertices.
1068             stringptr = readnumberline(inputline, infile, infilename);
1069             if (*stringptr == '\0') {
1070               printf("Error:  Missing %d endpoints in facet %d",
1071                      p->numberofvertices - k, i);
1072               break;
1073             }
1074           }
1075           p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1076         }
1077         if (k <= p->numberofvertices) {
1078           // This must be caused by an error.
1079           break;
1080         }
1081         // Read facet's boundary marker at last.
1082         if (markers == 1) {
1083           stringptr = findnextnumber(stringptr);
1084           if (*stringptr == '\0') {
1085             currentmarker = 0;
1086           } else {
1087             currentmarker = (int) strtol(stringptr, &stringptr, 0);
1088           }
1089           facetmarkerlist[i - 1] = currentmarker;
1090         }
1091       }
1092       if (i <= numberoffacets) {
1093         // This must be caused by an error.
1094         numberoffacets = i - 1;
1095         fclose(infile);
1096         return false;
1097       }
1098     }
1099 
1100     // Read the hole section.
1101     stringptr = readnumberline(inputline, infile, infilename);
1102     if (stringptr == nullptr) {
1103       // No hole list, return.
1104       fclose(infile);
1105       return true;
1106     }
1107     if (*stringptr != '\0') {
1108       numberofholes = (int) strtol (stringptr, &stringptr, 0);
1109     } else {
1110       numberofholes = 0;
1111     }
1112     if (numberofholes > 0) {
1113       // Initialize 'holelist'.
1114       holelist = new REAL[numberofholes * 3];
1115       for (i = 0; i < 3 * numberofholes; i += 3) {
1116         stringptr = readnumberline(inputline, infile, infilename);
1117         stringptr = findnextnumber(stringptr);
1118         if (*stringptr == '\0') {
1119           printf("Error:  Hole %d has no x coord.\n", firstnumber + (i / 3));
1120           break;
1121         } else {
1122           holelist[i] = (REAL) strtod(stringptr, &stringptr);
1123         }
1124         stringptr = findnextnumber(stringptr);
1125         if (*stringptr == '\0') {
1126           printf("Error:  Hole %d has no y coord.\n", firstnumber + (i / 3));
1127           break;
1128         } else {
1129           holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1130         }
1131         stringptr = findnextnumber(stringptr);
1132         if (*stringptr == '\0') {
1133           printf("Error:  Hole %d has no z coord.\n", firstnumber + (i / 3));
1134           break;
1135         } else {
1136           holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1137         }
1138       }
1139       if (i < 3 * numberofholes) {
1140         // This must be caused by an error.
1141         fclose(infile);
1142         return false;
1143       }
1144     }
1145 
1146     // Read the region section.  The 'region' section is optional, if we
1147     //   don't reach the end-of-file, try read it in.
1148     stringptr = readnumberline(inputline, infile, nullptr);
1149     if (stringptr != (char *) nullptr && *stringptr != '\0') {
1150       numberofregions = (int) strtol (stringptr, &stringptr, 0);
1151     } else {
1152       numberofregions = 0;
1153     }
1154     if (numberofregions > 0) {
1155       // Initialize 'regionlist'.
1156       regionlist = new REAL[numberofregions * 5];
1157       index = 0;
1158       for (i = 0; i < numberofregions; i++) {
1159         stringptr = readnumberline(inputline, infile, infilename);
1160         stringptr = findnextnumber(stringptr);
1161         if (*stringptr == '\0') {
1162           printf("Error:  Region %d has no x coordinate.\n", firstnumber + i);
1163           break;
1164         } else {
1165           regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1166         }
1167         stringptr = findnextnumber(stringptr);
1168         if (*stringptr == '\0') {
1169           printf("Error:  Region %d has no y coordinate.\n", firstnumber + i);
1170           break;
1171         } else {
1172           regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1173         }
1174         stringptr = findnextnumber(stringptr);
1175         if (*stringptr == '\0') {
1176           printf("Error:  Region %d has no z coordinate.\n", firstnumber + i);
1177           break;
1178         } else {
1179           regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1180         }
1181         stringptr = findnextnumber(stringptr);
1182         if (*stringptr == '\0') {
1183           printf("Error:  Region %d has no region attrib.\n", firstnumber + i);
1184           break;
1185         } else {
1186           regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1187         }
1188         stringptr = findnextnumber(stringptr);
1189         if (*stringptr == '\0') {
1190           regionlist[index] = regionlist[index - 1];
1191         } else {
1192           regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1193         }
1194         index++;
1195       }
1196       if (i < numberofregions) {
1197         // This must be caused by an error.
1198         fclose(infile);
1199         return false;
1200       }
1201     }
1202 
1203   } else {
1204 
1205     // Read a PSLG from Triangle's poly file.
1206     assert(mesh_dim == 2);
1207     // A PSLG is a facet of a PLC.
1208     numberoffacets = 1;
1209     // Initialize the 'facetlist'.
1210     facetlist = new facet[numberoffacets];
1211     facetmarkerlist = (int *) nullptr; // No facet markers.
1212     f = &(facetlist[0]);
1213     init(f);
1214     // Read number of segments.
1215     stringptr = readnumberline(inputline, infile, infilename);
1216     // Segments are degenerate polygons.
1217     f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
1218     if (f->numberofpolygons > 0) {
1219       f->polygonlist = new polygon[f->numberofpolygons];
1220     }
1221     // Go through all segments, read in their vertices.
1222     for (j = 0; j < f->numberofpolygons; j++) {
1223       p = &(f->polygonlist[j]);
1224       init(p);
1225       // Read in a segment.
1226       stringptr = readnumberline(inputline, infile, infilename);
1227       stringptr = findnextnumber(stringptr); // Skip its index.
1228       p->numberofvertices = 2; // A segment always has two vertices.
1229       p->vertexlist = new int[p->numberofvertices];
1230       p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0);
1231       stringptr = findnextnumber(stringptr);
1232       p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0);
1233     }
1234     // Read number of holes.
1235     stringptr = readnumberline(inputline, infile, infilename);
1236     f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
1237     if (f->numberofholes > 0) {
1238       // Initialize 'f->holelist'.
1239       f->holelist = new REAL[f->numberofholes * 3];
1240       // Read the holes' coordinates.
1241       for (j = 0; j < f->numberofholes; j++) {
1242         // Read a 2D hole point.
1243         stringptr = readnumberline(inputline, infile, infilename);
1244         stringptr = findnextnumber(stringptr); // Skip its index.
1245         f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr);
1246         stringptr = findnextnumber(stringptr);
1247         f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr);
1248         f->holelist[j * 3 + 2] = 0.0; // The z-coord.
1249       }
1250     }
1251     // The regions are skipped.
1252 
1253   }
1254 
1255   // End of reading poly/smesh file.
1256   fclose(infile);
1257   return true;
1258 }
1259 
1260 ///////////////////////////////////////////////////////////////////////////////
1261 //                                                                           //
1262 // load_off()    Load a polyhedron from a .off file.                         //
1263 //                                                                           //
1264 // The .off format is one of file formats of the Geomview, an interactive    //
1265 // program for viewing and manipulating geometric objects.  More information //
1266 // is available form: http://www.geomview.org.                               //
1267 //                                                                           //
1268 ///////////////////////////////////////////////////////////////////////////////
1269 
load_off(char * filebasename)1270 bool tetgenio::load_off(char* filebasename)
1271 {
1272   FILE *fp;
1273   tetgenio::facet *f;
1274   tetgenio::polygon *p;
1275   char infilename[FILENAMESIZE];
1276   char buffer[INPUTLINESIZE];
1277   char *bufferp;
1278   double *coord;
1279   int nverts = 0, iverts = 0;
1280   int nfaces = 0, ifaces = 0;
1281   int nedges = 0;
1282   int line_count = 0, i;
1283 
1284   // Default, the off file's index is from '0'. We check it by remembering the
1285   //   smallest index we found in the file. It should be either 0 or 1.
1286   int smallestidx = 0;
1287 
1288   strncpy(infilename, filebasename, 1024 - 1);
1289   infilename[FILENAMESIZE - 1] = '\0';
1290   if (infilename[0] == '\0') {
1291     printf("Error:  No filename.\n");
1292     return false;
1293   }
1294   if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1295     strcat(infilename, ".off");
1296   }
1297 
1298   if (!(fp = fopen(infilename, "r"))) {
1299     printf("  Unable to open file %s\n", infilename);
1300     return false;
1301   }
1302   printf("Opening %s.\n", infilename);
1303 
1304   while ((bufferp = readline(buffer, fp, &line_count)) != nullptr) {
1305     // Check section
1306     if (nverts == 0) {
1307       // Read header
1308       bufferp = strstr(bufferp, "OFF");
1309       if (bufferp != nullptr) {
1310         // Read mesh counts
1311         bufferp = findnextnumber(bufferp); // Skip field "OFF".
1312         if (*bufferp == '\0') {
1313           // Read a non-empty line.
1314           bufferp = readline(buffer, fp, &line_count);
1315         }
1316         if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1317             || (nverts == 0)) {
1318           printf("Syntax error reading header on line %d in file %s\n",
1319                  line_count, infilename);
1320           fclose(fp);
1321           return false;
1322         }
1323         // Allocate memory for 'tetgenio'
1324         if (nverts > 0) {
1325           numberofpoints = nverts;
1326           pointlist = new REAL[nverts * 3];
1327           smallestidx = nverts + 1; // A bigger enough number.
1328         }
1329         if (nfaces > 0) {
1330           numberoffacets = nfaces;
1331           facetlist = new tetgenio::facet[nfaces];
1332         }
1333       }
1334     } else if (iverts < nverts) {
1335       // Read vertex coordinates
1336       coord = &pointlist[iverts * 3];
1337       for (i = 0; i < 3; i++) {
1338         if (*bufferp == '\0') {
1339           printf("Syntax error reading vertex coords on line %d in file %s\n",
1340                  line_count, infilename);
1341           fclose(fp);
1342           return false;
1343         }
1344         coord[i] = (REAL) strtod(bufferp, &bufferp);
1345         bufferp = findnextnumber(bufferp);
1346       }
1347       iverts++;
1348     } else if (ifaces < nfaces) {
1349       // Get next face
1350       f = &facetlist[ifaces];
1351       init(f);
1352       // In .off format, each facet has one polygon, no hole.
1353       f->numberofpolygons = 1;
1354       f->polygonlist = new tetgenio::polygon[1];
1355       p = &f->polygonlist[0];
1356       init(p);
1357       // Read the number of vertices, it should be greater than 0.
1358       p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1359       if (p->numberofvertices == 0) {
1360         printf("Syntax error reading polygon on line %d in file %s\n",
1361                line_count, infilename);
1362         fclose(fp);
1363         return false;
1364       }
1365       // Allocate memory for face vertices
1366       p->vertexlist = new int[p->numberofvertices];
1367       for (i = 0; i < p->numberofvertices; i++) {
1368         bufferp = findnextnumber(bufferp);
1369         if (*bufferp == '\0') {
1370           printf("Syntax error reading polygon on line %d in file %s\n",
1371                  line_count, infilename);
1372           fclose(fp);
1373           return false;
1374         }
1375         p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1376         // Detect the smallest index.
1377         if (p->vertexlist[i] < smallestidx) {
1378           smallestidx = p->vertexlist[i];
1379         }
1380       }
1381       ifaces++;
1382     } else {
1383       // Should never get here
1384       printf("Found extra text starting at line %d in file %s\n", line_count,
1385              infilename);
1386       break;
1387     }
1388   }
1389 
1390   // Close file
1391   fclose(fp);
1392 
1393   // Decide the firstnumber of the index.
1394   if (smallestidx == 0) {
1395     firstnumber = 0;
1396   } else if (smallestidx == 1) {
1397     firstnumber = 1;
1398   } else {
1399     printf("A wrong smallest index (%d) was detected in file %s\n",
1400            smallestidx, infilename);
1401     return false;
1402   }
1403 
1404   if (iverts != nverts) {
1405     printf("Expected %d vertices, but read only %d vertices in file %s\n",
1406            nverts, iverts, infilename);
1407     return false;
1408   }
1409   if (ifaces != nfaces) {
1410     printf("Expected %d faces, but read only %d faces in file %s\n",
1411            nfaces, ifaces, infilename);
1412     return false;
1413   }
1414 
1415   return true;
1416 }
1417 
1418 ///////////////////////////////////////////////////////////////////////////////
1419 //                                                                           //
1420 // load_ply()    Load a polyhedron from a .ply file.                         //
1421 //                                                                           //
1422 // This is a simplified version of reading .ply files, which only reads the  //
1423 // set of vertices and the set of faces. Other informations (such as color,  //
1424 // material, texture, etc) in .ply file are ignored. Complete routines for   //
1425 // reading and writing ,ply files are available from: http://www.cc.gatech.  //
1426 // edu/projects/large_models/ply.html.  Except the header section, ply file  //
1427 // format has exactly the same format for listing vertices and polygons as   //
1428 // off file format.                                                          //
1429 //                                                                           //
1430 ///////////////////////////////////////////////////////////////////////////////
1431 
load_ply(char * filebasename)1432 bool tetgenio::load_ply(char* filebasename)
1433 {
1434   FILE *fp;
1435   tetgenio::facet *f;
1436   tetgenio::polygon *p;
1437   char infilename[FILENAMESIZE];
1438   char buffer[INPUTLINESIZE];
1439   char *bufferp, *str;
1440   double *coord;
1441   int endheader = 0, format = 0;
1442   int nverts = 0, iverts = 0;
1443   int nfaces = 0, ifaces = 0;
1444   int line_count = 0, i;
1445 
1446   // Default, the ply file's index is from '0'. We check it by remembering the
1447   //   smallest index we found in the file. It should be either 0 or 1.
1448   int smallestidx = 0;
1449 
1450   strncpy(infilename, filebasename, FILENAMESIZE - 1);
1451   infilename[FILENAMESIZE - 1] = '\0';
1452   if (infilename[0] == '\0') {
1453     printf("Error:  No filename.\n");
1454     return false;
1455   }
1456   if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1457     strcat(infilename, ".ply");
1458   }
1459 
1460   if (!(fp = fopen(infilename, "r"))) {
1461     printf("Error:  Unable to open file %s\n", infilename);
1462     return false;
1463   }
1464   printf("Opening %s.\n", infilename);
1465 
1466   while ((bufferp = readline(buffer, fp, &line_count)) != nullptr) {
1467     if (!endheader) {
1468       // Find if it is the keyword "end_header".
1469       str = strstr(bufferp, "end_header");
1470       // strstr() is case sensitive.
1471       if (!str) str = strstr(bufferp, "End_header");
1472       if (!str) str = strstr(bufferp, "End_Header");
1473       if (str) {
1474         // This is the end of the header section.
1475         endheader = 1;
1476         continue;
1477       }
1478       // Parse the number of vertices and the number of faces.
1479       if (nverts == 0 || nfaces == 0) {
1480         // Find if it si the keyword "element".
1481         str = strstr(bufferp, "element");
1482         if (!str) str = strstr(bufferp, "Element");
1483         if (str) {
1484           bufferp = findnextfield(str);
1485           if (*bufferp == '\0') {
1486             printf("Syntax error reading element type on line%d in file %s\n",
1487                    line_count, infilename);
1488             fclose(fp);
1489             return false;
1490           }
1491           if (nverts == 0) {
1492             // Find if it is the keyword "vertex".
1493             str = strstr(bufferp, "vertex");
1494             if (!str) str = strstr(bufferp, "Vertex");
1495             if (str) {
1496               bufferp = findnextnumber(str);
1497               if (*bufferp == '\0') {
1498                 printf("Syntax error reading vertex number on line");
1499                 printf(" %d in file %s\n", line_count, infilename);
1500                 fclose(fp);
1501                 return false;
1502               }
1503               nverts = (int) strtol(bufferp, &bufferp, 0);
1504               // Allocate memory for 'tetgenio'
1505               if (nverts > 0) {
1506                 numberofpoints = nverts;
1507                 pointlist = new REAL[nverts * 3];
1508                 smallestidx = nverts + 1; // A big enough index.
1509               }
1510             }
1511           }
1512           if (nfaces == 0) {
1513             // Find if it is the keyword "face".
1514             str = strstr(bufferp, "face");
1515             if (!str) str = strstr(bufferp, "Face");
1516             if (str) {
1517               bufferp = findnextnumber(str);
1518               if (*bufferp == '\0') {
1519                 printf("Syntax error reading face number on line");
1520                 printf(" %d in file %s\n", line_count, infilename);
1521                 fclose(fp);
1522                 return false;
1523               }
1524               nfaces = (int) strtol(bufferp, &bufferp, 0);
1525               // Allocate memory for 'tetgenio'
1526               if (nfaces > 0) {
1527                 numberoffacets = nfaces;
1528                 facetlist = new tetgenio::facet[nfaces];
1529               }
1530             }
1531           }
1532         } // It is not the string "element".
1533       }
1534       if (format == 0) {
1535         // Find the keyword "format".
1536         str = strstr(bufferp, "format");
1537         if (!str) str = strstr(bufferp, "Format");
1538         if (str) {
1539           format = 1;
1540           bufferp = findnextfield(str);
1541           // Find if it is the string "ascii".
1542           str = strstr(bufferp, "ascii");
1543           if (!str) str = strstr(bufferp, "ASCII");
1544           if (!str) {
1545             printf("This routine only reads ascii format of ply files.\n");
1546             printf("Hint: You can convert the binary to ascii format by\n");
1547             printf("  using the provided ply tools:\n");
1548             printf("  ply2ascii < %s > ascii_%s\n", infilename, infilename);
1549             fclose(fp);
1550             return false;
1551           }
1552         }
1553       }
1554     } else if (iverts < nverts) {
1555       // Read vertex coordinates
1556       coord = &pointlist[iverts * 3];
1557       for (i = 0; i < 3; i++) {
1558         if (*bufferp == '\0') {
1559           printf("Syntax error reading vertex coords on line %d in file %s\n",
1560                  line_count, infilename);
1561           fclose(fp);
1562           return false;
1563         }
1564         coord[i] = (REAL) strtod(bufferp, &bufferp);
1565         bufferp = findnextnumber(bufferp);
1566       }
1567       iverts++;
1568     } else if (ifaces < nfaces) {
1569       // Get next face
1570       f = &facetlist[ifaces];
1571       init(f);
1572       // In .off format, each facet has one polygon, no hole.
1573       f->numberofpolygons = 1;
1574       f->polygonlist = new tetgenio::polygon[1];
1575       p = &f->polygonlist[0];
1576       init(p);
1577       // Read the number of vertices, it should be greater than 0.
1578       p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1579       if (p->numberofvertices == 0) {
1580         printf("Syntax error reading polygon on line %d in file %s\n",
1581                line_count, infilename);
1582         fclose(fp);
1583         return false;
1584       }
1585       // Allocate memory for face vertices
1586       p->vertexlist = new int[p->numberofvertices];
1587       for (i = 0; i < p->numberofvertices; i++) {
1588         bufferp = findnextnumber(bufferp);
1589         if (*bufferp == '\0') {
1590           printf("Syntax error reading polygon on line %d in file %s\n",
1591                  line_count, infilename);
1592           fclose(fp);
1593           return false;
1594         }
1595         p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1596         if (p->vertexlist[i] < smallestidx) {
1597           smallestidx = p->vertexlist[i];
1598         }
1599       }
1600       ifaces++;
1601     } else {
1602       // Should never get here
1603       printf("Found extra text starting at line %d in file %s\n", line_count,
1604              infilename);
1605       break;
1606     }
1607   }
1608 
1609   // Close file
1610   fclose(fp);
1611 
1612   // Decide the firstnumber of the index.
1613   if (smallestidx == 0) {
1614     firstnumber = 0;
1615   } else if (smallestidx == 1) {
1616     firstnumber = 1;
1617   } else {
1618     printf("A wrong smallest index (%d) was detected in file %s\n",
1619            smallestidx, infilename);
1620     return false;
1621   }
1622 
1623   if (iverts != nverts) {
1624     printf("Expected %d vertices, but read only %d vertices in file %s\n",
1625            nverts, iverts, infilename);
1626     return false;
1627   }
1628   if (ifaces != nfaces) {
1629     printf("Expected %d faces, but read only %d faces in file %s\n",
1630            nfaces, ifaces, infilename);
1631     return false;
1632   }
1633 
1634   return true;
1635 }
1636 
1637 ///////////////////////////////////////////////////////////////////////////////
1638 //                                                                           //
1639 // load_stl()    Load a surface mesh from a .stl file.                       //
1640 //                                                                           //
1641 // The .stl or stereolithography format is an ASCII or binary file used in   //
1642 // manufacturing.  It is a list of the triangular surfaces that describe a   //
1643 // computer generated solid model. This is the standard input for most rapid //
1644 // prototyping machines.                                                     //
1645 //                                                                           //
1646 // Comment: A .stl file many contain many duplicated points.  They will be   //
1647 // unified during the Delaunay tetrahedralization process.                   //
1648 //                                                                           //
1649 ///////////////////////////////////////////////////////////////////////////////
1650 
load_stl(char * filebasename)1651 bool tetgenio::load_stl(char* filebasename)
1652 {
1653   FILE *fp;
1654   tetgenmesh::arraypool *plist;
1655   tetgenio::facet *f;
1656   tetgenio::polygon *p;
1657   char infilename[FILENAMESIZE];
1658   char buffer[INPUTLINESIZE];
1659   char *bufferp, *str;
1660   double *coord;
1661   int solid = 0;
1662   int nverts = 0, iverts = 0;
1663   int nfaces = 0;
1664   int line_count = 0, i;
1665 
1666   strncpy(infilename, filebasename, FILENAMESIZE - 1);
1667   infilename[FILENAMESIZE - 1] = '\0';
1668   if (infilename[0] == '\0') {
1669     printf("Error:  No filename.\n");
1670     return false;
1671   }
1672   if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1673     strcat(infilename, ".stl");
1674   }
1675 
1676   if (!(fp = fopen(infilename, "r"))) {
1677     printf("Error:  Unable to open file %s\n", infilename);
1678     return false;
1679   }
1680   printf("Opening %s.\n", infilename);
1681 
1682   // STL file has no number of points available. Use a list to read points.
1683   plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
1684 
1685   while ((bufferp = readline(buffer, fp, &line_count)) != nullptr) {
1686     // The ASCII .stl file must start with the lower case keyword solid and
1687     //   end with endsolid.
1688     if (solid == 0) {
1689       // Read header
1690       bufferp = strstr(bufferp, "solid");
1691       if (bufferp != nullptr) {
1692         solid = 1;
1693       }
1694     } else {
1695       // We're inside the block of the solid.
1696       str = bufferp;
1697       // Is this the end of the solid.
1698       bufferp = strstr(bufferp, "endsolid");
1699       if (bufferp != nullptr) {
1700         solid = 0;
1701       } else {
1702         // Read the XYZ coordinates if it is a vertex.
1703         bufferp = str;
1704         bufferp = strstr(bufferp, "vertex");
1705         if (bufferp != nullptr) {
1706           plist->newindex((void **) &coord);
1707           for (i = 0; i < 3; i++) {
1708             bufferp = findnextnumber(bufferp);
1709             if (*bufferp == '\0') {
1710               printf("Syntax error reading vertex coords on line %d\n",
1711                    line_count);
1712               delete plist;
1713               fclose(fp);
1714               return false;
1715             }
1716             coord[i] = (REAL) strtod(bufferp, &bufferp);
1717           }
1718         }
1719       }
1720     }
1721   }
1722   fclose(fp);
1723 
1724   nverts = (int) plist->objects;
1725   // nverts should be an integer times 3 (every 3 vertices denote a face).
1726   if (nverts == 0 || (nverts % 3 != 0)) {
1727     printf("Error:  Wrong number of vertices in file %s.\n", infilename);
1728     delete plist;
1729     return false;
1730   }
1731   numberofpoints = nverts;
1732   pointlist = new REAL[nverts * 3];
1733   for (i = 0; i < nverts; i++) {
1734     coord = (double *) fastlookup(plist, i);
1735     iverts = i * 3;
1736     pointlist[iverts] = (REAL) coord[0];
1737     pointlist[iverts + 1] = (REAL) coord[1];
1738     pointlist[iverts + 2] = (REAL) coord[2];
1739   }
1740 
1741   nfaces = (int) (nverts / 3);
1742   numberoffacets = nfaces;
1743   facetlist = new tetgenio::facet[nfaces];
1744 
1745   // Default use '1' as the array starting index.
1746   firstnumber = 1;
1747   iverts = firstnumber;
1748   for (i = 0; i < nfaces; i++) {
1749     f = &facetlist[i];
1750     init(f);
1751     // In .stl format, each facet has one polygon, no hole.
1752     f->numberofpolygons = 1;
1753     f->polygonlist = new tetgenio::polygon[1];
1754     p = &f->polygonlist[0];
1755     init(p);
1756     // Each polygon has three vertices.
1757     p->numberofvertices = 3;
1758     p->vertexlist = new int[p->numberofvertices];
1759     p->vertexlist[0] = iverts;
1760     p->vertexlist[1] = iverts + 1;
1761     p->vertexlist[2] = iverts + 2;
1762     iverts += 3;
1763   }
1764 
1765   delete plist;
1766   return true;
1767 }
1768 
1769 ///////////////////////////////////////////////////////////////////////////////
1770 //                                                                           //
1771 // load_medit()    Load a surface mesh from a .mesh file.                    //
1772 //                                                                           //
1773 // The .mesh format is the file format of Medit, a user-friendly interactive //
1774 // mesh viewer program.                                                      //
1775 //                                                                           //
1776 ///////////////////////////////////////////////////////////////////////////////
1777 
load_medit(char * filebasename,int istetmesh)1778 bool tetgenio::load_medit(char* filebasename, int istetmesh)
1779 {
1780   FILE *fp;
1781   tetgenio::facet *tmpflist, *f;
1782   tetgenio::polygon *p;
1783   char infilename[FILENAMESIZE];
1784   char buffer[INPUTLINESIZE];
1785   char *bufferp, *str;
1786   double *coord;
1787   int *tmpfmlist;
1788   int dimension = 0;
1789   int nverts = 0;
1790   int nfaces = 0;
1791   int ntets = 0;
1792   int line_count = 0;
1793   int corners = 0; // 3 (triangle) or 4 (quad).
1794   int *plist;
1795   int i, j;
1796 
1797   int smallestidx = 0;
1798 
1799   strncpy(infilename, filebasename, FILENAMESIZE - 1);
1800   infilename[FILENAMESIZE - 1] = '\0';
1801   if (infilename[0] == '\0') {
1802     printf("Error:  No filename.\n");
1803     return false;
1804   }
1805   if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1806     strcat(infilename, ".mesh");
1807   }
1808 
1809   if (!(fp = fopen(infilename, "r"))) {
1810     printf("Error:  Unable to open file %s\n", infilename);
1811     return false;
1812   }
1813   printf("Opening %s.\n", infilename);
1814 
1815   while ((bufferp = readline(buffer, fp, &line_count)) != nullptr) {
1816     if (*bufferp == '#') continue;  // A comment line is skipped.
1817     if (dimension == 0) {
1818       // Find if it is the keyword "Dimension".
1819       str = strstr(bufferp, "Dimension");
1820       if (!str) str = strstr(bufferp, "dimension");
1821       if (!str) str = strstr(bufferp, "DIMENSION");
1822       if (str) {
1823         // Read the dimensions
1824         bufferp = findnextnumber(str); // Skip field "Dimension".
1825         if (*bufferp == '\0') {
1826           // Read a non-empty line.
1827           bufferp = readline(buffer, fp, &line_count);
1828         }
1829         dimension = (int) strtol(bufferp, &bufferp, 0);
1830         if (dimension != 2 && dimension != 3) {
1831           printf("Unknown dimension in file on line %d in file %s\n",
1832                  line_count, infilename);
1833           fclose(fp);
1834           return false;
1835         }
1836         mesh_dim = dimension;
1837       }
1838     }
1839     if (nverts == 0) {
1840       // Find if it is the keyword "Vertices".
1841       str = strstr(bufferp, "Vertices");
1842       if (!str) str = strstr(bufferp, "vertices");
1843       if (!str) str = strstr(bufferp, "VERTICES");
1844       if (str) {
1845         // Read the number of vertices.
1846         bufferp = findnextnumber(str); // Skip field "Vertices".
1847         if (*bufferp == '\0') {
1848           // Read a non-empty line.
1849           bufferp = readline(buffer, fp, &line_count);
1850         }
1851         nverts = (int) strtol(bufferp, &bufferp, 0);
1852         // Initialize the smallest index.
1853         smallestidx = nverts + 1;
1854         // Allocate memory for 'tetgenio'
1855         if (nverts > 0) {
1856           numberofpoints = nverts;
1857           pointlist = new REAL[nverts * 3];
1858         }
1859         // Read the follwoing node list.
1860         for (i = 0; i < nverts; i++) {
1861           bufferp = readline(buffer, fp, &line_count);
1862           if (bufferp == nullptr) {
1863             printf("Unexpected end of file on line %d in file %s\n",
1864                    line_count, infilename);
1865             fclose(fp);
1866             return false;
1867           }
1868           // Read vertex coordinates
1869           coord = &pointlist[i * 3];
1870           for (j = 0; j < 3; j++) {
1871             if (*bufferp == '\0') {
1872               printf("Syntax error reading vertex coords on line");
1873               printf(" %d in file %s\n", line_count, infilename);
1874               fclose(fp);
1875               return false;
1876             }
1877             if ((j < 2) || (dimension == 3)) {
1878               coord[j] = (REAL) strtod(bufferp, &bufferp);
1879             } else {
1880               assert((j == 2) && (dimension == 2));
1881               coord[j] = 0.0;
1882             }
1883             bufferp = findnextnumber(bufferp);
1884           }
1885         }
1886         continue;
1887       }
1888     }
1889     if (ntets == 0) {
1890       // Find if it is the keyword "Tetrahedra"
1891       corners = 0;
1892       str = strstr(bufferp, "Tetrahedra");
1893       if (!str) str = strstr(bufferp, "tetrahedra");
1894       if (!str) str = strstr(bufferp, "TETRAHEDRA");
1895       if (str) {
1896         corners = 4;
1897       }
1898       if (corners == 4) {
1899         // Read the number of tetrahedra
1900         bufferp = findnextnumber(str); // Skip field "Tetrahedra".
1901         if (*bufferp == '\0') {
1902           // Read a non-empty line.
1903           bufferp = readline(buffer, fp, &line_count);
1904         }
1905         ntets = strtol(bufferp, &bufferp, 0);
1906         if (ntets > 0) {
1907           // It is a tetrahedral mesh.
1908           numberoftetrahedra = ntets;
1909           numberofcorners = 4;
1910           numberoftetrahedronattributes = 1;
1911           tetrahedronlist = new int[ntets * 4];
1912           tetrahedronattributelist = new REAL[ntets];
1913         }
1914       } // if (corners == 4)
1915       // Read the list of tetrahedra.
1916       for (i = 0; i < numberoftetrahedra; i++) {
1917         plist = &(tetrahedronlist[i * 4]);
1918         bufferp = readline(buffer, fp, &line_count);
1919         if (bufferp == nullptr) {
1920           printf("Unexpected end of file on line %d in file %s\n",
1921                  line_count, infilename);
1922           fclose(fp);
1923           return false;
1924         }
1925         // Read the vertices of the tet.
1926         for (j = 0; j < corners; j++) {
1927           if (*bufferp == '\0') {
1928             printf("Syntax error reading face on line %d in file %s\n",
1929                    line_count, infilename);
1930             fclose(fp);
1931             return false;
1932           }
1933           plist[j] = (int) strtol(bufferp, &bufferp, 0);
1934           // Remember the smallest index.
1935           if (plist[j] < smallestidx) smallestidx = plist[j];
1936           bufferp = findnextnumber(bufferp);
1937         }
1938         // Read the attribute of the tet if it exists.
1939         tetrahedronattributelist[i] = 0;
1940         if (*bufferp != '\0') {
1941           tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
1942         }
1943       } // i
1944     } // Tetrahedra
1945     if (nfaces == 0) {
1946       // Find if it is the keyword "Triangles" or "Quadrilaterals".
1947       corners = 0;
1948       str = strstr(bufferp, "Triangles");
1949       if (!str) str = strstr(bufferp, "triangles");
1950       if (!str) str = strstr(bufferp, "TRIANGLES");
1951       if (str) {
1952         corners = 3;
1953       } else {
1954         str = strstr(bufferp, "Quadrilaterals");
1955         if (!str) str = strstr(bufferp, "quadrilaterals");
1956         if (!str) str = strstr(bufferp, "QUADRILATERALS");
1957         if (str) {
1958           corners = 4;
1959         }
1960       }
1961       if (corners == 3 || corners == 4) {
1962         // Read the number of triangles (or quadrilaterals).
1963         bufferp = findnextnumber(str); // Skip field "Triangles".
1964         if (*bufferp == '\0') {
1965           // Read a non-empty line.
1966           bufferp = readline(buffer, fp, &line_count);
1967         }
1968         nfaces = strtol(bufferp, &bufferp, 0);
1969         // Allocate memory for 'tetgenio'
1970         if (nfaces > 0) {
1971           if (!istetmesh) {
1972             // It is a PLC surface mesh.
1973             if (numberoffacets > 0) {
1974               // facetlist has already been allocated. Enlarge arrays.
1975               // This happens when the surface mesh contains mixed cells.
1976               tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1977               tmpfmlist = new int[numberoffacets + nfaces];
1978               // Copy the data of old arrays into new arrays.
1979               for (i = 0; i < numberoffacets; i++) {
1980                 f = &(tmpflist[i]);
1981                 tetgenio::init(f);
1982                 *f = facetlist[i];
1983                 tmpfmlist[i] = facetmarkerlist[i];
1984               }
1985               // Release old arrays.
1986               delete [] facetlist;
1987               delete [] facetmarkerlist;
1988               // Remember the new arrays.
1989               facetlist = tmpflist;
1990               facetmarkerlist = tmpfmlist;
1991             } else {
1992               // This is the first time to allocate facetlist.
1993               facetlist = new tetgenio::facet[nfaces];
1994               facetmarkerlist = new int[nfaces];
1995             }
1996           } else {
1997             if (corners == 3) {
1998               // It is a surface mesh of a tetrahedral mesh.
1999               numberoftrifaces = nfaces;
2000               trifacelist = new int[nfaces * 3];
2001               trifacemarkerlist = new int[nfaces];
2002             }
2003           }
2004         } // if (nfaces > 0)
2005         // Read the following list of faces.
2006         if (!istetmesh) {
2007           for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
2008             bufferp = readline(buffer, fp, &line_count);
2009             if (bufferp == nullptr) {
2010               printf("Unexpected end of file on line %d in file %s\n",
2011                      line_count, infilename);
2012               fclose(fp);
2013               return false;
2014             }
2015             f = &facetlist[i];
2016             tetgenio::init(f);
2017             // In .mesh format, each facet has one polygon, no hole.
2018             f->numberofpolygons = 1;
2019             f->polygonlist = new tetgenio::polygon[1];
2020             p = &f->polygonlist[0];
2021             tetgenio::init(p);
2022             p->numberofvertices = corners;
2023             // Allocate memory for face vertices
2024             p->vertexlist = new int[p->numberofvertices];
2025             // Read the vertices of the face.
2026             for (j = 0; j < corners; j++) {
2027               if (*bufferp == '\0') {
2028                 printf("Syntax error reading face on line %d in file %s\n",
2029                        line_count, infilename);
2030                 fclose(fp);
2031                 return false;
2032               }
2033               p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
2034               // Remember the smallest index.
2035               if (p->vertexlist[j] < smallestidx) {
2036                 smallestidx = p->vertexlist[j];
2037               }
2038               bufferp = findnextnumber(bufferp);
2039             }
2040             // Read the marker of the face if it exists.
2041             facetmarkerlist[i] = 0;
2042             if (*bufferp != '\0') {
2043               facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2044             }
2045           }
2046           // Have read in a list of triangles/quads.
2047           numberoffacets += nfaces;
2048           nfaces = 0;
2049         } else {
2050           // It is a surface mesh of a tetrahedral mesh.
2051           if (corners == 3) {
2052             for (i = 0; i < numberoftrifaces; i++) {
2053               plist = &(trifacelist[i * 3]);
2054               bufferp = readline(buffer, fp, &line_count);
2055               if (bufferp == nullptr) {
2056                 printf("Unexpected end of file on line %d in file %s\n",
2057                        line_count, infilename);
2058                 fclose(fp);
2059                 return false;
2060               }
2061               // Read the vertices of the face.
2062               for (j = 0; j < corners; j++) {
2063                 if (*bufferp == '\0') {
2064                   printf("Syntax error reading face on line %d in file %s\n",
2065                          line_count, infilename);
2066                   fclose(fp);
2067                   return false;
2068                 }
2069                 plist[j] = (int) strtol(bufferp, &bufferp, 0);
2070                 // Remember the smallest index.
2071                 if (plist[j] < smallestidx) {
2072                   smallestidx = plist[j];
2073                 }
2074                 bufferp = findnextnumber(bufferp);
2075               }
2076               // Read the marker of the face if it exists.
2077               trifacemarkerlist[i] = 0;
2078               if (*bufferp != '\0') {
2079                 trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2080               }
2081             } // i
2082           } // if (corners == 3)
2083         } // if (b->refine)
2084       } // if (corners == 3 || corners == 4)
2085     }
2086   }
2087 
2088   // Close file
2089   fclose(fp);
2090 
2091   // Decide the firstnumber of the index.
2092   if (smallestidx == 0) {
2093     firstnumber = 0;
2094   } else if (smallestidx == 1) {
2095     firstnumber = 1;
2096   } else {
2097     printf("A wrong smallest index (%d) was detected in file %s\n",
2098            smallestidx, infilename);
2099     return false;
2100   }
2101 
2102   return true;
2103 }
2104 
2105 ///////////////////////////////////////////////////////////////////////////////
2106 //                                                                           //
2107 // load_vtk()    Load VTK surface mesh from file (.vtk ascii or binary).     //
2108 //                                                                           //
2109 // This function is contributed by: Bryn Lloyd, Computer Vision Laborator,   //
2110 // ETH, Zuerich. May 7, 2007.                                                //
2111 //                                                                           //
2112 ///////////////////////////////////////////////////////////////////////////////
2113 
2114 // Two inline functions used in read/write VTK files.
2115 
swapBytes(unsigned char * var,int size)2116 void swapBytes(unsigned char* var, int size)
2117 {
2118   int i = 0;
2119   int j = size - 1;
2120   char c;
2121 
2122   while (i < j) {
2123     c = var[i]; var[i] = var[j]; var[j] = c;
2124     i++, j--;
2125   }
2126 }
2127 
testIsBigEndian()2128 bool testIsBigEndian()
2129 {
2130   short word = 0x4321;
2131   if((*(char *)& word) != 0x21)
2132     return true;
2133   else
2134     return false;
2135 }
2136 
2137 
load_vtk(char * filebasename)2138 bool tetgenio::load_vtk(char* filebasename)
2139 {
2140   FILE *fp;
2141   tetgenio::facet *f;
2142   tetgenio::polygon *p;
2143   char infilename[FILENAMESIZE];
2144   char line[INPUTLINESIZE];
2145   char mode[128], id[256], fmt[64];
2146   char *bufferp;
2147   double *coord;
2148   float _x, _y, _z;
2149   int nverts = 0;
2150   int nfaces = 0;
2151   int line_count = 0;
2152   int dummy;
2153   int id1, id2, id3;
2154   int nn = -1;
2155   int nn_old = -1;
2156   int i, j;
2157   bool ImALittleEndian = !testIsBigEndian();
2158 
2159   int smallestidx = 0;
2160 
2161   strncpy(infilename, filebasename, FILENAMESIZE - 1);
2162   infilename[FILENAMESIZE - 1] = '\0';
2163   if (infilename[0] == '\0') {
2164     printf("Error:  No filename.\n");
2165     return false;
2166   }
2167   if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
2168     strcat(infilename, ".vtk");
2169   }
2170   if (!(fp = fopen(infilename, "r"))) {
2171     printf("Error:  Unable to open file %s\n", infilename);
2172     return false;
2173   }
2174   printf("Opening %s.\n", infilename);
2175 
2176   // Default uses the index starts from '0'.
2177   firstnumber = 0;
2178   strcpy(mode, "BINARY");
2179 
2180   while((bufferp = readline(line, fp, &line_count)) != nullptr) {
2181     if(strlen(line) == 0) continue;
2182     //swallow lines beginning with a comment sign or white space
2183     if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
2184        line[0] == 32) continue;
2185 
2186     sscanf(line, "%s", id);
2187     if(!strcmp(id, "ASCII")) {
2188       strcpy(mode, "ASCII");
2189     }
2190 
2191     if(!strcmp(id, "POINTS")) {
2192       sscanf(line, "%s %d %s", id, &nverts, fmt);
2193       if (nverts > 0) {
2194         numberofpoints = nverts;
2195         pointlist = new REAL[nverts * 3];
2196         smallestidx = nverts + 1;
2197       }
2198 
2199       if(!strcmp(mode, "BINARY")) {
2200         for(i = 0; i < nverts; i++) {
2201           coord = &pointlist[i * 3];
2202           if(!strcmp(fmt, "double")) {
2203             fread((char*)(&(coord[0])), sizeof(double), 1, fp);
2204             fread((char*)(&(coord[1])), sizeof(double), 1, fp);
2205             fread((char*)(&(coord[2])), sizeof(double), 1, fp);
2206             if(ImALittleEndian){
2207               swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
2208               swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
2209               swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
2210             }
2211           } else if(!strcmp(fmt, "float")) {
2212             fread((char*)(&_x), sizeof(float), 1, fp);
2213             fread((char*)(&_y), sizeof(float), 1, fp);
2214             fread((char*)(&_z), sizeof(float), 1, fp);
2215             if(ImALittleEndian){
2216               swapBytes((unsigned char *) &_x, sizeof(_x));
2217               swapBytes((unsigned char *) &_y, sizeof(_y));
2218               swapBytes((unsigned char *) &_z, sizeof(_z));
2219             }
2220             coord[0] = double(_x);
2221             coord[1] = double(_y);
2222             coord[2] = double(_z);
2223           } else {
2224             printf("Error: Only float or double formats are supported!\n");
2225             return false;
2226           }
2227         }
2228       } else if(!strcmp(mode, "ASCII")) {
2229         for(i = 0; i < nverts; i++){
2230           bufferp = readline(line, fp, &line_count);
2231           if (bufferp == nullptr) {
2232             printf("Unexpected end of file on line %d in file %s\n",
2233                    line_count, infilename);
2234             fclose(fp);
2235             return false;
2236           }
2237           // Read vertex coordinates
2238           coord = &pointlist[i * 3];
2239           for (j = 0; j < 3; j++) {
2240             if (*bufferp == '\0') {
2241               printf("Syntax error reading vertex coords on line");
2242               printf(" %d in file %s\n", line_count, infilename);
2243               fclose(fp);
2244               return false;
2245             }
2246             coord[j] = (REAL) strtod(bufferp, &bufferp);
2247             bufferp = findnextnumber(bufferp);
2248           }
2249         }
2250       }
2251       continue;
2252     }
2253 
2254     if(!strcmp(id, "POLYGONS")) {
2255       sscanf(line, "%s %d  %d", id, &nfaces, &dummy);
2256       if (nfaces > 0) {
2257         numberoffacets = nfaces;
2258         facetlist = new tetgenio::facet[nfaces];
2259       }
2260 
2261       if(!strcmp(mode, "BINARY")) {
2262         for(i = 0; i < nfaces; i++){
2263           fread((char*)(&nn), sizeof(int), 1, fp);
2264           if(ImALittleEndian){
2265             swapBytes((unsigned char *) &nn, sizeof(nn));
2266           }
2267           if (i == 0)
2268             nn_old = nn;
2269           if (nn != nn_old) {
2270             printf("Error:  No mixed cells are allowed.\n");
2271             return false;
2272           }
2273 
2274           if(nn == 3){
2275             fread((char*)(&id1), sizeof(int), 1, fp);
2276             fread((char*)(&id2), sizeof(int), 1, fp);
2277             fread((char*)(&id3), sizeof(int), 1, fp);
2278             if(ImALittleEndian){
2279               swapBytes((unsigned char *) &id1, sizeof(id1));
2280               swapBytes((unsigned char *) &id2, sizeof(id2));
2281               swapBytes((unsigned char *) &id3, sizeof(id3));
2282             }
2283             f = &facetlist[i];
2284             init(f);
2285             // In .off format, each facet has one polygon, no hole.
2286             f->numberofpolygons = 1;
2287             f->polygonlist = new tetgenio::polygon[1];
2288             p = &f->polygonlist[0];
2289             init(p);
2290             // Set number of vertices
2291             p->numberofvertices = 3;
2292             // Allocate memory for face vertices
2293             p->vertexlist = new int[p->numberofvertices];
2294             p->vertexlist[0] = id1;
2295             p->vertexlist[1] = id2;
2296             p->vertexlist[2] = id3;
2297             // Detect the smallest index.
2298             for (j = 0; j < 3; j++) {
2299               if (p->vertexlist[j] < smallestidx) {
2300                 smallestidx = p->vertexlist[j];
2301               }
2302             }
2303           } else {
2304             printf("Error: Only triangles are supported\n");
2305             return false;
2306           }
2307         }
2308       } else if(!strcmp(mode, "ASCII")) {
2309         for(i = 0; i < nfaces; i++) {
2310           bufferp = readline(line, fp, &line_count);
2311           nn = (int) strtol(bufferp, &bufferp, 0);
2312           if (i == 0)
2313             nn_old = nn;
2314           if (nn != nn_old) {
2315             printf("Error:  No mixed cells are allowed.\n");
2316             return false;
2317           }
2318 
2319           if (nn == 3) {
2320             bufferp = findnextnumber(bufferp); // Skip the first field.
2321             id1 = (int) strtol(bufferp, &bufferp, 0);
2322             bufferp = findnextnumber(bufferp);
2323             id2 = (int) strtol(bufferp, &bufferp, 0);
2324             bufferp = findnextnumber(bufferp);
2325             id3 = (int) strtol(bufferp, &bufferp, 0);
2326             f = &facetlist[i];
2327             init(f);
2328             // In .off format, each facet has one polygon, no hole.
2329             f->numberofpolygons = 1;
2330             f->polygonlist = new tetgenio::polygon[1];
2331             p = &f->polygonlist[0];
2332             init(p);
2333             // Set number of vertices
2334             p->numberofvertices = 3;
2335             // Allocate memory for face vertices
2336             p->vertexlist = new int[p->numberofvertices];
2337             p->vertexlist[0] = id1;
2338             p->vertexlist[1] = id2;
2339             p->vertexlist[2] = id3;
2340             // Detect the smallest index.
2341             for (j = 0; j < 3; j++) {
2342               if (p->vertexlist[j] < smallestidx) {
2343                 smallestidx = p->vertexlist[j];
2344               }
2345             }
2346           } else {
2347             printf("Error:  Only triangles are supported.\n");
2348             return false;
2349           }
2350         }
2351       }
2352 
2353       fclose(fp);
2354 
2355       // Decide the firstnumber of the index.
2356       if (smallestidx == 0) {
2357         firstnumber = 0;
2358       } else if (smallestidx == 1) {
2359         firstnumber = 1;
2360       } else {
2361         printf("A wrong smallest index (%d) was detected in file %s\n",
2362                smallestidx, infilename);
2363         return false;
2364       }
2365 
2366       return true;
2367     }
2368 
2369     if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
2370       printf("Warning:  load_vtk(): cannot read formats LINES, CELLS.\n");
2371     }
2372   } // while ()
2373 
2374   return true;
2375 }
2376 
2377 ///////////////////////////////////////////////////////////////////////////////
2378 //                                                                           //
2379 // load_plc()    Load a piecewise linear complex from file(s).               //
2380 //                                                                           //
2381 ///////////////////////////////////////////////////////////////////////////////
2382 
load_plc(char * filebasename,int object)2383 bool tetgenio::load_plc(char* filebasename, int object)
2384 {
2385   bool success;
2386 
2387   if (object == (int) tetgenbehavior::NODES) {
2388     success = load_node(filebasename);
2389   } else if (object == (int) tetgenbehavior::POLY) {
2390     success = load_poly(filebasename);
2391   } else if (object == (int) tetgenbehavior::OFF) {
2392     success = load_off(filebasename);
2393   } else if (object == (int) tetgenbehavior::PLY) {
2394     success = load_ply(filebasename);
2395   } else if (object == (int) tetgenbehavior::STL) {
2396     success = load_stl(filebasename);
2397   } else if (object == (int) tetgenbehavior::MEDIT) {
2398     success = load_medit(filebasename, 0);
2399   } else if (object == (int) tetgenbehavior::VTK) {
2400     success = load_vtk(filebasename);
2401   } else {
2402     success = load_poly(filebasename);
2403   }
2404 
2405   if (success) {
2406     // Try to load the following files (.edge, .var, .mtr).
2407     load_edge(filebasename);
2408     load_var(filebasename);
2409     load_mtr(filebasename);
2410   }
2411 
2412   return success;
2413 }
2414 
2415 ///////////////////////////////////////////////////////////////////////////////
2416 //                                                                           //
2417 // load_mesh()    Load a tetrahedral mesh from file(s).                      //
2418 //                                                                           //
2419 ///////////////////////////////////////////////////////////////////////////////
2420 
load_tetmesh(char * filebasename,int object)2421 bool tetgenio::load_tetmesh(char* filebasename, int object)
2422 {
2423   bool success;
2424 
2425   if (object == (int) tetgenbehavior::MEDIT) {
2426     success = load_medit(filebasename, 1);
2427   } else {
2428     success = load_node(filebasename);
2429     if (success) {
2430       success = load_tet(filebasename);
2431     }
2432     if (success) {
2433       // Try to load the following files (.face, .edge, .vol).
2434       load_face(filebasename);
2435       load_edge(filebasename);
2436       load_vol(filebasename);
2437     }
2438   }
2439 
2440   if (success) {
2441     // Try to load the following files (.var, .mtr).
2442     load_var(filebasename);
2443     load_mtr(filebasename);
2444   }
2445 
2446   return success;
2447 }
2448 
2449 ///////////////////////////////////////////////////////////////////////////////
2450 //                                                                           //
2451 // save_nodes()    Save points to a .node file.                              //
2452 //                                                                           //
2453 ///////////////////////////////////////////////////////////////////////////////
2454 
save_nodes(char * filebasename)2455 void tetgenio::save_nodes(char* filebasename)
2456 {
2457   FILE *fout;
2458   char outnodefilename[FILENAMESIZE];
2459   char outmtrfilename[FILENAMESIZE];
2460   int i, j;
2461 
2462   sprintf(outnodefilename, "%s.node", filebasename);
2463   printf("Saving nodes to %s\n", outnodefilename);
2464   fout = fopen(outnodefilename, "w");
2465   fprintf(fout, "%d  %d  %d  %d\n", numberofpoints, mesh_dim,
2466           numberofpointattributes, pointmarkerlist != nullptr ? 1 : 0);
2467   for (i = 0; i < numberofpoints; i++) {
2468     if (mesh_dim == 2) {
2469       fprintf(fout, "%d  %.16g  %.16g", i + firstnumber, pointlist[i * 3],
2470               pointlist[i * 3 + 1]);
2471     } else {
2472       fprintf(fout, "%d  %.16g  %.16g  %.16g", i + firstnumber,
2473               pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2474     }
2475     for (j = 0; j < numberofpointattributes; j++) {
2476       fprintf(fout, "  %.16g",
2477               pointattributelist[i * numberofpointattributes + j]);
2478     }
2479     if (pointmarkerlist != nullptr) {
2480       fprintf(fout, "  %d", pointmarkerlist[i]);
2481     }
2482     fprintf(fout, "\n");
2483   }
2484   fclose(fout);
2485 
2486   // If the point metrics exist, output them to a .mtr file.
2487   if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) nullptr)) {
2488     sprintf(outmtrfilename, "%s.mtr", filebasename);
2489     printf("Saving metrics to %s\n", outmtrfilename);
2490     fout = fopen(outmtrfilename, "w");
2491     fprintf(fout, "%d  %d\n", numberofpoints, numberofpointmtrs);
2492     for (i = 0; i < numberofpoints; i++) {
2493       for (j = 0; j < numberofpointmtrs; j++) {
2494         fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2495       }
2496       fprintf(fout, "\n");
2497     }
2498     fclose(fout);
2499   }
2500 }
2501 
2502 ///////////////////////////////////////////////////////////////////////////////
2503 //                                                                           //
2504 // save_elements()    Save elements to a .ele file.                          //
2505 //                                                                           //
2506 ///////////////////////////////////////////////////////////////////////////////
2507 
save_elements(char * filebasename)2508 void tetgenio::save_elements(char* filebasename)
2509 {
2510   FILE *fout;
2511   char outelefilename[FILENAMESIZE];
2512   int i, j;
2513 
2514   sprintf(outelefilename, "%s.ele", filebasename);
2515   printf("Saving elements to %s\n", outelefilename);
2516   fout = fopen(outelefilename, "w");
2517   if (mesh_dim == 3) {
2518     fprintf(fout, "%d  %d  %d\n", numberoftetrahedra, numberofcorners,
2519             numberoftetrahedronattributes);
2520     for (i = 0; i < numberoftetrahedra; i++) {
2521       fprintf(fout, "%d", i + firstnumber);
2522       for (j = 0; j < numberofcorners; j++) {
2523         fprintf(fout, "  %5d", tetrahedronlist[i * numberofcorners + j]);
2524       }
2525       for (j = 0; j < numberoftetrahedronattributes; j++) {
2526         fprintf(fout, "  %g",
2527           tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2528       }
2529       fprintf(fout, "\n");
2530     }
2531   } else {
2532     // Save a two-dimensional mesh.
2533     fprintf(fout, "%d  %d  %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
2534     for (i = 0; i < numberoftrifaces; i++) {
2535       fprintf(fout, "%d", i + firstnumber);
2536       for (j = 0; j < 3; j++) {
2537         fprintf(fout, "  %5d", trifacelist[i * 3 + j]);
2538       }
2539       if (trifacemarkerlist != nullptr) {
2540         fprintf(fout, "  %d", trifacemarkerlist[i]);
2541       }
2542       fprintf(fout, "\n");
2543     }
2544   }
2545 
2546   fclose(fout);
2547 }
2548 
2549 ///////////////////////////////////////////////////////////////////////////////
2550 //                                                                           //
2551 // save_faces()    Save faces to a .face file.                               //
2552 //                                                                           //
2553 ///////////////////////////////////////////////////////////////////////////////
2554 
save_faces(char * filebasename)2555 void tetgenio::save_faces(char* filebasename)
2556 {
2557   FILE *fout;
2558   char outfacefilename[FILENAMESIZE];
2559   int i;
2560 
2561   sprintf(outfacefilename, "%s.face", filebasename);
2562   printf("Saving faces to %s\n", outfacefilename);
2563   fout = fopen(outfacefilename, "w");
2564   fprintf(fout, "%d  %d\n", numberoftrifaces,
2565           trifacemarkerlist != nullptr ? 1 : 0);
2566   for (i = 0; i < numberoftrifaces; i++) {
2567     fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber, trifacelist[i * 3],
2568             trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2569     if (trifacemarkerlist != nullptr) {
2570       fprintf(fout, "  %d", trifacemarkerlist[i]);
2571     }
2572     fprintf(fout, "\n");
2573   }
2574 
2575   fclose(fout);
2576 }
2577 
2578 ///////////////////////////////////////////////////////////////////////////////
2579 //                                                                           //
2580 // save_edges()    Save egdes to a .edge file.                               //
2581 //                                                                           //
2582 ///////////////////////////////////////////////////////////////////////////////
2583 
save_edges(char * filebasename)2584 void tetgenio::save_edges(char* filebasename)
2585 {
2586   FILE *fout;
2587   char outedgefilename[FILENAMESIZE];
2588   int i;
2589 
2590   sprintf(outedgefilename, "%s.edge", filebasename);
2591   printf("Saving edges to %s\n", outedgefilename);
2592   fout = fopen(outedgefilename, "w");
2593   fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != nullptr ? 1 : 0);
2594   for (i = 0; i < numberofedges; i++) {
2595     fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
2596             edgelist[i * 2 + 1]);
2597     if (edgemarkerlist != nullptr) {
2598       fprintf(fout, "  %d", edgemarkerlist[i]);
2599     }
2600     fprintf(fout, "\n");
2601   }
2602 
2603   fclose(fout);
2604 }
2605 
2606 ///////////////////////////////////////////////////////////////////////////////
2607 //                                                                           //
2608 // save_neighbors()    Save egdes to a .neigh file.                          //
2609 //                                                                           //
2610 ///////////////////////////////////////////////////////////////////////////////
2611 
save_neighbors(char * filebasename)2612 void tetgenio::save_neighbors(char* filebasename)
2613 {
2614   FILE *fout;
2615   char outneighborfilename[FILENAMESIZE];
2616   int i;
2617 
2618   sprintf(outneighborfilename, "%s.neigh", filebasename);
2619   printf("Saving neighbors to %s\n", outneighborfilename);
2620   fout = fopen(outneighborfilename, "w");
2621   fprintf(fout, "%d  %d\n", numberoftetrahedra, mesh_dim + 1);
2622   for (i = 0; i < numberoftetrahedra; i++) {
2623     if (mesh_dim == 2) {
2624       fprintf(fout, "%d  %5d  %5d  %5d", i + firstnumber,  neighborlist[i * 3],
2625               neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2626     } else {
2627       fprintf(fout, "%d  %5d  %5d  %5d  %5d", i + firstnumber,
2628               neighborlist[i * 4], neighborlist[i * 4 + 1],
2629               neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2630     }
2631     fprintf(fout, "\n");
2632   }
2633 
2634   fclose(fout);
2635 }
2636 
2637 ///////////////////////////////////////////////////////////////////////////////
2638 //                                                                           //
2639 // save_poly()    Save segments or facets to a .poly file.                   //
2640 //                                                                           //
2641 // It only save the facets, holes and regions. No .node file is saved.       //
2642 //                                                                           //
2643 ///////////////////////////////////////////////////////////////////////////////
2644 
save_poly(char * filebasename)2645 void tetgenio::save_poly(char* filebasename)
2646 {
2647   FILE *fout;
2648   facet *f;
2649   polygon *p;
2650   char outpolyfilename[FILENAMESIZE];
2651   int i, j, k;
2652 
2653   sprintf(outpolyfilename, "%s.poly", filebasename);
2654   printf("Saving poly to %s\n", outpolyfilename);
2655   fout = fopen(outpolyfilename, "w");
2656 
2657   // The zero indicates that the vertices are in a separate .node file.
2658   //   Followed by number of dimensions, number of vertex attributes,
2659   //   and number of boundary markers (zero or one).
2660   fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
2661           pointmarkerlist != nullptr ? 1 : 0);
2662 
2663   // Save segments or facets.
2664   if (mesh_dim == 2) {
2665     // Number of segments, number of boundary markers (zero or one).
2666     fprintf(fout, "%d  %d\n", numberofedges, edgemarkerlist != nullptr ? 1 : 0);
2667     for (i = 0; i < numberofedges; i++) {
2668       fprintf(fout, "%d  %4d  %4d", i + firstnumber, edgelist[i * 2],
2669               edgelist[i * 2 + 1]);
2670       if (edgemarkerlist != nullptr) {
2671         fprintf(fout, "  %d", edgemarkerlist[i]);
2672       }
2673       fprintf(fout, "\n");
2674     }
2675   } else {
2676     // Number of facets, number of boundary markers (zero or one).
2677     fprintf(fout, "%d  %d\n", numberoffacets, facetmarkerlist != nullptr ? 1 : 0);
2678     for (i = 0; i < numberoffacets; i++) {
2679       f = &(facetlist[i]);
2680       fprintf(fout, "%d  %d  %d  # %d\n", f->numberofpolygons,f->numberofholes,
2681             facetmarkerlist != nullptr ? facetmarkerlist[i] : 0, i + firstnumber);
2682       // Output polygons of this facet.
2683       for (j = 0; j < f->numberofpolygons; j++) {
2684         p = &(f->polygonlist[j]);
2685         fprintf(fout, "%d  ", p->numberofvertices);
2686         for (k = 0; k < p->numberofvertices; k++) {
2687           if (((k + 1) % 10) == 0) {
2688             fprintf(fout, "\n  ");
2689           }
2690           fprintf(fout, "  %d", p->vertexlist[k]);
2691         }
2692         fprintf(fout, "\n");
2693       }
2694       // Output holes of this facet.
2695       for (j = 0; j < f->numberofholes; j++) {
2696         fprintf(fout, "%d  %.12g  %.12g  %.12g\n", j + firstnumber,
2697            f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2698       }
2699     }
2700   }
2701 
2702   // Save holes.
2703   fprintf(fout, "%d\n", numberofholes);
2704   for (i = 0; i < numberofholes; i++) {
2705     // Output x, y coordinates.
2706     fprintf(fout, "%d  %.12g  %.12g", i + firstnumber, holelist[i * mesh_dim],
2707             holelist[i * mesh_dim + 1]);
2708     if (mesh_dim == 3) {
2709       // Output z coordinate.
2710       fprintf(fout, "  %.12g", holelist[i * mesh_dim + 2]);
2711     }
2712     fprintf(fout, "\n");
2713   }
2714 
2715   // Save regions.
2716   fprintf(fout, "%d\n", numberofregions);
2717   for (i = 0; i < numberofregions; i++) {
2718     if (mesh_dim == 2) {
2719       // Output the index, x, y coordinates, attribute (region number)
2720       //   and maximum area constraint (maybe -1).
2721       fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
2722               regionlist[i * 4], regionlist[i * 4 + 1],
2723               regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2724     } else {
2725       // Output the index, x, y, z coordinates, attribute (region number)
2726       //   and maximum volume constraint (maybe -1).
2727       fprintf(fout, "%d  %.12g  %.12g  %.12g  %.12g  %.12g\n", i + firstnumber,
2728               regionlist[i * 5], regionlist[i * 5 + 1],
2729               regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2730               regionlist[i * 5 + 4]);
2731     }
2732   }
2733 
2734   fclose(fout);
2735 }
2736 
2737 ///////////////////////////////////////////////////////////////////////////////
2738 //                                                                           //
2739 // save_faces2smesh()    Save triangular faces to a .smesh file.             //
2740 //                                                                           //
2741 // It only save the facets. No holes and regions. No .node file.             //
2742 //                                                                           //
2743 ///////////////////////////////////////////////////////////////////////////////
2744 
save_faces2smesh(char * filebasename)2745 void tetgenio::save_faces2smesh(char* filebasename)
2746 {
2747   FILE *fout;
2748   char outsmeshfilename[FILENAMESIZE];
2749   int i, j;
2750 
2751   sprintf(outsmeshfilename, "%s.smesh", filebasename);
2752   printf("Saving faces to %s\n", outsmeshfilename);
2753   fout = fopen(outsmeshfilename, "w");
2754 
2755   // The zero indicates that the vertices are in a separate .node file.
2756   //   Followed by number of dimensions, number of vertex attributes,
2757   //   and number of boundary markers (zero or one).
2758   fprintf(fout, "%d  %d  %d  %d\n", 0, mesh_dim, numberofpointattributes,
2759           pointmarkerlist != nullptr ? 1 : 0);
2760 
2761   // Number of facets, number of boundary markers (zero or one).
2762   fprintf(fout, "%d  %d\n", numberoftrifaces,
2763           trifacemarkerlist != nullptr ? 1 : 0);
2764 
2765   // Output triangular facets.
2766   for (i = 0; i < numberoftrifaces; i++) {
2767     j = i * 3;
2768     fprintf(fout, "3  %d %d %d", trifacelist[j], trifacelist[j + 1],
2769             trifacelist[j + 2]);
2770     if (trifacemarkerlist != nullptr) {
2771       fprintf(fout, "  %d", trifacemarkerlist[i]);
2772     }
2773     fprintf(fout, "\n");
2774   }
2775 
2776   // No holes and regions.
2777   fprintf(fout, "0\n");
2778   fprintf(fout, "0\n");
2779 
2780   fclose(fout);
2781 }
2782 
2783 ///////////////////////////////////////////////////////////////////////////////
2784 //                                                                           //
2785 // readline()   Read a nonempty line from a file.                            //
2786 //                                                                           //
2787 // A line is considered "nonempty" if it contains something more than white  //
2788 // spaces.  If a line is considered empty, it will be dropped and the next   //
2789 // line will be read, this process ends until reaching the end-of-file or a  //
2790 // non-empty line.  Return nullptr if it is the end-of-file, otherwise, return  //
2791 // a pointer to the first non-whitespace character of the line.              //
2792 //                                                                           //
2793 ///////////////////////////////////////////////////////////////////////////////
2794 
readline(char * string,FILE * infile,int * linenumber)2795 char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2796 {
2797   char *result;
2798 
2799   // Search for a non-empty line.
2800   do {
2801     result = fgets(string, INPUTLINESIZE - 1, infile);
2802     if (linenumber) (*linenumber)++;
2803     if (result == (char *) nullptr) {
2804       return (char *) nullptr;
2805     }
2806     // Skip white spaces.
2807     while ((*result == ' ') || (*result == '\t')) result++;
2808     // If it's end of line, read another line and try again.
2809   } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
2810   return result;
2811 }
2812 
2813 ///////////////////////////////////////////////////////////////////////////////
2814 //                                                                           //
2815 // findnextfield()   Find the next field of a string.                        //
2816 //                                                                           //
2817 // Jumps past the current field by searching for whitespace or a comma, then //
2818 // jumps past the whitespace or the comma to find the next field.            //
2819 //                                                                           //
2820 ///////////////////////////////////////////////////////////////////////////////
2821 
findnextfield(char * string)2822 char* tetgenio::findnextfield(char *string)
2823 {
2824   char *result;
2825 
2826   result = string;
2827   // Skip the current field.  Stop upon reaching whitespace or a comma.
2828   while ((*result != '\0') && (*result != ' ') &&  (*result != '\t') &&
2829          (*result != ',') && (*result != ';')) {
2830     result++;
2831   }
2832   // Now skip the whitespace or the comma, stop at anything else that looks
2833   //   like a character, or the end of a line.
2834   while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2835          (*result == ';')) {
2836     result++;
2837   }
2838   return result;
2839 }
2840 
2841 ///////////////////////////////////////////////////////////////////////////////
2842 //                                                                           //
2843 // readnumberline()   Read a nonempty number line from a file.               //
2844 //                                                                           //
2845 // A line is considered "nonempty" if it contains something that looks like  //
2846 // a number.  Comments (prefaced by `#') are ignored.                        //
2847 //                                                                           //
2848 ///////////////////////////////////////////////////////////////////////////////
2849 
readnumberline(char * string,FILE * infile,char * infilename)2850 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2851 {
2852   char *result;
2853 
2854   // Search for something that looks like a number.
2855   do {
2856     result = fgets(string, INPUTLINESIZE, infile);
2857     if (result == (char *) nullptr) {
2858       return result;
2859     }
2860     // Skip anything that doesn't look like a number, a comment,
2861     //   or the end of a line.
2862     while ((*result != '\0') && (*result != '#')
2863            && (*result != '.') && (*result != '+') && (*result != '-')
2864            && ((*result < '0') || (*result > '9'))) {
2865       result++;
2866     }
2867     // If it's a comment or end of line, read another line and try again.
2868   } while ((*result == '#') || (*result == '\0'));
2869   return result;
2870 }
2871 
2872 ///////////////////////////////////////////////////////////////////////////////
2873 //                                                                           //
2874 // findnextnumber()   Find the next field of a number string.                //
2875 //                                                                           //
2876 // Jumps past the current field by searching for whitespace or a comma, then //
2877 // jumps past the whitespace or the comma to find the next field that looks  //
2878 // like a number.                                                            //
2879 //                                                                           //
2880 ///////////////////////////////////////////////////////////////////////////////
2881 
findnextnumber(char * string)2882 char* tetgenio::findnextnumber(char *string)
2883 {
2884   char *result;
2885 
2886   result = string;
2887   // Skip the current field.  Stop upon reaching whitespace or a comma.
2888   while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2889          (*result != '\t') && (*result != ',')) {
2890     result++;
2891   }
2892   // Now skip the whitespace and anything else that doesn't look like a
2893   //   number, a comment, or the end of a line.
2894   while ((*result != '\0') && (*result != '#')
2895          && (*result != '.') && (*result != '+') && (*result != '-')
2896          && ((*result < '0') || (*result > '9'))) {
2897     result++;
2898   }
2899   // Check for a comment (prefixed with `#').
2900   if (*result == '#') {
2901     *result = '\0';
2902   }
2903   return result;
2904 }
2905 
2906 ////                                                                       ////
2907 ////                                                                       ////
2908 //// io_cxx ///////////////////////////////////////////////////////////////////
2909 
2910 //// behavior_cxx /////////////////////////////////////////////////////////////
2911 ////                                                                       ////
2912 ////                                                                       ////
2913 
2914 ///////////////////////////////////////////////////////////////////////////////
2915 //                                                                           //
2916 // syntax()    Print list of command line switches.                          //
2917 //                                                                           //
2918 ///////////////////////////////////////////////////////////////////////////////
2919 
syntax()2920 void tetgenbehavior::syntax()
2921 {
2922   printf("  tetgen [-pYq_Aa_mriO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
2923   printf("    -p  Tetrahedralizes a piecewise linear complex (PLC).\n");
2924   printf("    -Y  Preserves the input surface mesh (does not modify it).\n");
2925   printf("    -q  Refines mesh (to improve mesh quality).\n");
2926   printf("    -A  Assigns attributes to tetrahedra in different regions.\n");
2927   printf("    -a  Applies a maximum tetrahedron volume constraint.\n");
2928   printf("    -m  Applies a mesh sizing function.\n");
2929   printf("    -r  Reconstructs a previously generated mesh.\n");
2930   printf("    -i  Inserts a list of additional points.\n");
2931   printf("    -O  Specifies the level of mesh optimization.\n");
2932   printf("    -S  Specifies maximum number of added points.\n");
2933   printf("    -T  Sets a tolerance for coplanar test (default 1e-8).\n");
2934   printf("    -X  Suppresses use of exact arithmetic.\n");
2935   printf("    -M  No merge of coplanar facets or very close vertices.\n");
2936   printf("    -w  Generates weighted Delaunay (regular) triangulation.\n");
2937   printf("    -c  Retains the convex hull of the PLC.\n");
2938   printf("    -d  Detects self-intersections of facets of the PLC.\n");
2939   printf("    -z  Numbers all output items starting from zero.\n");
2940   printf("    -f  Outputs all faces to .face file.\n");
2941   printf("    -e  Outputs all edges to .edge file.\n");
2942   printf("    -n  Outputs tetrahedra neighbors to .neigh file.\n");
2943   printf("    -v  Outputs Voronoi diagram to files.\n");
2944   printf("    -g  Outputs mesh to .mesh file for viewing by Medit.\n");
2945   printf("    -k  Outputs mesh to .vtk file for viewing by Paraview.\n");
2946   printf("    -J  No jettison of unused vertices from output .node file.\n");
2947   printf("    -B  Suppresses output of boundary information.\n");
2948   printf("    -N  Suppresses output of .node file.\n");
2949   printf("    -E  Suppresses output of .ele file.\n");
2950   printf("    -F  Suppresses output of .face and .edge file.\n");
2951   printf("    -I  Suppresses mesh iteration numbers.\n");
2952   printf("    -C  Checks the consistency of the final mesh.\n");
2953   printf("    -Q  Quiet:  No terminal output except errors.\n");
2954   printf("    -V  Verbose:  Detailed information, more terminal output.\n");
2955   printf("    -h  Help:  A brief instruction for using TetGen.\n");
2956 }
2957 
2958 ///////////////////////////////////////////////////////////////////////////////
2959 //                                                                           //
2960 // usage()    Print a brief instruction for using TetGen.                    //
2961 //                                                                           //
2962 ///////////////////////////////////////////////////////////////////////////////
2963 
usage()2964 void tetgenbehavior::usage()
2965 {
2966   printf("TetGen\n");
2967   printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
2968   printf("Triangulator\n");
2969   printf("Version 1.5\n");
2970   printf("(June 21, 2013)\n");
2971   printf("\n");
2972   printf("Copyright (C) 2002 - 2013\n");
2973   printf("Hang Si\n");
2974   printf("Mohrenstr. 39, 10117 Berlin, Germany\n");
2975   printf("si@wias-berlin.de\n");
2976   printf("\n");
2977   printf("What Can TetGen Do?\n");
2978   printf("\n");
2979   printf("  TetGen generates Delaunay tetrahedralizations, constrained\n");
2980   printf("  Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
2981   printf("\n");
2982   printf("Command Line Syntax:\n");
2983   printf("\n");
2984   printf("  Below is the basic command line syntax of TetGen with a list of ");
2985   printf("short\n");
2986   printf("  descriptions. Underscores indicate that numbers may optionally\n");
2987   printf("  follow certain switches.  Do not leave any space between a ");
2988   printf("switch\n");
2989   printf("  and its numeric parameter.  \'input_file\' contains input data\n");
2990   printf("  depending on the switches you supplied which may be a ");
2991   printf("  piecewise\n");
2992   printf("  linear complex or a list of nodes.  File formats and detailed\n");
2993   printf("  description of command line switches are found in user's ");
2994   printf("manual.\n");
2995   printf("\n");
2996   syntax();
2997   printf("\n");
2998   printf("Examples of How to Use TetGen:\n");
2999   printf("\n");
3000   printf("  \'tetgen object\' reads vertices from object.node, and writes ");
3001   printf("their\n  Delaunay tetrahedralization to object.1.node, ");
3002   printf("object.1.ele\n  (tetrahedra), and object.1.face");
3003   printf(" (convex hull faces).\n");
3004   printf("\n");
3005   printf("  \'tetgen -p object\' reads a PLC from object.poly or object.");
3006   printf("smesh (and\n  possibly object.node) and writes its constrained ");
3007   printf("Delaunay\n  tetrahedralization to object.1.node, object.1.ele, ");
3008   printf("object.1.face,\n");
3009   printf("  (boundary faces) and object.1.edge (boundary edges).\n");
3010   printf("\n");
3011   printf("  \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
3012   printf("  object.smesh (and possibly object.node), generates a mesh ");
3013   printf("whose\n  tetrahedra have radius-edge ratio smaller than 1.414 and ");
3014   printf("have volume\n  of 0.1 or less, and writes the mesh to ");
3015   printf("object.1.node, object.1.ele,\n  object.1.face, and object.1.edge\n");
3016   printf("\n");
3017   printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3018   terminatetetgen(0);
3019 }
3020 
3021 ///////////////////////////////////////////////////////////////////////////////
3022 //                                                                           //
3023 // parse_commandline()    Read the command line, identify switches, and set  //
3024 //                        up options and file names.                         //
3025 //                                                                           //
3026 // 'argc' and 'argv' are the same parameters passed to the function main()   //
3027 // of a C/C++ program. They together represent the command line user invoked //
3028 // from an environment in which TetGen is running.                           //
3029 //                                                                           //
3030 ///////////////////////////////////////////////////////////////////////////////
3031 
parse_commandline(int argc,char ** argv)3032 bool tetgenbehavior::parse_commandline(int argc, char **argv)
3033 {
3034   int startindex;
3035   int increment;
3036   int meshnumber;
3037   int i, j, k;
3038   char workstring[1024];
3039 
3040   // First determine the input style of the switches.
3041   if (argc == 0) {
3042     startindex = 0;                    // Switches are given without a dash.
3043     argc = 1;                    // For running the following for-loop once.
3044     commandline[0] = '\0';
3045   } else {
3046     startindex = 1;
3047     strcpy(commandline, argv[0]);
3048     strcat(commandline, " ");
3049   }
3050 
3051   for (i = startindex; i < argc; i++) {
3052     // Remember the command line for output.
3053     strcat(commandline, argv[i]);
3054     strcat(commandline, " ");
3055     if (startindex == 1) {
3056       // Is this string a filename?
3057       if (argv[i][0] != '-') {
3058         strncpy(infilename, argv[i], 1024 - 1);
3059         infilename[1024 - 1] = '\0';
3060         continue;
3061       }
3062     }
3063     // Parse the individual switch from the string.
3064     for (j = startindex; argv[i][j] != '\0'; j++) {
3065       if (argv[i][j] == 'p') {
3066         plc = 1;
3067         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3068             (argv[i][j + 1] == '.')) {
3069           k = 0;
3070           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3071                  (argv[i][j + 1] == '.')) {
3072             j++;
3073             workstring[k] = argv[i][j];
3074             k++;
3075           }
3076           workstring[k] = '\0';
3077           facet_ang_tol = (REAL) strtod(workstring, (char **) nullptr);
3078         }
3079       } else if (argv[i][j] == 's') {
3080         psc = 1;
3081       } else if (argv[i][j] == 'Y') {
3082         nobisect = 1;
3083         if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3084           nobisect_param = (argv[i][j + 1] - '0');
3085           j++;
3086         }
3087         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3088           j++;
3089           if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3090             addsteiner_algo = (argv[i][j + 1] - '0');
3091             j++;
3092           }
3093         }
3094       } else if (argv[i][j] == 'r') {
3095         refine = 1;
3096       } else if (argv[i][j] == 'q') {
3097         quality = 1;
3098         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3099             (argv[i][j + 1] == '.')) {
3100           k = 0;
3101           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3102                  (argv[i][j + 1] == '.')) {
3103             j++;
3104             workstring[k] = argv[i][j];
3105             k++;
3106           }
3107           workstring[k] = '\0';
3108           minratio = (REAL) strtod(workstring, (char **) nullptr);
3109         }
3110         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3111           j++;
3112           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3113               (argv[i][j + 1] == '.')) {
3114             k = 0;
3115             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3116                    (argv[i][j + 1] == '.')) {
3117               j++;
3118               workstring[k] = argv[i][j];
3119               k++;
3120             }
3121             workstring[k] = '\0';
3122             mindihedral = (REAL) strtod(workstring, (char **) nullptr);
3123           }
3124         }
3125         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3126           j++;
3127           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3128               (argv[i][j + 1] == '.')) {
3129             k = 0;
3130             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3131                    (argv[i][j + 1] == '.')) {
3132               j++;
3133               workstring[k] = argv[i][j];
3134               k++;
3135             }
3136             workstring[k] = '\0';
3137             optmaxdihedral = (REAL) strtod(workstring, (char **) nullptr);
3138           }
3139         }
3140       } else if (argv[i][j] == 'w') {
3141         weighted = 1;
3142         if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3143           weighted_param = (argv[i][j + 1] - '0');
3144           j++;
3145         }
3146       } else if (argv[i][j] == 'b') {
3147         // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
3148         brio_hilbert = 1;
3149         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3150             (argv[i][j + 1] == '.')) {
3151           k = 0;
3152           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3153                  (argv[i][j + 1] == '.')) {
3154             j++;
3155             workstring[k] = argv[i][j];
3156             k++;
3157           }
3158           workstring[k] = '\0';
3159           brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
3160         }
3161         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3162           j++;
3163           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3164               (argv[i][j + 1] == '.')) {
3165             k = 0;
3166             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3167                    (argv[i][j + 1] == '.')) {
3168               j++;
3169               workstring[k] = argv[i][j];
3170               k++;
3171             }
3172             workstring[k] = '\0';
3173             brio_ratio = (REAL) strtod(workstring, (char **) nullptr);
3174           }
3175         }
3176         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3177           j++;
3178           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3179               (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3180             k = 0;
3181             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3182                    (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3183               j++;
3184               workstring[k] = argv[i][j];
3185               k++;
3186             }
3187             workstring[k] = '\0';
3188             hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
3189           }
3190         }
3191         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3192           j++;
3193           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3194               (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3195             k = 0;
3196             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3197                    (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3198               j++;
3199               workstring[k] = argv[i][j];
3200               k++;
3201             }
3202             workstring[k] = '\0';
3203             hilbert_order = (int)strtod(workstring, (char **) nullptr);
3204           }
3205         }
3206         if (brio_threshold == 0) { // -b0
3207           brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3208         }
3209         if (brio_ratio >= 1.0) { // -b/1
3210           no_sort = 1;
3211           brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3212         }
3213       } else if (argv[i][j] == 'l') {
3214         incrflip = 1;
3215       } else if (argv[i][j] == 'L') {
3216         flipinsert = 1;
3217       } else if (argv[i][j] == 'm') {
3218         metric = 1;
3219       } else if (argv[i][j] == 'a') {
3220         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3221             (argv[i][j + 1] == '.')) {
3222           fixedvolume = 1;
3223           k = 0;
3224           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3225                  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3226                  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3227             j++;
3228             workstring[k] = argv[i][j];
3229             k++;
3230           }
3231           workstring[k] = '\0';
3232           maxvolume = (REAL) strtod(workstring, (char **) nullptr);
3233         } else {
3234           varvolume = 1;
3235         }
3236       } else if (argv[i][j] == 'A') {
3237         regionattrib = 1;
3238       } else if (argv[i][j] == 'D') {
3239         conforming = 1;
3240         if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
3241           reflevel = (argv[i][j + 1] - '1') + 1;
3242           j++;
3243         }
3244       } else if (argv[i][j] == 'i') {
3245         insertaddpoints = 1;
3246       } else if (argv[i][j] == 'd') {
3247         diagnose = 1;
3248       } else if (argv[i][j] == 'c') {
3249         convex = 1;
3250       } else if (argv[i][j] == 'M') {
3251         nomergefacet = 1;
3252         nomergevertex = 1;
3253         if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3254           nomergefacet = (argv[i][j + 1] - '0');
3255           j++;
3256         }
3257         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3258           j++;
3259           if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3260             nomergevertex = (argv[i][j + 1] - '0');
3261             j++;
3262           }
3263         }
3264       } else if (argv[i][j] == 'X') {
3265         if (argv[i][j + 1] == '1') {
3266           nostaticfilter = 1;
3267           j++;
3268         } else {
3269           noexact = 1;
3270         }
3271       } else if (argv[i][j] == 'z') {
3272         zeroindex = 1;
3273       } else if (argv[i][j] == 'f') {
3274         facesout++;
3275       } else if (argv[i][j] == 'e') {
3276         edgesout++;
3277       } else if (argv[i][j] == 'n') {
3278         neighout++;
3279       } else if (argv[i][j] == 'v') {
3280         voroout = 1;
3281       } else if (argv[i][j] == 'g') {
3282         meditview = 1;
3283       } else if (argv[i][j] == 'k') {
3284         vtkview = 1;
3285       } else if (argv[i][j] == 'J') {
3286         nojettison = 1;
3287       } else if (argv[i][j] == 'B') {
3288         nobound = 1;
3289       } else if (argv[i][j] == 'N') {
3290         nonodewritten = 1;
3291       } else if (argv[i][j] == 'E') {
3292         noelewritten = 1;
3293       } else if (argv[i][j] == 'F') {
3294         nofacewritten = 1;
3295       } else if (argv[i][j] == 'I') {
3296         noiterationnum = 1;
3297       } else if (argv[i][j] == 'S') {
3298         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3299             (argv[i][j + 1] == '.')) {
3300           k = 0;
3301           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3302                  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3303                  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3304             j++;
3305             workstring[k] = argv[i][j];
3306             k++;
3307           }
3308           workstring[k] = '\0';
3309           steinerleft = (int) strtol(workstring, (char **) nullptr, 0);
3310         }
3311       } else if (argv[i][j] == 'o') {
3312         if (argv[i][j + 1] == '2') {
3313           order = 2;
3314           j++;
3315         }
3316         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3317           j++;
3318           if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3319               (argv[i][j + 1] == '.')) {
3320             k = 0;
3321             while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3322                    (argv[i][j + 1] == '.')) {
3323               j++;
3324               workstring[k] = argv[i][j];
3325               k++;
3326             }
3327             workstring[k] = '\0';
3328             optmaxdihedral = (REAL) strtod(workstring, (char **) nullptr);
3329           }
3330         }
3331       } else if (argv[i][j] == 'O') {
3332         if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3333           optlevel = (argv[i][j + 1] - '0');
3334           j++;
3335         }
3336         if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3337           j++;
3338           if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
3339             optscheme = (argv[i][j + 1] - '0');
3340             j++;
3341           }
3342         }
3343       } else if (argv[i][j] == 'T') {
3344         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3345             (argv[i][j + 1] == '.')) {
3346           k = 0;
3347           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3348                  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3349                  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3350             j++;
3351             workstring[k] = argv[i][j];
3352             k++;
3353           }
3354           workstring[k] = '\0';
3355           epsilon = (REAL) strtod(workstring, (char **) nullptr);
3356         }
3357       } else if (argv[i][j] == 'R') {
3358         reversetetori = 1;
3359       } else if (argv[i][j] == 'C') {
3360         docheck++;
3361       } else if (argv[i][j] == 'Q') {
3362         quiet = 1;
3363       } else if (argv[i][j] == 'V') {
3364         verbose++;
3365       } else if (argv[i][j] == 'x') {
3366         if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3367             (argv[i][j + 1] == '.')) {
3368           k = 0;
3369           while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3370                  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3371                  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3372             j++;
3373             workstring[k] = argv[i][j];
3374             k++;
3375           }
3376           workstring[k] = '\0';
3377           tetrahedraperblock = (int) strtol(workstring, (char **) nullptr, 0);
3378           if (tetrahedraperblock > 8188) {
3379             vertexperblock = tetrahedraperblock / 2;
3380             shellfaceperblock = vertexperblock / 2;
3381           } else {
3382             tetrahedraperblock = 8188;
3383           }
3384         }
3385       } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
3386                  (argv[i][j] == '?')) {
3387         usage();
3388       } else {
3389         printf("Warning:  Unknown switch -%c.\n", argv[i][j]);
3390       }
3391     }
3392   }
3393 
3394   if (startindex == 0) {
3395     // Set a temporary filename for debugging output.
3396     strcpy(infilename, "tetgen-tmpfile");
3397   } else {
3398     if (infilename[0] == '\0') {
3399       // No input file name. Print the syntax and exit.
3400       syntax();
3401       terminatetetgen(0);
3402     }
3403     // Recognize the object from file extension if it is available.
3404     if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3405       infilename[strlen(infilename) - 5] = '\0';
3406       object = NODES;
3407     } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3408       infilename[strlen(infilename) - 5] = '\0';
3409       object = POLY;
3410       plc = 1;
3411     } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3412       infilename[strlen(infilename) - 6] = '\0';
3413       object = POLY;
3414       plc = 1;
3415     } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3416       infilename[strlen(infilename) - 4] = '\0';
3417       object = OFF;
3418       plc = 1;
3419     } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3420       infilename[strlen(infilename) - 4] = '\0';
3421       object = PLY;
3422       plc = 1;
3423     } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3424       infilename[strlen(infilename) - 4] = '\0';
3425       object = STL;
3426       plc = 1;
3427     } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3428       infilename[strlen(infilename) - 5] = '\0';
3429       object = MEDIT;
3430       if (!refine) plc = 1;
3431     } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
3432       infilename[strlen(infilename) - 4] = '\0';
3433       object = VTK;
3434       plc = 1;
3435     } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3436       infilename[strlen(infilename) - 4] = '\0';
3437       object = MESH;
3438       refine = 1;
3439     }
3440   }
3441 
3442   if (nobisect && (!plc && !refine)) { // -Y
3443     plc = 1; // Default -p option.
3444   }
3445   if (quality && (!plc && !refine)) { // -q
3446     plc = 1; // Default -p option.
3447   }
3448   if (diagnose && !plc) { // -d
3449     plc = 1;
3450   }
3451   if (plc && !quality && !nobisect) { // -p only
3452     // Create a CDT, do not do mesh optimization.
3453     optlevel = 0;
3454   }
3455   if (refine && !quality) { // -r only
3456     // Reconstruct a mesh, no mesh optimization.
3457     optlevel = 0;
3458   }
3459 
3460   // Detect improper combinations of switches.
3461   if (plc && refine) {
3462     printf("Error:  Switch -r cannot use together with -p.\n");
3463     return false;
3464   }
3465   if (refine && (plc || noiterationnum)) {
3466     printf("Error:  Switches %s cannot use together with -r.\n",
3467            "-p, -d, and -I");
3468     return false;
3469   }
3470   if ((refine || plc) && weighted) {
3471     printf("Error:  Switches -w cannot use together with -p or -r.\n");
3472     return false;
3473   }
3474 
3475   if (convex) { // -c
3476     if (plc && !regionattrib) {
3477       // -A (region attribute) is needed for marking exterior tets (-1).
3478       regionattrib = 1;
3479     }
3480   }
3481 
3482   // Note: -A must not used together with -r option.
3483   // Be careful not to add an extra attribute to each element unless the
3484   //   input supports it (PLC in, but not refining a preexisting mesh).
3485   if (refine || !plc) {
3486     regionattrib = 0;
3487   }
3488   // Be careful not to allocate space for element area constraints that
3489   //   will never be assigned any value (other than the default -1.0).
3490   if (!refine && !plc) {
3491     varvolume = 0;
3492   }
3493   // If '-a' or '-aa' is in use, enable '-q' option too.
3494   if (fixedvolume || varvolume) {
3495     if (quality == 0) {
3496       quality = 1;
3497       if (!plc && !refine) {
3498         plc = 1; // enable -p.
3499       }
3500     }
3501   }
3502   // No user-specified dihedral angle bound. Use default ones.
3503   if (!quality) {
3504     if (optmaxdihedral < 179.0) {
3505       optmaxdihedral = 179.0;
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 
3557 ////                                                                       ////
3558 ////                                                                       ////
3559 //// behavior_cxx /////////////////////////////////////////////////////////////
3560 
3561 //// mempool_cxx //////////////////////////////////////////////////////////////
3562 ////                                                                       ////
3563 ////                                                                       ////
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 
3620 ///////////////////////////////////////////////////////////////////////////////
3621 //                                                                           //
3622 // inittable()    Initialize the look-up tables.                             //
3623 //                                                                           //
3624 ///////////////////////////////////////////////////////////////////////////////
3625 
inittables()3626 void tetgenmesh::inittables()
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 
3706 ///////////////////////////////////////////////////////////////////////////////
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 //                                                                           //
3714 ///////////////////////////////////////////////////////////////////////////////
3715 
restart()3716 void tetgenmesh::arraypool::restart()
3717 {
3718   objects = 0l;
3719 }
3720 
3721 ///////////////////////////////////////////////////////////////////////////////
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 //                                                                           //
3728 ///////////////////////////////////////////////////////////////////////////////
3729 
poolinit(int sizeofobject,int log2objperblk)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 **) nullptr;
3744   toparraylen = 0;
3745 
3746   // Ready all indices to be allocated.
3747   restart();
3748 }
3749 
3750 ///////////////////////////////////////////////////////////////////////////////
3751 //                                                                           //
3752 // arraypool()    The constructor and destructor.                            //
3753 //                                                                           //
3754 ///////////////////////////////////////////////////////////////////////////////
3755 
arraypool(int sizeofobject,int log2objperblk)3756 tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
3757 {
3758   poolinit(sizeofobject, log2objperblk);
3759 }
3760 
~arraypool()3761 tetgenmesh::arraypool::~arraypool()
3762 {
3763   int i;
3764 
3765   // Has anything been allocated at all?
3766   if (toparray != (char **) nullptr) {
3767     // Walk through the top array.
3768     for (i = 0; i < toparraylen; i++) {
3769       // Check every pointer; nullptrs may be scattered randomly.
3770       if (toparray[i] != (char *) nullptr) {
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 **) nullptr;
3781   toparraylen = 0;
3782   objects = 0;
3783   totalmemory = 0;
3784 }
3785 
3786 ///////////////////////////////////////////////////////////////////////////////
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 //                                                                           //
3796 ///////////////////////////////////////////////////////////////////////////////
3797 
getblock(int objectindex)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 **) nullptr) {
3810     // Allocate the top array big enough to hold 'topindex', and nullptr 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 *) nullptr;
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, nullptr 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 *) nullptr;
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 *) nullptr) {
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 
3856 ///////////////////////////////////////////////////////////////////////////////
3857 //                                                                           //
3858 // lookup()    Return the pointer to the object with a given index, or nullptr  //
3859 //             if the object's block doesn't exist yet.                      //
3860 //                                                                           //
3861 ///////////////////////////////////////////////////////////////////////////////
3862 
lookup(int objectindex)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 **) nullptr) {
3870     return (void *) nullptr;
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 *) nullptr;
3878   }
3879 
3880   // Find the block, or learn that it hasn't been allocated yet.
3881   block = toparray[topindex];
3882   if (block == (char *) nullptr) {
3883     return (void *) nullptr;
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 
3892 ///////////////////////////////////////////////////////////////////////////////
3893 //                                                                           //
3894 // newindex()    Allocate space for a fresh object from the pool.            //
3895 //                                                                           //
3896 ///////////////////////////////////////////////////////////////////////////////
3897 
newindex(void ** newptr)3898 int tetgenmesh::arraypool::newindex(void **newptr)
3899 {
3900   void *newobject;
3901   int newindex;
3902 
3903   // Allocate an object at index 'firstvirgin'.
3904   newindex = objects;
3905   newobject = (void *) (getblock(objects) +
3906     (objects & (objectsperblock - 1)) * objectbytes);
3907   objects++;
3908 
3909   // If 'newptr' is not nullptr, use it to return a pointer to the object.
3910   if (newptr != (void **) nullptr) {
3911     *newptr = newobject;
3912   }
3913   return newindex;
3914 }
3915 
3916 
3917 ///////////////////////////////////////////////////////////////////////////////
3918 //                                                                           //
3919 // memorypool()   The constructors of memorypool.                            //
3920 //                                                                           //
3921 ///////////////////////////////////////////////////////////////////////////////
3922 
memorypool()3923 tetgenmesh::memorypool::memorypool()
3924 {
3925   firstblock = nowblock = (void **) nullptr;
3926   nextitem = (void *) nullptr;
3927   deaditemstack = (void *) nullptr;
3928   pathblock = (void **) nullptr;
3929   pathitem = (void *) nullptr;
3930   alignbytes = 0;
3931   itembytes = itemwords = 0;
3932   itemsperblock = 0;
3933   items = maxitems = 0l;
3934   unallocateditems = 0;
3935   pathitemsleft = 0;
3936 }
3937 
memorypool(int bytecount,int itemcount,int wsize,int alignment)3938 tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
3939                                    int alignment)
3940 {
3941   poolinit(bytecount, itemcount, wsize, alignment);
3942 }
3943 
3944 ///////////////////////////////////////////////////////////////////////////////
3945 //                                                                           //
3946 // ~memorypool()   Free to the operating system all memory taken by a pool.  //
3947 //                                                                           //
3948 ///////////////////////////////////////////////////////////////////////////////
3949 
~memorypool()3950 tetgenmesh::memorypool::~memorypool()
3951 {
3952   while (firstblock != (void **) nullptr) {
3953     nowblock = (void **) *(firstblock);
3954     free(firstblock);
3955     firstblock = nowblock;
3956   }
3957 }
3958 
3959 ///////////////////////////////////////////////////////////////////////////////
3960 //                                                                           //
3961 // poolinit()    Initialize a pool of memory for allocation of items.        //
3962 //                                                                           //
3963 // A `pool' is created whose records have size at least `bytecount'.  Items  //
3964 // will be allocated in `itemcount'-item blocks.  Each item is assumed to be //
3965 // a collection of words, and either pointers or floating-point values are   //
3966 // assumed to be the "primary" word type.  (The "primary" word type is used  //
3967 // to determine alignment of items.)  If `alignment' isn't zero, all items   //
3968 // will be `alignment'-byte aligned in memory.  `alignment' must be either a //
3969 // multiple or a factor of the primary word size;  powers of two are safe.   //
3970 // `alignment' is normally used to create a few unused bits at the bottom of //
3971 // each item's pointer, in which information may be stored.                  //
3972 //                                                                           //
3973 ///////////////////////////////////////////////////////////////////////////////
3974 
poolinit(int bytecount,int itemcount,int wordsize,int alignment)3975 void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
3976                                       int alignment)
3977 {
3978   // Find the proper alignment, which must be at least as large as:
3979   //   - The parameter `alignment'.
3980   //   - The primary word type, to avoid unaligned accesses.
3981   //   - sizeof(void *), so the stack of dead items can be maintained
3982   //       without unaligned accesses.
3983   if (alignment > wordsize) {
3984     alignbytes = alignment;
3985   } else {
3986     alignbytes = wordsize;
3987   }
3988   if ((int) sizeof(void *) > alignbytes) {
3989     alignbytes = (int) sizeof(void *);
3990   }
3991   itemwords = ((bytecount + alignbytes - 1) /  alignbytes)
3992             * (alignbytes / wordsize);
3993   itembytes = itemwords * wordsize;
3994   itemsperblock = itemcount;
3995 
3996   // Allocate a block of items.  Space for `itemsperblock' items and one
3997   //   pointer (to point to the next block) are allocated, as well as space
3998   //   to ensure alignment of the items.
3999   firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4000                                 + alignbytes);
4001   if (firstblock == (void **) nullptr) {
4002     terminatetetgen(1);
4003   }
4004   // Set the next block pointer to nullptr.
4005   *(firstblock) = (void *) nullptr;
4006   restart();
4007 }
4008 
4009 ///////////////////////////////////////////////////////////////////////////////
4010 //                                                                           //
4011 // restart()   Deallocate all items in this pool.                            //
4012 //                                                                           //
4013 // The pool is returned to its starting state, except that no memory is      //
4014 // freed to the operating system.  Rather, the previously allocated blocks   //
4015 // are ready to be reused.                                                   //
4016 //                                                                           //
4017 ///////////////////////////////////////////////////////////////////////////////
4018 
restart()4019 void tetgenmesh::memorypool::restart()
4020 {
4021   uintptr_t alignptr;
4022 
4023   items = 0;
4024   maxitems = 0;
4025 
4026   // Set the currently active block.
4027   nowblock = firstblock;
4028   // Find the first item in the pool.  Increment by the size of (void *).
4029   alignptr = (uintptr_t) (nowblock + 1);
4030   // Align the item on an `alignbytes'-byte boundary.
4031   nextitem = (void *)
4032     (alignptr + (uintptr_t) alignbytes -
4033      (alignptr % (uintptr_t) alignbytes));
4034   // There are lots of unallocated items left in this block.
4035   unallocateditems = itemsperblock;
4036   // The stack of deallocated items is empty.
4037   deaditemstack = (void *) nullptr;
4038 }
4039 
4040 ///////////////////////////////////////////////////////////////////////////////
4041 //                                                                           //
4042 // alloc()   Allocate space for an item.                                     //
4043 //                                                                           //
4044 ///////////////////////////////////////////////////////////////////////////////
4045 
alloc()4046 void* tetgenmesh::memorypool::alloc()
4047 {
4048   void *newitem;
4049   void **newblock;
4050   uintptr_t alignptr;
4051 
4052   // First check the linked list of dead items.  If the list is not
4053   //   empty, allocate an item from the list rather than a fresh one.
4054   if (deaditemstack != (void *) nullptr) {
4055     newitem = deaditemstack;                     // Take first item in list.
4056     deaditemstack = * (void **) deaditemstack;
4057   } else {
4058     // Check if there are any free items left in the current block.
4059     if (unallocateditems == 0) {
4060       // Check if another block must be allocated.
4061       if (*nowblock == (void *) nullptr) {
4062         // Allocate a new block of items, pointed to by the previous block.
4063         newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4064                                     + alignbytes);
4065         if (newblock == (void **) nullptr) {
4066           terminatetetgen(1);
4067         }
4068         *nowblock = (void *) newblock;
4069         // The next block pointer is nullptr.
4070         *newblock = (void *) nullptr;
4071       }
4072       // Move to the new block.
4073       nowblock = (void **) *nowblock;
4074       // Find the first item in the block.
4075       //   Increment by the size of (void *).
4076       alignptr = (uintptr_t) (nowblock + 1);
4077       // Align the item on an `alignbytes'-byte boundary.
4078       nextitem = (void *)
4079         (alignptr + (uintptr_t) alignbytes -
4080          (alignptr % (uintptr_t) alignbytes));
4081       // There are lots of unallocated items left in this block.
4082       unallocateditems = itemsperblock;
4083     }
4084     // Allocate a new item.
4085     newitem = nextitem;
4086     // Advance `nextitem' pointer to next free item in block.
4087     nextitem = (void *) ((uintptr_t) nextitem + itembytes);
4088     unallocateditems--;
4089     maxitems++;
4090   }
4091   items++;
4092   return newitem;
4093 }
4094 
4095 ///////////////////////////////////////////////////////////////////////////////
4096 //                                                                           //
4097 // dealloc()   Deallocate space for an item.                                 //
4098 //                                                                           //
4099 // The deallocated space is stored in a queue for later reuse.               //
4100 //                                                                           //
4101 ///////////////////////////////////////////////////////////////////////////////
4102 
dealloc(void * dyingitem)4103 void tetgenmesh::memorypool::dealloc(void *dyingitem)
4104 {
4105   // Push freshly killed item onto stack.
4106   *((void **) dyingitem) = deaditemstack;
4107   deaditemstack = dyingitem;
4108   items--;
4109 }
4110 
4111 ///////////////////////////////////////////////////////////////////////////////
4112 //                                                                           //
4113 // traversalinit()   Prepare to traverse the entire list of items.           //
4114 //                                                                           //
4115 // This routine is used in conjunction with traverse().                      //
4116 //                                                                           //
4117 ///////////////////////////////////////////////////////////////////////////////
4118 
traversalinit()4119 void tetgenmesh::memorypool::traversalinit()
4120 {
4121   uintptr_t alignptr;
4122 
4123   // Begin the traversal in the first block.
4124   pathblock = firstblock;
4125   // Find the first item in the block.  Increment by the size of (void *).
4126   alignptr = (uintptr_t) (pathblock + 1);
4127   // Align with item on an `alignbytes'-byte boundary.
4128   pathitem = (void *)
4129     (alignptr + (uintptr_t) alignbytes -
4130      (alignptr % (uintptr_t) alignbytes));
4131   // Set the number of items left in the current block.
4132   pathitemsleft = itemsperblock;
4133 }
4134 
4135 ///////////////////////////////////////////////////////////////////////////////
4136 //                                                                           //
4137 // traverse()   Find the next item in the list.                              //
4138 //                                                                           //
4139 // This routine is used in conjunction with traversalinit().  Be forewarned  //
4140 // that this routine successively returns all items in the list, including   //
4141 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
4142 // ones are actually dead.  It can usually be done more space-efficiently by //
4143 // a routine that knows something about the structure of the item.           //
4144 //                                                                           //
4145 ///////////////////////////////////////////////////////////////////////////////
4146 
traverse()4147 void* tetgenmesh::memorypool::traverse()
4148 {
4149   void *newitem;
4150   uintptr_t alignptr;
4151 
4152   // Stop upon exhausting the list of items.
4153   if (pathitem == nextitem) {
4154     return (void *) nullptr;
4155   }
4156   // Check whether any untraversed items remain in the current block.
4157   if (pathitemsleft == 0) {
4158     // Find the next block.
4159     pathblock = (void **) *pathblock;
4160     // Find the first item in the block.  Increment by the size of (void *).
4161     alignptr = (uintptr_t) (pathblock + 1);
4162     // Align with item on an `alignbytes'-byte boundary.
4163     pathitem = (void *)
4164       (alignptr + (uintptr_t) alignbytes -
4165        (alignptr % (uintptr_t) alignbytes));
4166     // Set the number of items left in the current block.
4167     pathitemsleft = itemsperblock;
4168   }
4169   newitem = pathitem;
4170   // Find the next item in the block.
4171   pathitem = (void *) ((uintptr_t) pathitem + itembytes);
4172   pathitemsleft--;
4173   return newitem;
4174 }
4175 
4176 ///////////////////////////////////////////////////////////////////////////////
4177 //                                                                           //
4178 // makeindex2pointmap()    Create a map from index to vertices.              //
4179 //                                                                           //
4180 // 'idx2verlist' returns the created map.  Traverse all vertices, a pointer  //
4181 // to each vertex is set into the array.  The pointer to the first vertex is //
4182 // saved in 'idx2verlist[in->firstnumber]'.                                  //
4183 //                                                                           //
4184 ///////////////////////////////////////////////////////////////////////////////
4185 
makeindex2pointmap(point * & idx2verlist)4186 void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
4187 {
4188   point pointloop;
4189   int idx;
4190 
4191   if (b->verbose > 1) {
4192     printf("  Constructing mapping from indices to points.\n");
4193   }
4194 
4195   idx2verlist = new point[points->items + 1];
4196 
4197   points->traversalinit();
4198   pointloop = pointtraverse();
4199   idx =  in->firstnumber;
4200   while (pointloop != (point) nullptr) {
4201     idx2verlist[idx++] = pointloop;
4202     pointloop = pointtraverse();
4203   }
4204 }
4205 
4206 ///////////////////////////////////////////////////////////////////////////////
4207 //                                                                           //
4208 // makesubfacemap()    Create a map from vertex to subfaces incident at it.  //
4209 //                                                                           //
4210 // The map is returned in two arrays 'idx2faclist' and 'facperverlist'.  All //
4211 // subfaces incident at i-th vertex (i is counted from 0) are found in the   //
4212 // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1].   //
4213 // Each entry in facperverlist[j] is a subface whose origin is the vertex.   //
4214 //                                                                           //
4215 // NOTE: These two arrays will be created inside this routine, don't forget  //
4216 // to free them after using.                                                 //
4217 //                                                                           //
4218 ///////////////////////////////////////////////////////////////////////////////
4219 
makepoint2submap(memorypool * pool,int * & idx2faclist,face * & facperverlist)4220 void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
4221                                   face*& facperverlist)
4222 {
4223   face shloop;
4224   int i, j, k;
4225 
4226   if (b->verbose > 1) {
4227     printf("  Making a map from points to subfaces.\n");
4228   }
4229 
4230   // Initialize 'idx2faclist'.
4231   idx2faclist = new int[points->items + 1];
4232   for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
4233 
4234   // Loop all subfaces, counter the number of subfaces incident at a vertex.
4235   pool->traversalinit();
4236   shloop.sh = shellfacetraverse(pool);
4237   while (shloop.sh != (shellface *) nullptr) {
4238     // Increment the number of incident subfaces for each vertex.
4239     j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4240     idx2faclist[j]++;
4241     j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4242     idx2faclist[j]++;
4243     // Skip the third corner if it is a segment.
4244     if (shloop.sh[5] != nullptr) {
4245       j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4246       idx2faclist[j]++;
4247     }
4248     shloop.sh = shellfacetraverse(pool);
4249   }
4250 
4251   // Calculate the total length of array 'facperverlist'.
4252   j = idx2faclist[0];
4253   idx2faclist[0] = 0;  // Array starts from 0 element.
4254   for (i = 0; i < points->items; i++) {
4255     k = idx2faclist[i + 1];
4256     idx2faclist[i + 1] = idx2faclist[i] + j;
4257     j = k;
4258   }
4259 
4260   // The total length is in the last unit of idx2faclist.
4261   facperverlist = new face[idx2faclist[i]];
4262 
4263   // Loop all subfaces again, remember the subfaces at each vertex.
4264   pool->traversalinit();
4265   shloop.sh = shellfacetraverse(pool);
4266   while (shloop.sh != (shellface *) nullptr) {
4267     j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4268     shloop.shver = 0; // save the origin.
4269     facperverlist[idx2faclist[j]] = shloop;
4270     idx2faclist[j]++;
4271     // Is it a subface or a subsegment?
4272     if (shloop.sh[5] != nullptr) {
4273       j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4274       shloop.shver = 2; // save the origin.
4275       facperverlist[idx2faclist[j]] = shloop;
4276       idx2faclist[j]++;
4277       j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4278       shloop.shver = 4; // save the origin.
4279       facperverlist[idx2faclist[j]] = shloop;
4280       idx2faclist[j]++;
4281     } else {
4282       j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4283       shloop.shver = 1; // save the origin.
4284       facperverlist[idx2faclist[j]] = shloop;
4285       idx2faclist[j]++;
4286     }
4287     shloop.sh = shellfacetraverse(pool);
4288   }
4289 
4290   // Contents in 'idx2faclist' are shifted, now shift them back.
4291   for (i = points->items - 1; i >= 0; i--) {
4292     idx2faclist[i + 1] = idx2faclist[i];
4293   }
4294   idx2faclist[0] = 0;
4295 }
4296 
4297 ///////////////////////////////////////////////////////////////////////////////
4298 //                                                                           //
4299 // tetrahedrondealloc()    Deallocate space for a tet., marking it dead.     //
4300 //                                                                           //
4301 ///////////////////////////////////////////////////////////////////////////////
4302 
tetrahedrondealloc(tetrahedron * dyingtetrahedron)4303 void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
4304 {
4305   // Set tetrahedron's vertices to nullptr. This makes it possible to detect
4306   //   dead tetrahedra when traversing the list of all tetrahedra.
4307   dyingtetrahedron[4] = (tetrahedron) nullptr;
4308 
4309   // Dealloc the space to subfaces/subsegments.
4310   if (dyingtetrahedron[8] != nullptr) {
4311     tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
4312   }
4313   if (dyingtetrahedron[9] != nullptr) {
4314     tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
4315   }
4316 
4317   tetrahedrons->dealloc((void *) dyingtetrahedron);
4318 }
4319 
4320 ///////////////////////////////////////////////////////////////////////////////
4321 //                                                                           //
4322 // tetrahedrontraverse()    Traverse the tetrahedra, skipping dead ones.     //
4323 //                                                                           //
4324 ///////////////////////////////////////////////////////////////////////////////
4325 
tetrahedrontraverse()4326 tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
4327 {
4328   tetrahedron *newtetrahedron;
4329 
4330   do {
4331     newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4332     if (newtetrahedron == (tetrahedron *) nullptr) {
4333       return (tetrahedron *) nullptr;
4334     }
4335   } while ((newtetrahedron[4] == (tetrahedron) nullptr) ||
4336            ((point) newtetrahedron[7] == dummypoint));
4337   return newtetrahedron;
4338 }
4339 
alltetrahedrontraverse()4340 tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
4341 {
4342   tetrahedron *newtetrahedron;
4343 
4344   do {
4345     newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4346     if (newtetrahedron == (tetrahedron *) nullptr) {
4347       return (tetrahedron *) nullptr;
4348     }
4349   } while (newtetrahedron[4] == (tetrahedron) nullptr); // Skip dead ones.
4350   return newtetrahedron;
4351 }
4352 
4353 ///////////////////////////////////////////////////////////////////////////////
4354 //                                                                           //
4355 // shellfacedealloc()    Deallocate space for a shellface, marking it dead.  //
4356 //                       Used both for dealloc a subface and subsegment.     //
4357 //                                                                           //
4358 ///////////////////////////////////////////////////////////////////////////////
4359 
shellfacedealloc(memorypool * pool,shellface * dyingsh)4360 void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
4361 {
4362   // Set shellface's vertices to nullptr. This makes it possible to detect dead
4363   //   shellfaces when traversing the list of all shellfaces.
4364   dyingsh[3] = (shellface) nullptr;
4365   pool->dealloc((void *) dyingsh);
4366 }
4367 
4368 ///////////////////////////////////////////////////////////////////////////////
4369 //                                                                           //
4370 // shellfacetraverse()    Traverse the subfaces, skipping dead ones. Used    //
4371 //                        for both subfaces and subsegments pool traverse.   //
4372 //                                                                           //
4373 ///////////////////////////////////////////////////////////////////////////////
4374 
shellfacetraverse(memorypool * pool)4375 tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
4376 {
4377   shellface *newshellface;
4378 
4379   do {
4380     newshellface = (shellface *) pool->traverse();
4381     if (newshellface == (shellface *) nullptr) {
4382       return (shellface *) nullptr;
4383     }
4384   } while (newshellface[3] == (shellface) nullptr);          // Skip dead ones.
4385   return newshellface;
4386 }
4387 
4388 
4389 ///////////////////////////////////////////////////////////////////////////////
4390 //                                                                           //
4391 // pointdealloc()    Deallocate space for a point, marking it dead.          //
4392 //                                                                           //
4393 ///////////////////////////////////////////////////////////////////////////////
4394 
pointdealloc(point dyingpoint)4395 void tetgenmesh::pointdealloc(point dyingpoint)
4396 {
4397   // Mark the point as dead. This  makes it possible to detect dead points
4398   //   when traversing the list of all points.
4399   setpointtype(dyingpoint, DEADVERTEX);
4400   points->dealloc((void *) dyingpoint);
4401 }
4402 
4403 ///////////////////////////////////////////////////////////////////////////////
4404 //                                                                           //
4405 // pointtraverse()    Traverse the points, skipping dead ones.               //
4406 //                                                                           //
4407 ///////////////////////////////////////////////////////////////////////////////
4408 
pointtraverse()4409 tetgenmesh::point tetgenmesh::pointtraverse()
4410 {
4411   point newpoint;
4412 
4413   do {
4414     newpoint = (point) points->traverse();
4415     if (newpoint == (point) nullptr) {
4416       return (point) nullptr;
4417     }
4418   } while (pointtype(newpoint) == DEADVERTEX);            // Skip dead ones.
4419   return newpoint;
4420 }
4421 
4422 ///////////////////////////////////////////////////////////////////////////////
4423 //                                                                           //
4424 // maketetrahedron()    Create a new tetrahedron.                            //
4425 //                                                                           //
4426 ///////////////////////////////////////////////////////////////////////////////
4427 
maketetrahedron(triface * newtet)4428 void tetgenmesh::maketetrahedron(triface *newtet)
4429 {
4430   newtet->tet = (tetrahedron *) tetrahedrons->alloc();
4431 
4432   // Initialize the four adjoining tetrahedra to be "outer space".
4433   newtet->tet[0] = nullptr;
4434   newtet->tet[1] = nullptr;
4435   newtet->tet[2] = nullptr;
4436   newtet->tet[3] = nullptr;
4437   // Four nullptr vertices.
4438   newtet->tet[4] = nullptr;
4439   newtet->tet[5] = nullptr;
4440   newtet->tet[6] = nullptr;
4441   newtet->tet[7] = nullptr;
4442   // No attached segments and sbfaces yet.
4443   newtet->tet[8] = nullptr;
4444   newtet->tet[9] = nullptr;
4445   // Initialize the marker (clear all flags).
4446   setelemmarker(newtet->tet, 0);
4447   for (int i = 0; i < numelemattrib; i++) {
4448     setelemattribute(newtet->tet, i, 0.0);
4449   }
4450   if (b->varvolume) {
4451     setvolumebound(newtet->tet, -1.0);
4452   }
4453 
4454   // Initialize the version to be Zero.
4455   newtet->ver = 11;
4456 }
4457 
4458 ///////////////////////////////////////////////////////////////////////////////
4459 //                                                                           //
4460 // makeshellface()    Create a new shellface with version zero. Used for     //
4461 //                    both subfaces and seusegments.                         //
4462 //                                                                           //
4463 ///////////////////////////////////////////////////////////////////////////////
4464 
makeshellface(memorypool * pool,face * newface)4465 void tetgenmesh::makeshellface(memorypool *pool, face *newface)
4466 {
4467   newface->sh = (shellface *) pool->alloc();
4468 
4469   // No adjointing subfaces.
4470   newface->sh[0] = nullptr;
4471   newface->sh[1] = nullptr;
4472   newface->sh[2] = nullptr;
4473   // Three nullptr vertices.
4474   newface->sh[3] = nullptr;
4475   newface->sh[4] = nullptr;
4476   newface->sh[5] = nullptr;
4477   // No adjoining subsegments.
4478   newface->sh[6] = nullptr;
4479   newface->sh[7] = nullptr;
4480   newface->sh[8] = nullptr;
4481   // No adjoining tetrahedra.
4482   newface->sh[9] = nullptr;
4483   newface->sh[10] = nullptr;
4484   if (checkconstraints) {
4485     // Initialize the maximum area bound.
4486     setareabound(*newface, 0.0);
4487   }
4488 
4489   // Clear the infection and marktest bits.
4490   ((int *) (newface->sh))[shmarkindex + 1] = 0;
4491 
4492   // Set the boundary marker to zero.
4493   setshellmark(*newface, 0);
4494   // Set the default face type.
4495   setshelltype(*newface, NSHARP);
4496 
4497   newface->shver = 0;
4498 }
4499 
4500 ///////////////////////////////////////////////////////////////////////////////
4501 //                                                                           //
4502 // makepoint()    Create a new point.                                        //
4503 //                                                                           //
4504 ///////////////////////////////////////////////////////////////////////////////
4505 
makepoint(point * pnewpoint,enum verttype vtype)4506 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
4507 {
4508   int i;
4509 
4510   *pnewpoint = (point) points->alloc();
4511 
4512   // Initialize the point attributes.
4513   for (i = 0; i < numpointattrib; i++) {
4514     (*pnewpoint)[3 + i] = 0.0;
4515   }
4516   // Initialize the metric tensor.
4517   for (i = 0; i < sizeoftensor; i++) {
4518     (*pnewpoint)[pointmtrindex + i] = 0.0;
4519   }
4520   setpoint2tet(*pnewpoint, nullptr);
4521   setpoint2ppt(*pnewpoint, nullptr);
4522   if (b->plc || b->psc || b->refine) {
4523     // Initialize the point-to-simplex field.
4524     setpoint2sh(*pnewpoint, nullptr);
4525     if (b->metric && (bgm != nullptr)) {
4526       setpoint2bgmtet(*pnewpoint, nullptr);
4527     }
4528   }
4529   // Initialize the point marker (starting from in->firstnumber).
4530   setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
4531   // Clear all flags.
4532   ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
4533   // Initialize (set) the point type.
4534   setpointtype(*pnewpoint, vtype);
4535 }
4536 
4537 ///////////////////////////////////////////////////////////////////////////////
4538 //                                                                           //
4539 // initializepools()    Calculate the sizes of the point, tetrahedron, and   //
4540 //                      subface. Initialize their memory pools.              //
4541 //                                                                           //
4542 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
4543 // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'.  They are  //
4544 // used to find values within each point and tetrahedron, respectively.      //
4545 //                                                                           //
4546 ///////////////////////////////////////////////////////////////////////////////
4547 
initializepools()4548 void tetgenmesh::initializepools()
4549 {
4550   int pointsize = 0, elesize = 0, shsize = 0;
4551   int i;
4552 
4553   if (b->verbose) {
4554     printf("  Initializing memorypools.\n");
4555     printf("  tetrahedron per block: %d.\n", b->tetrahedraperblock);
4556   }
4557 
4558   inittables();
4559 
4560   // There are three input point lists available, which are in, addin,
4561   //   and bgm->in. These point lists may have different number of
4562   //   attributes. Decide the maximum number.
4563   numpointattrib = in->numberofpointattributes;
4564   if (bgm != nullptr) {
4565     if (bgm->in->numberofpointattributes > numpointattrib) {
4566       numpointattrib = bgm->in->numberofpointattributes;
4567     }
4568   }
4569   if (addin != nullptr) {
4570     if (addin->numberofpointattributes > numpointattrib) {
4571       numpointattrib = addin->numberofpointattributes;
4572     }
4573   }
4574   if (b->weighted || b->flipinsert) { // -w or -L.
4575     // The internal number of point attribute needs to be at least 1
4576     //   (for storing point weights).
4577     if (numpointattrib == 0) {
4578       numpointattrib = 1;
4579     }
4580   }
4581 
4582   // Default varconstraint = 0;
4583   if (in->segmentconstraintlist || in->facetconstraintlist) {
4584     checkconstraints = 1;
4585   }
4586 
4587   // The index within each point at which its metric tensor is found.
4588   // Each vertex has three coordinates.
4589   if (b->psc) {
4590     // '-s' option (PSC), the u,v coordinates are provided.
4591     pointmtrindex = 5 + numpointattrib;
4592   } else {
4593     pointmtrindex = 3 + numpointattrib;
4594   }
4595   // The index within each point at which its u, v coordinates are found.
4596   pointparamindex = 3 + (numpointattrib > 0);
4597   // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
4598   if (b->metric) {
4599     // Decide the size (1, 3, or 6) of the metric tensor.
4600     if (bgm != (tetgenmesh *) nullptr) {
4601       // A background mesh is allocated. It may not exist though.
4602       sizeoftensor = (bgm->in != (tetgenio *) nullptr) ?
4603         bgm->in->numberofpointmtrs : in->numberofpointmtrs;
4604     } else {
4605       // No given background mesh - Itself is a background mesh.
4606       sizeoftensor = in->numberofpointmtrs;
4607     }
4608     // Make sure sizeoftensor is at least 1.
4609     sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
4610   } else {
4611     // For '-q' option. Make sure to have space for saving a scalar value.
4612     sizeoftensor = b->quality ? 1 : 0;
4613   }
4614   // The index within each point at which an element pointer is found, where
4615   //   the index is measured in pointers. Ensure the index is aligned to a
4616   //   sizeof(tetrahedron)-byte address.
4617   point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
4618                  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
4619   // [Bruno Levy] seems to fix the problem for computing
4620   // Delaunay triangulation from 3D points alone.
4621   if (true || b->plc || b->refine || b->voroout) {
4622     // Increase the point size by three pointers, which are:
4623     //   - a pointer to a tet, read by point2tet();
4624     //   - a pointer to a parent point, read by point2ppt()).
4625     //   - a pointer to a subface or segment, read by point2sh();
4626     if (b->metric && (bgm != (tetgenmesh *) nullptr)) {
4627       // Increase one pointer into the background mesh, point2bgmtet().
4628       pointsize = (point2simindex + 4) * sizeof(tetrahedron);
4629     } else {
4630       pointsize = (point2simindex + 3) * sizeof(tetrahedron);
4631     }
4632   } else {
4633     // Increase the point size by two pointer, which are:
4634     //   - a pointer to a tet, read by point2tet();
4635     //   - a pointer to a parent point, read by point2ppt()). -- Used by btree.
4636     pointsize = (point2simindex + 2) * sizeof(tetrahedron);
4637   }
4638   // The index within each point at which the boundary marker is found,
4639   //   Ensure the point marker is aligned to a sizeof(int)-byte address.
4640   pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
4641   // Now point size is the ints (inidcated by pointmarkindex) plus:
4642   //   - an integer for boundary marker;
4643   //   - an integer for vertex type;
4644   //   - an integer for geometry tag (optional, -s option).
4645   pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
4646 
4647   // Initialize the pool of vertices.
4648   points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
4649 
4650   if (b->verbose) {
4651     printf("  Size of a point: %d bytes.\n", points->itembytes);
4652   }
4653 
4654   // Initialize the infinite vertex.
4655   dummypoint = (point) new char[pointsize];
4656   // Initialize all fields of this point.
4657   dummypoint[0] = 0.0;
4658   dummypoint[1] = 0.0;
4659   dummypoint[2] = 0.0;
4660   for (i = 0; i < numpointattrib; i++) {
4661     dummypoint[3 + i] = 0.0;
4662   }
4663   // Initialize the metric tensor.
4664   for (i = 0; i < sizeoftensor; i++) {
4665     dummypoint[pointmtrindex + i] = 0.0;
4666   }
4667   setpoint2tet(dummypoint, nullptr);
4668   setpoint2ppt(dummypoint, nullptr);
4669   if (b->plc || b->psc || b->refine) {
4670     // Initialize the point-to-simplex field.
4671     setpoint2sh(dummypoint, nullptr);
4672     if (b->metric && (bgm != nullptr)) {
4673       setpoint2bgmtet(dummypoint, nullptr);
4674     }
4675   }
4676   // Initialize the point marker (starting from in->firstnumber).
4677   setpointmark(dummypoint, -1); // The unique marker for dummypoint.
4678   // Clear all flags.
4679   ((int *) (dummypoint))[pointmarkindex + 1] = 0;
4680   // Initialize (set) the point type.
4681   setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
4682 
4683   // The number of bytes occupied by a tetrahedron is varying by the user-
4684   //   specified options. The contents of the first 12 pointers are listed
4685   //   in the following table:
4686   //     [0]  |__ neighbor at f0 __|
4687   //     [1]  |__ neighbor at f1 __|
4688   //     [2]  |__ neighbor at f2 __|
4689   //     [3]  |__ neighbor at f3 __|
4690   //     [4]  |_____ vertex p0 ____|
4691   //     [5]  |_____ vertex p1 ____|
4692   //     [6]  |_____ vertex p2 ____|
4693   //     [7]  |_____ vertex p3 ____|
4694   //     [8]  |__ segments array __| (used by -p)
4695   //     [9]  |__ subfaces array __| (used by -p)
4696   //    [10]  |_____ reserved _____|
4697   //    [11]  |___ elem marker ____| (used as an integer)
4698 
4699   elesize = 12 * sizeof(tetrahedron);
4700 
4701   // The index to find the element markers. An integer containing varies
4702   //   flags and element counter.
4703   assert(sizeof(int) <= sizeof(tetrahedron));
4704   assert((sizeof(tetrahedron) % sizeof(int)) == 0);
4705   elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
4706 
4707   // The actual number of element attributes. Note that if the
4708   //   `b->regionattrib' flag is set, an additional attribute will be added.
4709   numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
4710 
4711   // The index within each element at which its attributes are found, where
4712   //   the index is measured in REALs.
4713   elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
4714   // The index within each element at which the maximum voulme bound is
4715   //   found, where the index is measured in REALs.
4716   volumeboundindex = elemattribindex + numelemattrib;
4717   // If element attributes or an constraint are needed, increase the number
4718   //   of bytes occupied by an element.
4719   if (b->varvolume) {
4720     elesize = (volumeboundindex + 1) * sizeof(REAL);
4721   } else if (numelemattrib > 0) {
4722     elesize = volumeboundindex * sizeof(REAL);
4723   }
4724 
4725 
4726   // Having determined the memory size of an element, initialize the pool.
4727   tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
4728                                 16);
4729 
4730   if (b->verbose) {
4731     printf("  Size of a tetrahedron: %d (%d) bytes.\n", elesize,
4732            tetrahedrons->itembytes);
4733   }
4734 
4735   if (b->plc || b->refine) { // if (b->useshelles) {
4736     // The number of bytes occupied by a subface.  The list of pointers
4737     //   stored in a subface are: three to other subfaces, three to corners,
4738     //   three to subsegments, two to tetrahedra.
4739     shsize = 11 * sizeof(shellface);
4740     // The index within each subface at which the maximum area bound is
4741     //   found, where the index is measured in REALs.
4742     areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
4743     // If -q switch is in use, increase the number of bytes occupied by
4744     //   a subface for saving maximum area bound.
4745     if (checkconstraints) {
4746       shsize = (areaboundindex + 1) * sizeof(REAL);
4747     } else {
4748       shsize = areaboundindex * sizeof(REAL);
4749     }
4750     // The index within subface at which the facet marker is found. Ensure
4751     //   the marker is aligned to a sizeof(int)-byte address.
4752     shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
4753     // Increase the number of bytes by two or three integers, one for facet
4754     //   marker, one for shellface type, and optionally one for pbc group.
4755     shsize = (shmarkindex + 2) * sizeof(shellface);
4756 
4757     // Initialize the pool of subfaces. Each subface record is eight-byte
4758     //   aligned so it has room to store an edge version (from 0 to 5) in
4759     //   the least three bits.
4760     subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4761 
4762     if (b->verbose) {
4763       printf("  Size of a shellface: %d (%d) bytes.\n", shsize,
4764              subfaces->itembytes);
4765     }
4766 
4767     // Initialize the pool of subsegments. The subsegment's record is same
4768     //   with subface.
4769     subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4770 
4771     // Initialize the pool for tet-subseg connections.
4772     tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
4773                                  sizeof(void *), 0);
4774     // Initialize the pool for tet-subface connections.
4775     tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
4776                                  sizeof(void *), 0);
4777 
4778     // Initialize arraypools for segment & facet recovery.
4779     subsegstack = new arraypool(sizeof(face), 10);
4780     subfacstack = new arraypool(sizeof(face), 10);
4781     subvertstack = new arraypool(sizeof(point), 8);
4782 
4783     // Initialize arraypools for surface point insertion/deletion.
4784     caveshlist = new arraypool(sizeof(face), 8);
4785     caveshbdlist = new arraypool(sizeof(face), 8);
4786     cavesegshlist = new arraypool(sizeof(face), 4);
4787 
4788     cavetetshlist = new arraypool(sizeof(face), 8);
4789     cavetetseglist = new arraypool(sizeof(face), 8);
4790     caveencshlist = new arraypool(sizeof(face), 8);
4791     caveencseglist = new arraypool(sizeof(face), 8);
4792   }
4793 
4794   // Initialize the pools for flips.
4795   flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
4796   unflipqueue = new arraypool(sizeof(badface), 10);
4797 
4798   // Initialize the arraypools for point insertion.
4799   cavetetlist = new arraypool(sizeof(triface), 10);
4800   cavebdrylist = new arraypool(sizeof(triface), 10);
4801   caveoldtetlist = new arraypool(sizeof(triface), 10);
4802   cavetetvertlist = new arraypool(sizeof(point), 10);
4803 }
4804 
4805 ////                                                                       ////
4806 ////                                                                       ////
4807 //// mempool_cxx //////////////////////////////////////////////////////////////
4808 
4809 //// geom_cxx /////////////////////////////////////////////////////////////////
4810 ////                                                                       ////
4811 ////                                                                       ////
4812 
4813 // PI is the ratio of a circle's circumference to its diameter.
4814 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
4815 
4816 
4817 #ifdef USE_PCK //[Bruno]
4818 
4819 } // close namespace GEO_3rdParty
4820 
4821 // Prototypes for PCK predicates
4822 namespace GEO {
4823 
4824     namespace PCK {
4825 
4826         Sign GEOGRAM_API side4_3d(
4827             const double* p0, const double* p1,
4828             const double* p2, const double* p3, const double* p4
4829         );
4830 
4831         Sign GEOGRAM_API side4_3d_SOS(
4832             const double* p0, const double* p1,
4833             const double* p2, const double* p3, const double* p4
4834         );
4835 
4836         Sign GEOGRAM_API orient_3d(
4837             const double* p0, const double* p1,
4838             const double* p2, const double* p3
4839         );
4840 
4841         Sign GEOGRAM_API orient_3dlifted(
4842             const double* p0, const double* p1,
4843             const double* p2, const double* p3, const double* p4,
4844             double h0, double h1, double h2, double h3, double h4
4845         );
4846 
4847         Sign GEOGRAM_API orient_3dlifted_SOS(
4848             const double* p0, const double* p1,
4849             const double* p2, const double* p3, const double* p4,
4850             double h0, double h1, double h2, double h3, double h4
4851         );
4852 
4853         void GEOGRAM_API initialize();
4854     }
4855 }
4856 
4857 namespace GEO_3rdParty { // re-open namespace GEO_3rdParty
4858 
4859 // Wrapper around PCK predicates to make them sourcelevel
4860 // compatible with Shewchuk's predicates.
4861 namespace {
4862 
orient3d(REAL * pa,REAL * pb,REAL * pc,REAL * pd)4863     REAL orient3d(REAL* pa, REAL *pb, REAL *pc, REAL *pd) {
4864         // Warning: PCK seems to have a convention
4865         // different from Shewchuk's, to be checked
4866         // (and also for other predicates...)
4867         // If I do not change the sign, I do not obtain
4868         // the same number of tets in BDEL and tetgen.
4869         return -REAL(GEO::PCK::orient_3d(pa,pb,pc,pd));
4870     }
4871 
insphere(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * pe)4872     REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) {
4873         return REAL(GEO::PCK::side4_3d(pa,pb,pc,pd,pe));
4874     }
4875 
orient4d(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * pe,REAL ah,REAL bh,REAL ch,REAL dh,REAL eh)4876     REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
4877                   REAL ah, REAL bh, REAL ch, REAL dh, REAL eh) {
4878         return REAL(GEO::PCK::orient_3dlifted(pa,pb,pc,pd,pe,ah,bh,ch,dh,eh));
4879     }
4880 
4881     /**
4882      * \brief Computes a four-by-four determinant.
4883      */
det4x4(REAL a11,REAL a12,REAL a13,REAL a14,REAL a21,REAL a22,REAL a23,REAL a24,REAL a31,REAL a32,REAL a33,REAL a34,REAL a41,REAL a42,REAL a43,REAL a44)4884     inline REAL det4x4(
4885         REAL a11, REAL a12, REAL a13, REAL a14,
4886         REAL a21, REAL a22, REAL a23, REAL a24,
4887         REAL a31, REAL a32, REAL a33, REAL a34,
4888         REAL a41, REAL a42, REAL a43, REAL a44
4889     ) {
4890         REAL m12 = a21*a12 - a11*a22;
4891         REAL m13 = a31*a12 - a11*a32;
4892         REAL m14 = a41*a12 - a11*a42;
4893         REAL m23 = a31*a22 - a21*a32;
4894         REAL m24 = a41*a22 - a21*a42;
4895         REAL m34 = a41*a32 - a31*a42;
4896 
4897         REAL m123 = m23*a13 - m13*a23 + m12*a33;
4898         REAL m124 = m24*a13 - m14*a23 + m12*a43;
4899         REAL m134 = m34*a13 - m14*a33 + m13*a43;
4900         REAL m234 = m34*a23 - m24*a33 + m23*a43;
4901 
4902         return (m234*a14 - m134*a24 + m124*a34 - m123*a44);
4903     }
4904 
4905     // PCK predicates only return the sign of the predicate,
4906     // whereas Shewchuk ones also return a real number that
4907     // has the approximate value of the determinant computed
4908     // by the predicates (and of course its exact sign).
4909     // Some parts of tetgen need also to compute the value
4910     // of the determinant, so I added this function.
4911 
orient4d_numeric(REAL * p0,REAL * p1,REAL * p2,REAL * p3,REAL * p4,REAL h0,REAL h1,REAL h2,REAL h3,REAL h4)4912     REAL orient4d_numeric(
4913         REAL *p0, REAL *p1, REAL *p2, REAL *p3, REAL *p4,
4914         REAL h0, REAL h1, REAL h2, REAL h3, REAL h4
4915     ) {
4916 
4917         REAL a11 = p1[0] - p0[0] ;
4918         REAL a12 = p1[1] - p0[1] ;
4919         REAL a13 = p1[2] - p0[2] ;
4920         REAL a14 = h1 - h0 ;
4921 
4922         REAL a21 = p2[0] - p0[0] ;
4923         REAL a22 = p2[1] - p0[1] ;
4924         REAL a23 = p2[2] - p0[2] ;
4925         REAL a24 = h2 - h0 ;
4926 
4927         REAL a31 = p3[0] - p0[0] ;
4928         REAL a32 = p3[1] - p0[1] ;
4929         REAL a33 = p3[2] - p0[2] ;
4930         REAL a34 = h3 - h0 ;
4931 
4932         REAL a41 = p4[0] - p0[0] ;
4933         REAL a42 = p4[1] - p0[1] ;
4934         REAL a43 = p4[2] - p0[2] ;
4935         REAL a44 = h4 - h0 ;
4936 
4937         REAL Delta = det4x4(
4938             a11,a12,a13,a14,
4939             a21,a22,a23,a24,
4940             a31,a32,a33,a34,
4941             a41,a42,a43,a44
4942          ) ;
4943         return Delta;
4944     }
4945 
4946 
exactinit()4947     void exactinit() {
4948         GEO::PCK::initialize();
4949     }
4950 }
4951 
4952 #else
4953 
4954 ///////////////////////////////////////////////////////////////////////////////
4955 //                                                                           //
4956 // Robust Geometric predicates                                               //
4957 //                                                                           //
4958 // Geometric predicates are simple tests of spatial relations of a set of d- //
4959 // dimensional points, such as the orientation test and the point-in-sphere  //
4960 // test. Each of these tests is performed by evaluating the sign of a deter- //
4961 // minant of a matrix whose entries are the coordinates of these points.  If //
4962 // the computation is performed by using the floating-point numbers, e.g.,   //
4963 // the single or double precision numbers in C/C++, roundoff error may cause //
4964 // an incorrect result. This may either lead to a wrong result or eventually //
4965 // lead to a failure of the program.  Computing the predicates exactly will  //
4966 // avoid the error and make the program robust.                              //
4967 //                                                                           //
4968 // The following routines are the robust geometric predicates for 3D orient- //
4969 // ation test and point-in-sphere test.  They were implemented by Shewchuk.  //
4970 // The source code are generously provided by him in the public domain,      //
4971 // http://www.cs.cmu.edu/~quake/robust.html. predicates.cxx is a C++ version //
4972 // of the original C code.                                                   //
4973 //                                                                           //
4974 // The original predicates of Shewchuk only use "dynamic filters", i.e., it  //
4975 // computes the error at run time step by step. TetGen first adds a "static  //
4976 // filter" in each predicate. It estimates the maximal possible error in all //
4977 // cases.  So it can safely and quickly answer many easy cases.              //
4978 //                                                                           //
4979 ///////////////////////////////////////////////////////////////////////////////
4980 
4981 REAL exactinit() ;
4982 REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd);
4983 REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe);
4984 REAL orient4d(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
4985               REAL ah, REAL bh, REAL ch, REAL dh, REAL eh);
4986 
orient4d_numeric(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * pe,REAL ah,REAL bh,REAL ch,REAL dh,REAL eh)4987 inline REAL orient4d_numeric(
4988     REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe,
4989     REAL ah, REAL bh, REAL ch, REAL dh, REAL eh) {
4990     return orient4d(pa,pb,pc,pd,pe,ah,bh,ch,dh,eh);
4991 }
4992 
4993 
4994 #endif
4995 
4996 ///////////////////////////////////////////////////////////////////////////////
4997 //                                                                           //
4998 // insphere_s()    Insphere test with symbolic perturbation.                 //
4999 //                                                                           //
5000 // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
5001 // outside the circumscirbed sphere of the four points.                      //
5002 //                                                                           //
5003 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
5004 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
5005 // points pa, pb, and pc. Otherwise, the returned sign is flipped.           //
5006 //                                                                           //
5007 // Return a positive value (> 0) if pe lies inside, a negative value (< 0)   //
5008 // if pe lies outside the sphere, the returned value will not be zero.       //
5009 //                                                                           //
5010 ///////////////////////////////////////////////////////////////////////////////
5011 
insphere_s(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * pe)5012 REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
5013 {
5014 #ifdef USE_PCK // [Bruno]
5015     return REAL(GEO::PCK::side4_3d_SOS(pa,pb,pc,pd,pe));
5016 #else
5017   REAL sign;
5018 
5019   sign = insphere(pa, pb, pc, pd, pe);
5020   if (sign != 0.0) {
5021     return sign;
5022   }
5023 
5024   // Symbolic perturbation.
5025   point pt[5], swappt;
5026   REAL oriA, oriB;
5027   int swaps, count;
5028   int n, i;
5029 
5030   pt[0] = pa;
5031   pt[1] = pb;
5032   pt[2] = pc;
5033   pt[3] = pd;
5034   pt[4] = pe;
5035 
5036   // Sort the five points such that their indices are in the increasing
5037   //   order. An optimized bubble sort algorithm is used, i.e., it has
5038   //   the worst case O(n^2) runtime, but it is usually much faster.
5039   swaps = 0; // Record the total number of swaps.
5040   n = 5;
5041   do {
5042     count = 0;
5043     n = n - 1;
5044     for (i = 0; i < n; i++) {
5045       if (pointmark(pt[i]) > pointmark(pt[i+1])) {
5046         swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
5047         count++;
5048       }
5049     }
5050     swaps += count;
5051   } while (count > 0); // Continue if some points are swapped.
5052 
5053   oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
5054   if (oriA != 0.0) {
5055     // Flip the sign if there are odd number of swaps.
5056     if ((swaps % 2) != 0) oriA = -oriA;
5057     return oriA;
5058   }
5059 
5060   oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
5061   assert(oriB != 0.0); // SELF_CHECK
5062   // Flip the sign if there are odd number of swaps.
5063   if ((swaps % 2) != 0) oriB = -oriB;
5064   return oriB;
5065 #endif
5066 }
5067 
5068 
5069 ///////////////////////////////////////////////////////////////////////////////
5070 //                                                                           //
5071 // orient4d_s()    4d orientation test with symbolic perturbation.           //
5072 //                                                                           //
5073 // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
5074 // point pe' in R^4 lies below or above the hyperplance passing through the  //
5075 // four points pa', pb', pc', and pd'.                                       //
5076 //                                                                           //
5077 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
5078 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
5079 // the points pa, pb, and pc. Otherwise, the returned sign is flipped.       //
5080 //                                                                           //
5081 // Return a positive value (> 0) if pe' lies below, a negative value (< 0)   //
5082 // if pe' lies above the hyperplane, the returned value should not be zero.  //
5083 //                                                                           //
5084 ///////////////////////////////////////////////////////////////////////////////
5085 
orient4d_s(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * pe,REAL aheight,REAL bheight,REAL cheight,REAL dheight,REAL eheight)5086 REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
5087                             REAL aheight, REAL bheight, REAL cheight,
5088                             REAL dheight, REAL eheight) {
5089 #ifdef USE_PCK // [Bruno]
5090 
5091     return REAL(GEO::PCK::orient_3dlifted_SOS(
5092                     pa,pb,pc,pd,pe,aheight,bheight,cheight,dheight,eheight
5093     ));
5094 
5095 #else
5096 
5097   REAL sign;
5098 
5099   sign = orient4d(pa, pb, pc, pd, pe,
5100                   aheight, bheight, cheight, dheight, eheight);
5101   if (sign != 0.0) {
5102     return sign;
5103   }
5104 
5105   // Symbolic perturbation.
5106   point pt[5], swappt;
5107   REAL oriA, oriB;
5108   int swaps, count;
5109   int n, i;
5110 
5111   pt[0] = pa;
5112   pt[1] = pb;
5113   pt[2] = pc;
5114   pt[3] = pd;
5115   pt[4] = pe;
5116 
5117   // Sort the five points such that their indices are in the increasing
5118   //   order. An optimized bubble sort algorithm is used, i.e., it has
5119   //   the worst case O(n^2) runtime, but it is usually much faster.
5120   swaps = 0; // Record the total number of swaps.
5121   n = 5;
5122   do {
5123     count = 0;
5124     n = n - 1;
5125     for (i = 0; i < n; i++) {
5126       if (pointmark(pt[i]) > pointmark(pt[i+1])) {
5127         swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
5128         count++;
5129       }
5130     }
5131     swaps += count;
5132   } while (count > 0); // Continue if some points are swapped.
5133 
5134   oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
5135   if (oriA != 0.0) {
5136     // Flip the sign if there are odd number of swaps.
5137     if ((swaps % 2) != 0) oriA = -oriA;
5138     return oriA;
5139   }
5140 
5141   oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
5142   assert(oriB != 0.0); // SELF_CHECK
5143   // Flip the sign if there are odd number of swaps.
5144   if ((swaps % 2) != 0) oriB = -oriB;
5145   return oriB;
5146 
5147 #endif
5148 }
5149 
5150 ///////////////////////////////////////////////////////////////////////////////
5151 //                                                                           //
5152 // tri_edge_test()    Triangle-edge intersection test.                       //
5153 //                                                                           //
5154 // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
5155 // Q) in 3D, and tests if they intersect each other.                         //
5156 //                                                                           //
5157 // If the point 'R' is not nullptr, it lies strictly above the plane defined by //
5158 // A, B, C. It is used in test when T and E are coplanar.                    //
5159 //                                                                           //
5160 // If T and E intersect each other, they may intersect in different ways. If //
5161 // 'level' > 0, their intersection type will be reported 'types' and 'pos'.  //
5162 //                                                                           //
5163 // The retrun value indicates one of the following cases:                    //
5164 //   - 0, T and E are disjoint.                                              //
5165 //   - 1, T and E intersect each other.                                      //
5166 //   - 2, T and E are not coplanar. They intersect at a single point.        //
5167 //   - 4, T and E are coplanar. They intersect at a single point or a line   //
5168 //        segment (if types[1] != DISJOINT).                                 //
5169 //                                                                           //
5170 ///////////////////////////////////////////////////////////////////////////////
5171 
5172 #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
5173 
5174 #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
5175 
tri_edge_2d(point A,point B,point C,point P,point Q,point R,int level,int * types,int * pos)5176 int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
5177                             point R, int level, int *types, int *pos)
5178 {
5179   point U[3], V[3];  // The permuted vectors of points.
5180   int pu[3], pv[3];  // The original positions of points.
5181   REAL abovept[3];
5182   REAL sA, sB, sC;
5183   REAL s1, s2, s3, s4;
5184   int z1;
5185 
5186   if (R == nullptr) {
5187     // Calculate a lift point.
5188     if (1) {
5189       REAL n[3], len;
5190       // Calculate a lift point, saved in dummypoint.
5191       facenormal(A, B, C, n, 1, nullptr);
5192       len = sqrt(dot(n, n));
5193       if (len != 0) {
5194         n[0] /= len;
5195         n[1] /= len;
5196         n[2] /= len;
5197         len = distance(A, B);
5198         len += distance(B, C);
5199         len += distance(C, A);
5200         len /= 3.0;
5201         R = abovept; //dummypoint;
5202         R[0] = A[0] + len * n[0];
5203         R[1] = A[1] + len * n[1];
5204         R[2] = A[2] + len * n[2];
5205       } else {
5206         // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
5207         //   to a line.  We need a line-line intersection test.
5208         //assert(0);
5209         // !!! A non-save return value.!!!
5210         return 0;  // DISJOINT
5211       }
5212     }
5213   }
5214 
5215   // Test A's, B's, and C's orientations wrt plane PQR.
5216   sA = orient3d(P, Q, R, A);
5217   sB = orient3d(P, Q, R, B);
5218   sC = orient3d(P, Q, R, C);
5219 
5220 
5221   if (sA < 0) {
5222     if (sB < 0) {
5223       if (sC < 0) { // (---).
5224         return 0;
5225       } else {
5226         if (sC > 0) { // (--+).
5227           // All points are in the right positions.
5228           SETVECTOR3(U, A, B, C);  // I3
5229           SETVECTOR3(V, P, Q, R);  // I2
5230           SETVECTOR3(pu, 0, 1, 2);
5231           SETVECTOR3(pv, 0, 1, 2);
5232           z1 = 0;
5233         } else { // (--0).
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 = 1;
5239         }
5240       }
5241     } else {
5242       if (sB > 0) {
5243         if (sC < 0) { // (-+-).
5244           SETVECTOR3(U, C, A, B);  // PT = ST
5245           SETVECTOR3(V, P, Q, R);  // I2
5246           SETVECTOR3(pu, 2, 0, 1);
5247           SETVECTOR3(pv, 0, 1, 2);
5248           z1 = 0;
5249         } else {
5250           if (sC > 0) { // (-++).
5251             SETVECTOR3(U, B, C, A);  // PT = ST x ST
5252             SETVECTOR3(V, Q, P, R);  // PL = SL
5253             SETVECTOR3(pu, 1, 2, 0);
5254             SETVECTOR3(pv, 1, 0, 2);
5255             z1 = 0;
5256           } else { // (-+0).
5257             SETVECTOR3(U, C, A, B);  // PT = ST
5258             SETVECTOR3(V, P, Q, R);  // I2
5259             SETVECTOR3(pu, 2, 0, 1);
5260             SETVECTOR3(pv, 0, 1, 2);
5261             z1 = 2;
5262           }
5263         }
5264       } else {
5265         if (sC < 0) { // (-0-).
5266           SETVECTOR3(U, C, A, B);  // PT = ST
5267           SETVECTOR3(V, P, Q, R);  // I2
5268           SETVECTOR3(pu, 2, 0, 1);
5269           SETVECTOR3(pv, 0, 1, 2);
5270           z1 = 1;
5271         } else {
5272           if (sC > 0) { // (-0+).
5273             SETVECTOR3(U, B, C, A);  // PT = ST x ST
5274             SETVECTOR3(V, Q, P, R);  // PL = SL
5275             SETVECTOR3(pu, 1, 2, 0);
5276             SETVECTOR3(pv, 1, 0, 2);
5277             z1 = 2;
5278           } else { // (-00).
5279             SETVECTOR3(U, B, C, A);  // PT = ST x ST
5280             SETVECTOR3(V, Q, P, R);  // PL = SL
5281             SETVECTOR3(pu, 1, 2, 0);
5282             SETVECTOR3(pv, 1, 0, 2);
5283             z1 = 3;
5284           }
5285         }
5286       }
5287     }
5288   } else {
5289     if (sA > 0) {
5290       if (sB < 0) {
5291         if (sC < 0) { // (+--).
5292           SETVECTOR3(U, B, C, A);  // PT = ST x ST
5293           SETVECTOR3(V, P, Q, R);  // I2
5294           SETVECTOR3(pu, 1, 2, 0);
5295           SETVECTOR3(pv, 0, 1, 2);
5296           z1 = 0;
5297         } else {
5298           if (sC > 0) { // (+-+).
5299             SETVECTOR3(U, C, A, B);  // PT = ST
5300             SETVECTOR3(V, Q, P, R);  // PL = SL
5301             SETVECTOR3(pu, 2, 0, 1);
5302             SETVECTOR3(pv, 1, 0, 2);
5303             z1 = 0;
5304           } else { // (+-0).
5305             SETVECTOR3(U, C, A, B);  // PT = ST
5306             SETVECTOR3(V, Q, P, R);  // PL = SL
5307             SETVECTOR3(pu, 2, 0, 1);
5308             SETVECTOR3(pv, 1, 0, 2);
5309             z1 = 2;
5310           }
5311         }
5312       } else {
5313         if (sB > 0) {
5314           if (sC < 0) { // (++-).
5315             SETVECTOR3(U, A, B, C);  // I3
5316             SETVECTOR3(V, Q, P, R);  // PL = SL
5317             SETVECTOR3(pu, 0, 1, 2);
5318             SETVECTOR3(pv, 1, 0, 2);
5319             z1 = 0;
5320           } else {
5321             if (sC > 0) { // (+++).
5322               return 0;
5323             } else { // (++0).
5324               SETVECTOR3(U, A, B, C);  // I3
5325               SETVECTOR3(V, Q, P, R);  // PL = SL
5326               SETVECTOR3(pu, 0, 1, 2);
5327               SETVECTOR3(pv, 1, 0, 2);
5328               z1 = 1;
5329             }
5330           }
5331         } else { // (+0#)
5332           if (sC < 0) { // (+0-).
5333             SETVECTOR3(U, B, C, A);  // PT = ST x ST
5334             SETVECTOR3(V, P, Q, R);  // I2
5335             SETVECTOR3(pu, 1, 2, 0);
5336             SETVECTOR3(pv, 0, 1, 2);
5337             z1 = 2;
5338           } else {
5339             if (sC > 0) { // (+0+).
5340               SETVECTOR3(U, C, A, B);  // PT = ST
5341               SETVECTOR3(V, Q, P, R);  // PL = SL
5342               SETVECTOR3(pu, 2, 0, 1);
5343               SETVECTOR3(pv, 1, 0, 2);
5344               z1 = 1;
5345             } else { // (+00).
5346               SETVECTOR3(U, B, C, A);  // PT = ST x ST
5347               SETVECTOR3(V, P, Q, R);  // I2
5348               SETVECTOR3(pu, 1, 2, 0);
5349               SETVECTOR3(pv, 0, 1, 2);
5350               z1 = 3;
5351             }
5352           }
5353         }
5354       }
5355     } else {
5356       if (sB < 0) {
5357         if (sC < 0) { // (0--).
5358           SETVECTOR3(U, B, C, A);  // PT = ST x ST
5359           SETVECTOR3(V, P, Q, R);  // I2
5360           SETVECTOR3(pu, 1, 2, 0);
5361           SETVECTOR3(pv, 0, 1, 2);
5362           z1 = 1;
5363         } else {
5364           if (sC > 0) { // (0-+).
5365             SETVECTOR3(U, A, B, C);  // I3
5366             SETVECTOR3(V, P, Q, R);  // I2
5367             SETVECTOR3(pu, 0, 1, 2);
5368             SETVECTOR3(pv, 0, 1, 2);
5369             z1 = 2;
5370           } else { // (0-0).
5371             SETVECTOR3(U, C, A, B);  // PT = ST
5372             SETVECTOR3(V, Q, P, R);  // PL = SL
5373             SETVECTOR3(pu, 2, 0, 1);
5374             SETVECTOR3(pv, 1, 0, 2);
5375             z1 = 3;
5376           }
5377         }
5378       } else {
5379         if (sB > 0) {
5380           if (sC < 0) { // (0+-).
5381             SETVECTOR3(U, A, B, C);  // I3
5382             SETVECTOR3(V, Q, P, R);  // PL = SL
5383             SETVECTOR3(pu, 0, 1, 2);
5384             SETVECTOR3(pv, 1, 0, 2);
5385             z1 = 2;
5386           } else {
5387             if (sC > 0) { // (0++).
5388               SETVECTOR3(U, B, C, A);  // PT = ST x ST
5389               SETVECTOR3(V, Q, P, R);  // PL = SL
5390               SETVECTOR3(pu, 1, 2, 0);
5391               SETVECTOR3(pv, 1, 0, 2);
5392               z1 = 1;
5393             } else { // (0+0).
5394               SETVECTOR3(U, C, A, B);  // PT = ST
5395               SETVECTOR3(V, P, Q, R);  // I2
5396               SETVECTOR3(pu, 2, 0, 1);
5397               SETVECTOR3(pv, 0, 1, 2);
5398               z1 = 3;
5399             }
5400           }
5401         } else { // (00#)
5402           if (sC < 0) { // (00-).
5403             SETVECTOR3(U, A, B, C);  // I3
5404             SETVECTOR3(V, Q, P, R);  // PL = SL
5405             SETVECTOR3(pu, 0, 1, 2);
5406             SETVECTOR3(pv, 1, 0, 2);
5407             z1 = 3;
5408           } else {
5409             if (sC > 0) { // (00+).
5410               SETVECTOR3(U, A, B, C);  // I3
5411               SETVECTOR3(V, P, Q, R);  // I2
5412               SETVECTOR3(pu, 0, 1, 2);
5413               SETVECTOR3(pv, 0, 1, 2);
5414               z1 = 3;
5415             } else { // (000)
5416               // Not possible unless ABC is degenerate.
5417               // Avoiding compiler warnings.
5418               SETVECTOR3(U, A, B, C);  // I3
5419               SETVECTOR3(V, P, Q, R);  // I2
5420               SETVECTOR3(pu, 0, 1, 2);
5421               SETVECTOR3(pv, 0, 1, 2);
5422               z1 = 4;
5423             }
5424           }
5425         }
5426       }
5427     }
5428   }
5429 
5430   s1 = orient3d(U[0], U[2], R, V[1]);  // A, C, R, Q
5431   s2 = orient3d(U[1], U[2], R, V[0]);  // B, C, R, P
5432 
5433   if (s1 > 0) {
5434     return 0;
5435   }
5436   if (s2 < 0) {
5437     return 0;
5438   }
5439 
5440   if (level == 0) {
5441     return 1;  // They are intersected.
5442   }
5443 
5444   assert(z1 != 4); // SELF_CHECK
5445 
5446   if (z1 == 1) {
5447     if (s1 == 0) {  // (0###)
5448       // C = Q.
5449       types[0] = (int) SHAREVERT;
5450       pos[0] = pu[2]; // C
5451       pos[1] = pv[1]; // Q
5452       types[1] = (int) DISJOINT;
5453     } else {
5454       if (s2 == 0) { // (#0##)
5455         // C = P.
5456         types[0] = (int) SHAREVERT;
5457         pos[0] = pu[2]; // C
5458         pos[1] = pv[0]; // P
5459         types[1] = (int) DISJOINT;
5460       } else { // (-+##)
5461         // C in [P, Q].
5462         types[0] = (int) ACROSSVERT;
5463         pos[0] = pu[2]; // C
5464         pos[1] = pv[0]; // [P, Q]
5465         types[1] = (int) DISJOINT;
5466       }
5467     }
5468     return 4;
5469   }
5470 
5471   s3 = orient3d(U[0], U[2], R, V[0]);  // A, C, R, P
5472   s4 = orient3d(U[1], U[2], R, V[1]);  // B, C, R, Q
5473 
5474   if (z1 == 0) {  // (tritri-03)
5475     if (s1 < 0) {
5476       if (s3 > 0) {
5477         assert(s2 > 0); // SELF_CHECK
5478         if (s4 > 0) {
5479           // [P, Q] overlaps [k, l] (-+++).
5480           types[0] = (int) ACROSSEDGE;
5481           pos[0] = pu[2]; // [C, A]
5482           pos[1] = pv[0]; // [P, Q]
5483           types[1] = (int) TOUCHFACE;
5484           pos[2] = 3;     // [A, B, C]
5485           pos[3] = pv[1]; // Q
5486         } else {
5487           if (s4 == 0) {
5488             // Q = l, [P, Q] contains [k, l] (-++0).
5489             types[0] = (int) ACROSSEDGE;
5490             pos[0] = pu[2]; // [C, A]
5491             pos[1] = pv[0]; // [P, Q]
5492             types[1] = (int) TOUCHEDGE;
5493             pos[2] = pu[1]; // [B, C]
5494             pos[3] = pv[1]; // Q
5495           } else { // s4 < 0
5496             // [P, Q] contains [k, l] (-++-).
5497             types[0] = (int) ACROSSEDGE;
5498             pos[0] = pu[2]; // [C, A]
5499             pos[1] = pv[0]; // [P, Q]
5500             types[1] = (int) ACROSSEDGE;
5501             pos[2] = pu[1]; // [B, C]
5502             pos[3] = pv[0]; // [P, Q]
5503           }
5504         }
5505       } else {
5506         if (s3 == 0) {
5507           assert(s2 > 0); // SELF_CHECK
5508           if (s4 > 0) {
5509             // P = k, [P, Q] in [k, l] (-+0+).
5510             types[0] = (int) TOUCHEDGE;
5511             pos[0] = pu[2]; // [C, A]
5512             pos[1] = pv[0]; // P
5513             types[1] = (int) TOUCHFACE;
5514             pos[2] = 3;     // [A, B, C]
5515             pos[3] = pv[1]; // Q
5516           } else {
5517             if (s4 == 0) {
5518               // [P, Q] = [k, l] (-+00).
5519               types[0] = (int) TOUCHEDGE;
5520               pos[0] = pu[2]; // [C, A]
5521               pos[1] = pv[0]; // P
5522               types[1] = (int) TOUCHEDGE;
5523               pos[2] = pu[1]; // [B, C]
5524               pos[3] = pv[1]; // Q
5525             } else {
5526               // P = k, [P, Q] contains [k, l] (-+0-).
5527               types[0] = (int) TOUCHEDGE;
5528               pos[0] = pu[2]; // [C, A]
5529               pos[1] = pv[0]; // P
5530               types[1] = (int) ACROSSEDGE;
5531               pos[2] = pu[1]; // [B, C]
5532               pos[3] = pv[0]; // [P, Q]
5533             }
5534           }
5535         } else { // s3 < 0
5536           if (s2 > 0) {
5537             if (s4 > 0) {
5538               // [P, Q] in [k, l] (-+-+).
5539               types[0] = (int) TOUCHFACE;
5540               pos[0] = 3;     // [A, B, C]
5541               pos[1] = pv[0]; // P
5542               types[1] = (int) TOUCHFACE;
5543               pos[2] = 3;     // [A, B, C]
5544               pos[3] = pv[1]; // Q
5545             } else {
5546               if (s4 == 0) {
5547                 // Q = l, [P, Q] in [k, l] (-+-0).
5548                 types[0] = (int) TOUCHFACE;
5549                 pos[0] = 3;     // [A, B, C]
5550                 pos[1] = pv[0]; // P
5551                 types[1] = (int) TOUCHEDGE;
5552                 pos[2] = pu[1]; // [B, C]
5553                 pos[3] = pv[1]; // Q
5554               } else { // s4 < 0
5555                 // [P, Q] overlaps [k, l] (-+--).
5556                 types[0] = (int) TOUCHFACE;
5557                 pos[0] = 3;     // [A, B, C]
5558                 pos[1] = pv[0]; // P
5559                 types[1] = (int) ACROSSEDGE;
5560                 pos[2] = pu[1]; // [B, C]
5561                 pos[3] = pv[0]; // [P, Q]
5562               }
5563             }
5564           } else { // s2 == 0
5565             // P = l (#0##).
5566             types[0] = (int) TOUCHEDGE;
5567             pos[0] = pu[1]; // [B, C]
5568             pos[1] = pv[0]; // P
5569             types[1] = (int) DISJOINT;
5570           }
5571         }
5572       }
5573     } else { // s1 == 0
5574       // Q = k (0####)
5575       types[0] = (int) TOUCHEDGE;
5576       pos[0] = pu[2]; // [C, A]
5577       pos[1] = pv[1]; // Q
5578       types[1] = (int) DISJOINT;
5579     }
5580   } else if (z1 == 2) {  // (tritri-23)
5581     if (s1 < 0) {
5582       if (s3 > 0) {
5583         assert(s2 > 0); // SELF_CHECK
5584         if (s4 > 0) {
5585           // [P, Q] overlaps [A, l] (-+++).
5586           types[0] = (int) ACROSSVERT;
5587           pos[0] = pu[0]; // A
5588           pos[1] = pv[0]; // [P, Q]
5589           types[1] = (int) TOUCHFACE;
5590           pos[2] = 3;     // [A, B, C]
5591           pos[3] = pv[1]; // Q
5592         } else {
5593           if (s4 == 0) {
5594             // Q = l, [P, Q] contains [A, l] (-++0).
5595             types[0] = (int) ACROSSVERT;
5596             pos[0] = pu[0]; // A
5597             pos[1] = pv[0]; // [P, Q]
5598             types[1] = (int) TOUCHEDGE;
5599             pos[2] = pu[1]; // [B, C]
5600             pos[3] = pv[1]; // Q
5601           } else { // s4 < 0
5602             // [P, Q] contains [A, l] (-++-).
5603             types[0] = (int) ACROSSVERT;
5604             pos[0] = pu[0]; // A
5605             pos[1] = pv[0]; // [P, Q]
5606             types[1] = (int) ACROSSEDGE;
5607             pos[2] = pu[1]; // [B, C]
5608             pos[3] = pv[0]; // [P, Q]
5609           }
5610         }
5611       } else {
5612         if (s3 == 0) {
5613           assert(s2 > 0); // SELF_CHECK
5614           if (s4 > 0) {
5615             // P = A, [P, Q] in [A, l] (-+0+).
5616             types[0] = (int) SHAREVERT;
5617             pos[0] = pu[0]; // A
5618             pos[1] = pv[0]; // P
5619             types[1] = (int) TOUCHFACE;
5620             pos[2] = 3;     // [A, B, C]
5621             pos[3] = pv[1]; // Q
5622           } else {
5623             if (s4 == 0) {
5624               // [P, Q] = [A, l] (-+00).
5625               types[0] = (int) SHAREVERT;
5626               pos[0] = pu[0]; // A
5627               pos[1] = pv[0]; // P
5628               types[1] = (int) TOUCHEDGE;
5629               pos[2] = pu[1]; // [B, C]
5630               pos[3] = pv[1]; // Q
5631             } else { // s4 < 0
5632               // Q = l, [P, Q] in [A, l] (-+0-).
5633               types[0] = (int) SHAREVERT;
5634               pos[0] = pu[0]; // A
5635               pos[1] = pv[0]; // P
5636               types[1] = (int) ACROSSEDGE;
5637               pos[2] = pu[1]; // [B, C]
5638               pos[3] = pv[0]; // [P, Q]
5639             }
5640           }
5641         } else { // s3 < 0
5642           if (s2 > 0) {
5643             if (s4 > 0) {
5644               // [P, Q] in [A, l] (-+-+).
5645               types[0] = (int) TOUCHFACE;
5646               pos[0] = 3;     // [A, B, C]
5647               pos[1] = pv[0]; // P
5648               types[0] = (int) TOUCHFACE;
5649               pos[0] = 3;     // [A, B, C]
5650               pos[1] = pv[1]; // Q
5651             } else {
5652               if (s4 == 0) {
5653                 // Q = l, [P, Q] in [A, l] (-+-0).
5654                 types[0] = (int) TOUCHFACE;
5655                 pos[0] = 3;     // [A, B, C]
5656                 pos[1] = pv[0]; // P
5657                 types[0] = (int) TOUCHEDGE;
5658                 pos[0] = pu[1]; // [B, C]
5659                 pos[1] = pv[1]; // Q
5660               } else { // s4 < 0
5661                 // [P, Q] overlaps [A, l] (-+--).
5662                 types[0] = (int) TOUCHFACE;
5663                 pos[0] = 3;     // [A, B, C]
5664                 pos[1] = pv[0]; // P
5665                 types[0] = (int) ACROSSEDGE;
5666                 pos[0] = pu[1]; // [B, C]
5667                 pos[1] = pv[0]; // [P, Q]
5668               }
5669             }
5670           } else { // s2 == 0
5671             // P = l (#0##).
5672             types[0] = (int) TOUCHEDGE;
5673             pos[0] = pu[1]; // [B, C]
5674             pos[1] = pv[0]; // P
5675             types[1] = (int) DISJOINT;
5676           }
5677         }
5678       }
5679     } else { // s1 == 0
5680       // Q = A (0###).
5681       types[0] = (int) SHAREVERT;
5682       pos[0] = pu[0]; // A
5683       pos[1] = pv[1]; // Q
5684       types[1] = (int) DISJOINT;
5685     }
5686   } else if (z1 == 3) {  // (tritri-33)
5687     if (s1 < 0) {
5688       if (s3 > 0) {
5689         assert(s2 > 0); // SELF_CHECK
5690         if (s4 > 0) {
5691           // [P, Q] overlaps [A, B] (-+++).
5692           types[0] = (int) ACROSSVERT;
5693           pos[0] = pu[0]; // A
5694           pos[1] = pv[0]; // [P, Q]
5695           types[1] = (int) TOUCHEDGE;
5696           pos[2] = pu[0]; // [A, B]
5697           pos[3] = pv[1]; // Q
5698         } else {
5699           if (s4 == 0) {
5700             // Q = B, [P, Q] contains [A, B] (-++0).
5701             types[0] = (int) ACROSSVERT;
5702             pos[0] = pu[0]; // A
5703             pos[1] = pv[0]; // [P, Q]
5704             types[1] = (int) SHAREVERT;
5705             pos[2] = pu[1]; // B
5706             pos[3] = pv[1]; // Q
5707           } else { // s4 < 0
5708             // [P, Q] contains [A, B] (-++-).
5709             types[0] = (int) ACROSSVERT;
5710             pos[0] = pu[0]; // A
5711             pos[1] = pv[0]; // [P, Q]
5712             types[1] = (int) ACROSSVERT;
5713             pos[2] = pu[1]; // B
5714             pos[3] = pv[0]; // [P, Q]
5715           }
5716         }
5717       } else {
5718         if (s3 == 0) {
5719           assert(s2 > 0); // SELF_CHECK
5720           if (s4 > 0) {
5721             // P = A, [P, Q] in [A, B] (-+0+).
5722             types[0] = (int) SHAREVERT;
5723             pos[0] = pu[0]; // A
5724             pos[1] = pv[0]; // P
5725             types[1] = (int) TOUCHEDGE;
5726             pos[2] = pu[0]; // [A, B]
5727             pos[3] = pv[1]; // Q
5728           } else {
5729             if (s4 == 0) {
5730               // [P, Q] = [A, B] (-+00).
5731               types[0] = (int) SHAREEDGE;
5732               pos[0] = pu[0]; // [A, B]
5733               pos[1] = pv[0]; // [P, Q]
5734               types[1] = (int) DISJOINT;
5735             } else { // s4 < 0
5736               // P= A, [P, Q] in [A, B] (-+0-).
5737               types[0] = (int) SHAREVERT;
5738               pos[0] = pu[0]; // A
5739               pos[1] = pv[0]; // P
5740               types[1] = (int) ACROSSVERT;
5741               pos[2] = pu[1]; // B
5742               pos[3] = pv[0]; // [P, Q]
5743             }
5744           }
5745         } else { // s3 < 0
5746           if (s2 > 0) {
5747             if (s4 > 0) {
5748               // [P, Q] in [A, B] (-+-+).
5749               types[0] = (int) TOUCHEDGE;
5750               pos[0] = pu[0]; // [A, B]
5751               pos[1] = pv[0]; // P
5752               types[1] = (int) TOUCHEDGE;
5753               pos[2] = pu[0]; // [A, B]
5754               pos[3] = pv[1]; // Q
5755             } else {
5756               if (s4 == 0) {
5757                 // Q = B, [P, Q] in [A, B] (-+-0).
5758                 types[0] = (int) TOUCHEDGE;
5759                 pos[0] = pu[0]; // [A, B]
5760                 pos[1] = pv[0]; // P
5761                 types[1] = (int) SHAREVERT;
5762                 pos[2] = pu[1]; // B
5763                 pos[3] = pv[1]; // Q
5764               } else { // s4 < 0
5765                 // [P, Q] overlaps [A, B] (-+--).
5766                 types[0] = (int) TOUCHEDGE;
5767                 pos[0] = pu[0]; // [A, B]
5768                 pos[1] = pv[0]; // P
5769                 types[1] = (int) ACROSSVERT;
5770                 pos[2] = pu[1]; // B
5771                 pos[3] = pv[0]; // [P, Q]
5772               }
5773             }
5774           } else { // s2 == 0
5775             // P = B (#0##).
5776             types[0] = (int) SHAREVERT;
5777             pos[0] = pu[1]; // B
5778             pos[1] = pv[0]; // P
5779             types[1] = (int) DISJOINT;
5780           }
5781         }
5782       }
5783     } else { // s1 == 0
5784       // Q = A (0###).
5785       types[0] = (int) SHAREVERT;
5786       pos[0] = pu[0]; // A
5787       pos[1] = pv[1]; // Q
5788       types[1] = (int) DISJOINT;
5789     }
5790   }
5791 
5792   return 4;
5793 }
5794 
tri_edge_tail(point A,point B,point C,point P,point Q,point R,REAL sP,REAL sQ,int level,int * types,int * pos)5795 int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
5796                               REAL sP,REAL sQ,int level,int *types,int *pos)
5797 {
5798   point U[3], V[3]; //, Ptmp;
5799   int pu[3], pv[3]; //, itmp;
5800   REAL s1, s2, s3;
5801   int z1;
5802 
5803 
5804   if (sP < 0) {
5805     if (sQ < 0) { // (--) disjoint
5806       return 0;
5807     } else {
5808       if (sQ > 0) { // (-+)
5809         SETVECTOR3(U, A, B, C);
5810         SETVECTOR3(V, P, Q, R);
5811         SETVECTOR3(pu, 0, 1, 2);
5812         SETVECTOR3(pv, 0, 1, 2);
5813         z1 = 0;
5814       } else { // (-0)
5815         SETVECTOR3(U, A, B, C);
5816         SETVECTOR3(V, P, Q, R);
5817         SETVECTOR3(pu, 0, 1, 2);
5818         SETVECTOR3(pv, 0, 1, 2);
5819         z1 = 1;
5820       }
5821     }
5822   } else {
5823     if (sP > 0) { // (+-)
5824       if (sQ < 0) {
5825         SETVECTOR3(U, A, B, C);
5826         SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
5827         SETVECTOR3(pu, 0, 1, 2);
5828         SETVECTOR3(pv, 1, 0, 2);
5829         z1 = 0;
5830       } else {
5831         if (sQ > 0) { // (++) disjoint
5832           return 0;
5833         } else { // (+0)
5834           SETVECTOR3(U, B, A, C); // A and B are flipped.
5835           SETVECTOR3(V, P, Q, R);
5836           SETVECTOR3(pu, 1, 0, 2);
5837           SETVECTOR3(pv, 0, 1, 2);
5838           z1 = 1;
5839         }
5840       }
5841     } else { // sP == 0
5842       if (sQ < 0) { // (0-)
5843         SETVECTOR3(U, A, B, C);
5844         SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
5845         SETVECTOR3(pu, 0, 1, 2);
5846         SETVECTOR3(pv, 1, 0, 2);
5847         z1 = 1;
5848       } else {
5849         if (sQ > 0) { // (0+)
5850           SETVECTOR3(U, B, A, C);  // A and B are flipped.
5851           SETVECTOR3(V, Q, P, R);  // P and Q are flipped.
5852           SETVECTOR3(pu, 1, 0, 2);
5853           SETVECTOR3(pv, 1, 0, 2);
5854           z1 = 1;
5855         } else { // (00)
5856           // A, B, C, P, and Q are coplanar.
5857           z1 = 2;
5858         }
5859       }
5860     }
5861   }
5862 
5863   if (z1 == 2) {
5864     // The triangle and the edge are coplanar.
5865     return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
5866   }
5867 
5868   s1 = orient3d(U[0], U[1], V[0], V[1]);
5869   if (s1 < 0) {
5870     return 0;
5871   }
5872 
5873   s2 = orient3d(U[1], U[2], V[0], V[1]);
5874   if (s2 < 0) {
5875     return 0;
5876   }
5877 
5878   s3 = orient3d(U[2], U[0], V[0], V[1]);
5879   if (s3 < 0) {
5880     return 0;
5881   }
5882 
5883   if (level == 0) {
5884     return 1;  // The are intersected.
5885   }
5886 
5887   types[1] = (int) DISJOINT; // No second intersection point.
5888 
5889   if (z1 == 0) {
5890     if (s1 > 0) {
5891       if (s2 > 0) {
5892         if (s3 > 0) { // (+++)
5893           // [P, Q] passes interior of [A, B, C].
5894           types[0] = (int) ACROSSFACE;
5895           pos[0] = 3;  // interior of [A, B, C]
5896           pos[1] = 0;  // [P, Q]
5897         } else { // s3 == 0 (++0)
5898           // [P, Q] intersects [C, A].
5899           types[0] = (int) ACROSSEDGE;
5900           pos[0] = pu[2];  // [C, A]
5901           pos[1] = 0;  // [P, Q]
5902         }
5903       } else { // s2 == 0
5904         if (s3 > 0) { // (+0+)
5905           // [P, Q] intersects [B, C].
5906           types[0] = (int) ACROSSEDGE;
5907           pos[0] = pu[1];  // [B, C]
5908           pos[1] = 0;  // [P, Q]
5909         } else { // s3 == 0 (+00)
5910           // [P, Q] passes C.
5911           types[0] = (int) ACROSSVERT;
5912           pos[0] = pu[2];  // C
5913           pos[1] = 0;  // [P, Q]
5914         }
5915       }
5916     } else { // s1 == 0
5917       if (s2 > 0) {
5918         if (s3 > 0) { // (0++)
5919           // [P, Q] intersects [A, B].
5920           types[0] = (int) ACROSSEDGE;
5921           pos[0] = pu[0];  // [A, B]
5922           pos[1] = 0;  // [P, Q]
5923         } else { // s3 == 0 (0+0)
5924           // [P, Q] passes A.
5925           types[0] = (int) ACROSSVERT;
5926           pos[0] = pu[0];  // A
5927           pos[1] = 0;  // [P, Q]
5928         }
5929       } else { // s2 == 0
5930         if (s3 > 0) { // (00+)
5931           // [P, Q] passes B.
5932           types[0] = (int) ACROSSVERT;
5933           pos[0] = pu[1];  // B
5934           pos[1] = 0;  // [P, Q]
5935         } else { // s3 == 0 (000)
5936           // Impossible.
5937           assert(0);
5938         }
5939       }
5940     }
5941   } else { // z1 == 1
5942     if (s1 > 0) {
5943       if (s2 > 0) {
5944         if (s3 > 0) { // (+++)
5945           // Q lies in [A, B, C].
5946           types[0] = (int) TOUCHFACE;
5947           pos[0] = 0; // [A, B, C]
5948           pos[1] = pv[1]; // Q
5949         } else { // s3 == 0 (++0)
5950           // Q lies on [C, A].
5951           types[0] = (int) TOUCHEDGE;
5952           pos[0] = pu[2]; // [C, A]
5953           pos[1] = pv[1]; // Q
5954         }
5955       } else { // s2 == 0
5956         if (s3 > 0) { // (+0+)
5957           // Q lies on [B, C].
5958           types[0] = (int) TOUCHEDGE;
5959           pos[0] = pu[1]; // [B, C]
5960           pos[1] = pv[1]; // Q
5961         } else { // s3 == 0 (+00)
5962           // Q = C.
5963           types[0] = (int) SHAREVERT;
5964           pos[0] = pu[2]; // C
5965           pos[1] = pv[1]; // Q
5966         }
5967       }
5968     } else { // s1 == 0
5969       if (s2 > 0) {
5970         if (s3 > 0) { // (0++)
5971           // Q lies on [A, B].
5972           types[0] = (int) TOUCHEDGE;
5973           pos[0] = pu[0]; // [A, B]
5974           pos[1] = pv[1]; // Q
5975         } else { // s3 == 0 (0+0)
5976           // Q = A.
5977           types[0] = (int) SHAREVERT;
5978           pos[0] = pu[0]; // A
5979           pos[1] = pv[1]; // Q
5980         }
5981       } else { // s2 == 0
5982         if (s3 > 0) { // (00+)
5983           // Q = B.
5984           types[0] = (int) SHAREVERT;
5985           pos[0] = pu[1]; // B
5986           pos[1] = pv[1]; // Q
5987         } else { // s3 == 0 (000)
5988           // Impossible.
5989           assert(0);
5990         }
5991       }
5992     }
5993   }
5994 
5995   // T and E intersect in a single point.
5996   return 2;
5997 }
5998 
tri_edge_test(point A,point B,point C,point P,point Q,point R,int level,int * types,int * pos)5999 int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q,
6000                               point R, int level, int *types, int *pos)
6001 {
6002   REAL sP, sQ;
6003 
6004   // Test the locations of P and Q with respect to ABC.
6005   sP = orient3d(A, B, C, P);
6006   sQ = orient3d(A, B, C, Q);
6007 
6008   return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
6009 }
6010 
6011 ///////////////////////////////////////////////////////////////////////////////
6012 //                                                                           //
6013 // tri_tri_inter()    Test whether two triangle (abc) and (opq) are          //
6014 //                    intersecting or not.                                   //
6015 //                                                                           //
6016 // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
6017 // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT.         //
6018 //                                                                           //
6019 ///////////////////////////////////////////////////////////////////////////////
6020 
tri_edge_inter_tail(REAL * A,REAL * B,REAL * C,REAL * P,REAL * Q,REAL s_p,REAL s_q)6021 int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C,  REAL* P,
6022                                     REAL* Q, REAL s_p, REAL s_q)
6023 {
6024   int types[2], pos[4];
6025   int ni;  // =0, 2, 4
6026 
6027   ni = tri_edge_tail(A, B, C, P, Q, nullptr, s_p, s_q, 1, types, pos);
6028 
6029   if (ni > 0) {
6030     if (ni == 2) {
6031       // Get the intersection type.
6032       if (types[0] == (int) SHAREVERT) {
6033         return (int) SHAREVERT;
6034       } else {
6035         return (int) INTERSECT;
6036       }
6037     } else if (ni == 4) {
6038       // There may be two intersections.
6039       if (types[0] == (int) SHAREVERT) {
6040         if (types[1] == (int) DISJOINT) {
6041           return (int) SHAREVERT;
6042         } else {
6043           assert(types[1] != (int) SHAREVERT);
6044           return (int) INTERSECT;
6045         }
6046       } else {
6047         if (types[0] == (int) SHAREEDGE) {
6048           return (int) SHAREEDGE;
6049         } else {
6050           return (int) INTERSECT;
6051         }
6052       }
6053     } else {
6054       assert(0);
6055     }
6056   }
6057 
6058   return (int) DISJOINT;
6059 }
6060 
tri_tri_inter(REAL * A,REAL * B,REAL * C,REAL * O,REAL * P,REAL * Q)6061 int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
6062 {
6063   REAL s_o, s_p, s_q;
6064   REAL s_a, s_b, s_c;
6065 
6066   s_o = orient3d(A, B, C, O);
6067   s_p = orient3d(A, B, C, P);
6068   s_q = orient3d(A, B, C, Q);
6069   if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
6070     // o, p, q are all in the same halfspace of ABC.
6071     return 0; // DISJOINT;
6072   }
6073 
6074   s_a = orient3d(O, P, Q, A);
6075   s_b = orient3d(O, P, Q, B);
6076   s_c = orient3d(O, P, Q, C);
6077   if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
6078     // a, b, c are all in the same halfspace of OPQ.
6079     return 0; // DISJOINT;
6080   }
6081 
6082   int abcop, abcpq, abcqo;
6083   int shareedge = 0;
6084 
6085   abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
6086   if (abcop == (int) INTERSECT) {
6087     return (int) INTERSECT;
6088   } else if (abcop == (int) SHAREEDGE) {
6089     shareedge++;
6090   }
6091   abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
6092   if (abcpq == (int) INTERSECT) {
6093     return (int) INTERSECT;
6094   } else if (abcpq == (int) SHAREEDGE) {
6095     shareedge++;
6096   }
6097   abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
6098   if (abcqo == (int) INTERSECT) {
6099     return (int) INTERSECT;
6100   } else if (abcqo == (int) SHAREEDGE) {
6101     shareedge++;
6102   }
6103   if (shareedge == 3) {
6104     // opq are coincident with abc.
6105     return (int) SHAREFACE;
6106   }
6107 
6108   // It is only possible either no share edge or one.
6109   assert(shareedge == 0 || shareedge == 1);
6110 
6111   // Continue to detect whether opq and abc are intersecting or not.
6112   int opqab, opqbc, opqca;
6113 
6114   opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
6115   if (opqab == (int) INTERSECT) {
6116     return (int) INTERSECT;
6117   }
6118   opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
6119   if (opqbc == (int) INTERSECT) {
6120     return (int) INTERSECT;
6121   }
6122   opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
6123   if (opqca == (int) INTERSECT) {
6124     return (int) INTERSECT;
6125   }
6126 
6127   // At this point, two triangles are not intersecting and not coincident.
6128   //   They may be share an edge, or share a vertex, or disjoint.
6129   if (abcop == (int) SHAREEDGE) {
6130     assert((abcpq == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
6131     // op is coincident with an edge of abc.
6132     return (int) SHAREEDGE;
6133   }
6134   if (abcpq == (int) SHAREEDGE) {
6135     assert((abcop == (int) SHAREVERT) && (abcqo == (int) SHAREVERT));
6136     // pq is coincident with an edge of abc.
6137     return (int) SHAREEDGE;
6138   }
6139   if (abcqo == (int) SHAREEDGE) {
6140     assert((abcop == (int) SHAREVERT) && (abcpq == (int) SHAREVERT));
6141     // qo is coincident with an edge of abc.
6142     return (int) SHAREEDGE;
6143   }
6144 
6145   // They may share a vertex or disjoint.
6146   if (abcop == (int) SHAREVERT) {
6147     // o or p is coincident with a vertex of abc.
6148     if (abcpq == (int) SHAREVERT) {
6149       // p is the coincident vertex.
6150       assert(abcqo != (int) SHAREVERT);
6151     } else {
6152       // o is the coincident vertex.
6153       assert(abcqo == (int) SHAREVERT);
6154     }
6155     return (int) SHAREVERT;
6156   }
6157   if (abcpq == (int) SHAREVERT) {
6158     // q is the coincident vertex.
6159     assert(abcqo == (int) SHAREVERT);
6160     return (int) SHAREVERT;
6161   }
6162 
6163   // They are disjoint.
6164   return (int) DISJOINT;
6165 }
6166 
6167 ///////////////////////////////////////////////////////////////////////////////
6168 //                                                                           //
6169 // lu_decmp()    Compute the LU decomposition of a matrix.                   //
6170 //                                                                           //
6171 // Compute the LU decomposition of a (non-singular) square matrix A using    //
6172 // partial pivoting and implicit row exchanges.  The result is:              //
6173 //     A = P * L * U,                                                        //
6174 // where P is a permutation matrix, L is unit lower triangular, and U is     //
6175 // upper triangular.  The factored form of A is used in combination with     //
6176 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix.       //
6177 //                                                                           //
6178 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
6179 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
6180 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row   //
6181 // permutation effected by the partial pivoting, effectively,  'ps' array    //
6182 // tells the user what the permutation matrix P is; 'd' is output as +1/-1   //
6183 // depending on whether the number of row interchanges was even or odd,      //
6184 // respectively.                                                             //
6185 //                                                                           //
6186 // Return true if the LU decomposition is successfully computed, otherwise,  //
6187 // return false in case that A is a singular matrix.                         //
6188 //                                                                           //
6189 ///////////////////////////////////////////////////////////////////////////////
6190 
lu_decmp(REAL lu[4][4],int n,int * ps,REAL * d,int N)6191 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6192 {
6193   REAL scales[4];
6194   REAL pivot, biggest, mult, tempf;
6195   int pivotindex = 0;
6196   int i, j, k;
6197 
6198   *d = 1.0;                                      // No row interchanges yet.
6199 
6200   for (i = N; i < n + N; i++) {                             // For each row.
6201     // Find the largest element in each row for row equilibration
6202     biggest = 0.0;
6203     for (j = N; j < n + N; j++)
6204       if (biggest < (tempf = fabs(lu[i][j])))
6205         biggest  = tempf;
6206     if (biggest != 0.0)
6207       scales[i] = 1.0 / biggest;
6208     else {
6209       scales[i] = 0.0;
6210       return false;                            // Zero row: singular matrix.
6211     }
6212     ps[i] = i;                                 // Initialize pivot sequence.
6213   }
6214 
6215   for (k = N; k < n + N - 1; k++) {                      // For each column.
6216     // Find the largest element in each column to pivot around.
6217     biggest = 0.0;
6218     for (i = k; i < n + N; i++) {
6219       if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6220         biggest = tempf;
6221         pivotindex = i;
6222       }
6223     }
6224     if (biggest == 0.0) {
6225       return false;                         // Zero column: singular matrix.
6226     }
6227     if (pivotindex != k) {                         // Update pivot sequence.
6228       j = ps[k];
6229       ps[k] = ps[pivotindex];
6230       ps[pivotindex] = j;
6231       *d = -(*d);                          // ...and change the parity of d.
6232     }
6233 
6234     // Pivot, eliminating an extra variable  each time
6235     pivot = lu[ps[k]][k];
6236     for (i = k + 1; i < n + N; i++) {
6237       lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6238       if (mult != 0.0) {
6239         for (j = k + 1; j < n + N; j++)
6240           lu[ps[i]][j] -= mult * lu[ps[k]][j];
6241       }
6242     }
6243   }
6244 
6245   // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6246   return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6247 }
6248 
6249 ///////////////////////////////////////////////////////////////////////////////
6250 //                                                                           //
6251 // lu_solve()    Solves the linear equation:  Ax = b,  after the matrix A    //
6252 //               has been decomposed into the lower and upper triangular     //
6253 //               matrices L and U, where A = LU.                             //
6254 //                                                                           //
6255 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as    //
6256 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]'  //
6257 // is input as the permutation vector returned by 'lu_decmp';  'b[N..n+N-1]' //
6258 // is input as the right-hand side vector, and returns with the solution     //
6259 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be   //
6260 // left in place for successive calls with different right-hand sides 'b'.   //
6261 //                                                                           //
6262 ///////////////////////////////////////////////////////////////////////////////
6263 
lu_solve(REAL lu[4][4],int n,int * ps,REAL * b,int N)6264 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6265 {
6266   int i, j;
6267   REAL X[4], dot;
6268 
6269   for (i = N; i < n + N; i++) X[i] = 0.0;
6270 
6271   // Vector reduction using U triangular matrix.
6272   for (i = N; i < n + N; i++) {
6273     dot = 0.0;
6274     for (j = N; j < i + N; j++)
6275       dot += lu[ps[i]][j] * X[j];
6276     X[i] = b[ps[i]] - dot;
6277   }
6278 
6279   // Back substitution, in L triangular matrix.
6280   for (i = n + N - 1; i >= N; i--) {
6281     dot = 0.0;
6282     for (j = i + 1; j < n + N; j++)
6283       dot += lu[ps[i]][j] * X[j];
6284     X[i] = (X[i] - dot) / lu[ps[i]][i];
6285   }
6286 
6287   for (i = N; i < n + N; i++) b[i] = X[i];
6288 }
6289 
6290 ///////////////////////////////////////////////////////////////////////////////
6291 //                                                                           //
6292 // incircle3d()    3D in-circle test.                                        //
6293 //                                                                           //
6294 // Return a negative value if pd is inside the circumcircle of the triangle  //
6295 // pa, pb, and pc.                                                           //
6296 //                                                                           //
6297 // IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input  //
6298 // triangles are [a,b,c] and [b,a,d].                                        //
6299 //                                                                           //
6300 ///////////////////////////////////////////////////////////////////////////////
6301 
incircle3d(point pa,point pb,point pc,point pd)6302 REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
6303 {
6304   REAL area2[2], n1[3], n2[3], c[3];
6305   REAL sign, r, d;
6306 
6307   // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
6308   facenormal(pa, pb, pc, n1, 1, nullptr);
6309   area2[0] = dot(n1, n1);
6310   facenormal(pb, pa, pd, n2, 1, nullptr);
6311   area2[1] = dot(n2, n2);
6312 
6313   if (area2[0] > area2[1]) {
6314     // Choose [a, b, c] as the base triangle.
6315     circumsphere(pa, pb, pc, nullptr, c, &r);
6316     d = distance(c, pd);
6317   } else {
6318     // Choose [b, a, d] as the base triangle.
6319     if (area2[1] > 0) {
6320       circumsphere(pb, pa, pd, nullptr, c, &r);
6321       d = distance(c, pc);
6322     } else {
6323       // The four points are collinear. This case only happens on the boundary.
6324       return 0; // Return "not inside".
6325     }
6326   }
6327 
6328   sign = d - r;
6329   if (fabs(sign) / r < b->epsilon) {
6330     sign = 0;
6331   }
6332 
6333   return sign;
6334 }
6335 
6336 ///////////////////////////////////////////////////////////////////////////////
6337 //                                                                           //
6338 // facenormal()    Calculate the normal of the face.                         //
6339 //                                                                           //
6340 // The normal of the face abc can be calculated by the cross product of 2 of //
6341 // its 3 edge vectors.  A better choice of two edge vectors will reduce the  //
6342 // numerical error during the calculation.  Burdakov proved that the optimal //
6343 // basis problem is equivalent to the minimum spanning tree problem with the //
6344 // edge length be the functional, see Burdakov, "A greedy algorithm for the  //
6345 // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
6346 // short edges in abc are chosen for the calculation.                        //
6347 //                                                                           //
6348 // If 'lav' is not nullptr and if 'pivot' is set, the average edge length of    //
6349 // the edges of the face [a,b,c] is returned.                                //
6350 //                                                                           //
6351 ///////////////////////////////////////////////////////////////////////////////
6352 
facenormal(point pa,point pb,point pc,REAL * n,int pivot,REAL * lav)6353 void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
6354                             REAL* lav)
6355 {
6356   REAL v1[3], v2[3], v3[3], *pv1, *pv2;
6357   REAL L1, L2, L3;
6358 
6359   v1[0] = pb[0] - pa[0];  // edge vector v1: a->b
6360   v1[1] = pb[1] - pa[1];
6361   v1[2] = pb[2] - pa[2];
6362   v2[0] = pa[0] - pc[0];  // edge vector v2: c->a
6363   v2[1] = pa[1] - pc[1];
6364   v2[2] = pa[2] - pc[2];
6365 
6366   // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
6367   if (pivot > 0) {
6368     // Choose edge vectors by Burdakov's algorithm.
6369     v3[0] = pc[0] - pb[0];  // edge vector v3: b->c
6370     v3[1] = pc[1] - pb[1];
6371     v3[2] = pc[2] - pb[2];
6372     L1 = dot(v1, v1);
6373     L2 = dot(v2, v2);
6374     L3 = dot(v3, v3);
6375     // Sort the three edge lengths.
6376     if (L1 < L2) {
6377       if (L2 < L3) {
6378         pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6379       } else {
6380         pv1 = v3; pv2 = v1; // n = v3 x (-v1).
6381       }
6382     } else {
6383       if (L1 < L3) {
6384         pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6385       } else {
6386         pv1 = v2; pv2 = v3; // n = v2 x (-v3).
6387       }
6388     }
6389     if (lav) {
6390       // return the average edge length.
6391       *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
6392     }
6393   } else {
6394     pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6395   }
6396 
6397   // Calculate the face normal.
6398   cross(pv1, pv2, n);
6399   // Inverse the direction;
6400   n[0] = -n[0];
6401   n[1] = -n[1];
6402   n[2] = -n[2];
6403 }
6404 
6405 ///////////////////////////////////////////////////////////////////////////////
6406 //                                                                           //
6407 // shortdistance()    Returns the shortest distance from point p to a line   //
6408 //                    defined by two points e1 and e2.                       //
6409 //                                                                           //
6410 // First compute the projection length l_p of the vector v1 = p - e1 along   //
6411 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the  //
6412 // shortest distance.                                                        //
6413 //                                                                           //
6414 // This routine allows that p is collinear with the line. In this case, the  //
6415 // return value is zero. The two points e1 and e2 should not be identical.   //
6416 //                                                                           //
6417 ///////////////////////////////////////////////////////////////////////////////
6418 
shortdistance(REAL * p,REAL * e1,REAL * e2)6419 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
6420 {
6421   REAL v1[3], v2[3];
6422   REAL len, l_p;
6423 
6424   v1[0] = e2[0] - e1[0];
6425   v1[1] = e2[1] - e1[1];
6426   v1[2] = e2[2] - e1[2];
6427   v2[0] = p[0] - e1[0];
6428   v2[1] = p[1] - e1[1];
6429   v2[2] = p[2] - e1[2];
6430 
6431   len = sqrt(dot(v1, v1));
6432   assert(len != 0.0);
6433 
6434   v1[0] /= len;
6435   v1[1] /= len;
6436   v1[2] /= len;
6437   l_p = dot(v1, v2);
6438 
6439   return sqrt(dot(v2, v2) - l_p * l_p);
6440 }
6441 
6442 ///////////////////////////////////////////////////////////////////////////////
6443 //                                                                           //
6444 // triarea()    Return the area of a triangle.                               //
6445 //                                                                           //
6446 ///////////////////////////////////////////////////////////////////////////////
6447 
triarea(REAL * pa,REAL * pb,REAL * pc)6448 REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
6449 {
6450   REAL A[4][4];
6451 
6452   // Compute the coefficient matrix A (3x3).
6453   A[0][0] = pb[0] - pa[0];
6454   A[0][1] = pb[1] - pa[1];
6455   A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
6456   A[1][0] = pc[0] - pa[0];
6457   A[1][1] = pc[1] - pa[1];
6458   A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
6459 
6460   cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
6461 
6462   return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
6463 }
6464 
orient3dfast(REAL * pa,REAL * pb,REAL * pc,REAL * pd)6465 REAL tetgenmesh::orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
6466 {
6467   REAL adx, bdx, cdx;
6468   REAL ady, bdy, cdy;
6469   REAL adz, bdz, cdz;
6470 
6471   adx = pa[0] - pd[0];
6472   bdx = pb[0] - pd[0];
6473   cdx = pc[0] - pd[0];
6474   ady = pa[1] - pd[1];
6475   bdy = pb[1] - pd[1];
6476   cdy = pc[1] - pd[1];
6477   adz = pa[2] - pd[2];
6478   bdz = pb[2] - pd[2];
6479   cdz = pc[2] - pd[2];
6480 
6481   return adx * (bdy * cdz - bdz * cdy)
6482        + bdx * (cdy * adz - cdz * ady)
6483        + cdx * (ady * bdz - adz * bdy);
6484 }
6485 
6486 ///////////////////////////////////////////////////////////////////////////////
6487 //                                                                           //
6488 // interiorangle()    Return the interior angle (0 - 2 * PI) between vectors //
6489 //                    o->p1 and o->p2.                                       //
6490 //                                                                           //
6491 // 'n' is the normal of the plane containing face (o, p1, p2).  The interior //
6492 // angle is the total angle rotating from o->p1 around n to o->p2.  Exchange //
6493 // the position of p1 and p2 will get the complement angle of the other one. //
6494 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1).  Set  //
6495 // 'n' be nullptr if you only want the interior angle between 0 - PI.           //
6496 //                                                                           //
6497 ///////////////////////////////////////////////////////////////////////////////
6498 
interiorangle(REAL * o,REAL * p1,REAL * p2,REAL * n)6499 REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
6500 {
6501   REAL v1[3], v2[3], np[3];
6502   REAL theta, costheta, lenlen;
6503   REAL ori, len1, len2;
6504 
6505   // Get the interior angle (0 - PI) between o->p1, and o->p2.
6506   v1[0] = p1[0] - o[0];
6507   v1[1] = p1[1] - o[1];
6508   v1[2] = p1[2] - o[2];
6509   v2[0] = p2[0] - o[0];
6510   v2[1] = p2[1] - o[1];
6511   v2[2] = p2[2] - o[2];
6512   len1 = sqrt(dot(v1, v1));
6513   len2 = sqrt(dot(v2, v2));
6514   lenlen = len1 * len2;
6515   assert(lenlen != 0.0);
6516 
6517   costheta = dot(v1, v2) / lenlen;
6518   if (costheta > 1.0) {
6519     costheta = 1.0; // Roundoff.
6520   } else if (costheta < -1.0) {
6521     costheta = -1.0; // Roundoff.
6522   }
6523   theta = acos(costheta);
6524   if (n != nullptr) {
6525     // Get a point above the face (o, p1, p2);
6526     np[0] = o[0] + n[0];
6527     np[1] = o[1] + n[1];
6528     np[2] = o[2] + n[2];
6529     // Adjust theta (0 - 2 * PI).
6530     ori = orient3d(p1, o, np, p2);
6531     if (ori > 0.0) {
6532       theta = 2 * PI - theta;
6533     }
6534   }
6535 
6536   return theta;
6537 }
6538 
6539 ///////////////////////////////////////////////////////////////////////////////
6540 //                                                                           //
6541 // projpt2edge()    Return the projection point from a point to an edge.     //
6542 //                                                                           //
6543 ///////////////////////////////////////////////////////////////////////////////
6544 
projpt2edge(REAL * p,REAL * e1,REAL * e2,REAL * prj)6545 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
6546 {
6547   REAL v1[3], v2[3];
6548   REAL len, l_p;
6549 
6550   v1[0] = e2[0] - e1[0];
6551   v1[1] = e2[1] - e1[1];
6552   v1[2] = e2[2] - e1[2];
6553   v2[0] = p[0] - e1[0];
6554   v2[1] = p[1] - e1[1];
6555   v2[2] = p[2] - e1[2];
6556 
6557   len = sqrt(dot(v1, v1));
6558   assert(len != 0.0);
6559   v1[0] /= len;
6560   v1[1] /= len;
6561   v1[2] /= len;
6562   l_p = dot(v1, v2);
6563 
6564   prj[0] = e1[0] + l_p * v1[0];
6565   prj[1] = e1[1] + l_p * v1[1];
6566   prj[2] = e1[2] + l_p * v1[2];
6567 }
6568 
6569 ///////////////////////////////////////////////////////////////////////////////
6570 //                                                                           //
6571 // projpt2face()    Return the projection point from a point to a face.      //
6572 //                                                                           //
6573 ///////////////////////////////////////////////////////////////////////////////
6574 
projpt2face(REAL * p,REAL * f1,REAL * f2,REAL * f3,REAL * prj)6575 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
6576 {
6577   REAL fnormal[3], v1[3];
6578   REAL len, dist;
6579 
6580   // Get the unit face normal.
6581   facenormal(f1, f2, f3, fnormal, 1, nullptr);
6582   len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
6583              fnormal[2]*fnormal[2]);
6584   fnormal[0] /= len;
6585   fnormal[1] /= len;
6586   fnormal[2] /= len;
6587   // Get the vector v1 = |p - f1|.
6588   v1[0] = p[0] - f1[0];
6589   v1[1] = p[1] - f1[1];
6590   v1[2] = p[2] - f1[2];
6591   // Get the project distance.
6592   dist = dot(fnormal, v1);
6593 
6594   // Get the project point.
6595   prj[0] = p[0] - dist * fnormal[0];
6596   prj[1] = p[1] - dist * fnormal[1];
6597   prj[2] = p[2] - dist * fnormal[2];
6598 }
6599 
6600 ///////////////////////////////////////////////////////////////////////////////
6601 //                                                                           //
6602 // facedihedral()    Return the dihedral angle (in radian) between two       //
6603 //                   adjoining faces.                                        //
6604 //                                                                           //
6605 // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are   //
6606 // apexes of these two faces.  Return the angle (between 0 to 2*pi) between  //
6607 // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2).        //
6608 //                                                                           //
6609 ///////////////////////////////////////////////////////////////////////////////
6610 
facedihedral(REAL * pa,REAL * pb,REAL * pc1,REAL * pc2)6611 REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2)
6612 {
6613   REAL n1[3], n2[3];
6614   REAL n1len, n2len;
6615   REAL costheta, ori;
6616   REAL theta;
6617 
6618   facenormal(pa, pb, pc1, n1, 1, nullptr);
6619   facenormal(pa, pb, pc2, n2, 1, nullptr);
6620   n1len = sqrt(dot(n1, n1));
6621   n2len = sqrt(dot(n2, n2));
6622   costheta = dot(n1, n2) / (n1len * n2len);
6623   // Be careful rounding error!
6624   if (costheta > 1.0) {
6625     costheta = 1.0;
6626   } else if (costheta < -1.0) {
6627     costheta = -1.0;
6628   }
6629   theta = acos(costheta);
6630   ori = orient3d(pa, pb, pc1, pc2);
6631   if (ori > 0.0) {
6632     theta = 2 * PI - theta;
6633   }
6634 
6635   return theta;
6636 }
6637 
6638 ///////////////////////////////////////////////////////////////////////////////
6639 //                                                                           //
6640 // tetalldihedral()    Get all (six) dihedral angles of a tet.               //
6641 //                                                                           //
6642 // If 'cosdd' is not nullptr, it returns the cosines of the 6 dihedral angles,  //
6643 // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd'   //
6644 // (or 'cosmind') is not nullptr, it returns the cosine of the maximal (or      //
6645 // minimal) dihedral angle.                                                  //
6646 //                                                                           //
6647 ///////////////////////////////////////////////////////////////////////////////
6648 
tetalldihedral(point pa,point pb,point pc,point pd,REAL * cosdd,REAL * cosmaxd,REAL * cosmind)6649 bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
6650                                 REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
6651 {
6652   REAL N[4][3], vol, cosd, len;
6653   int f1 = 0, f2 = 0, i, j;
6654 
6655   vol = 0; // Check if the tet is valid or not.
6656 
6657   // Get four normals of faces of the tet.
6658   tetallnormal(pa, pb, pc, pd, N, &vol);
6659 
6660   if (vol > 0) {
6661     // Normalize the normals.
6662     for (i = 0; i < 4; i++) {
6663       len = sqrt(dot(N[i], N[i]));
6664       if (len != 0.0) {
6665         for (j = 0; j < 3; j++) N[i][j] /= len;
6666       } else {
6667         // There are degeneracies, such as duplicated vertices.
6668         vol = 0; //assert(0);
6669       }
6670     }
6671   }
6672 
6673   if (vol <= 0) { // if (vol == 0.0) {
6674     // A degenerated tet or an inverted tet.
6675     facenormal(pc, pb, pd, N[0], 1, nullptr);
6676     facenormal(pa, pc, pd, N[1], 1, nullptr);
6677     facenormal(pb, pa, pd, N[2], 1, nullptr);
6678     facenormal(pa, pb, pc, N[3], 1, nullptr);
6679     // Normalize the normals.
6680     for (i = 0; i < 4; i++) {
6681       len = sqrt(dot(N[i], N[i]));
6682       if (len != 0.0) {
6683         for (j = 0; j < 3; j++) N[i][j] /= len;
6684       } else {
6685         // There are degeneracies, such as duplicated vertices.
6686         break; // Not a valid normal.
6687       }
6688     }
6689     if (i < 4) {
6690       // Do not calculate dihedral angles.
6691       // Set all angles be 0 degree. There will be no quality optimization for
6692       //   this tet! Use volume optimization to correct it.
6693       if (cosdd != nullptr) {
6694         for (i = 0; i < 6; i++) {
6695           cosdd[i] = -1.0; // 180 degree.
6696         }
6697       }
6698       // This tet has zero volume.
6699       if (cosmaxd != nullptr) {
6700         *cosmaxd = -1.0; // 180 degree.
6701       }
6702       if (cosmind != nullptr) {
6703         *cosmind = -1.0; // 180 degree.
6704       }
6705       return false;
6706     }
6707   }
6708 
6709   // Calculate the consine of the dihedral angles of the edges.
6710   for (i = 0; i < 6; i++) {
6711     switch (i) {
6712     case 0: f1 = 0; f2 = 1; break; // [c,d].
6713     case 1: f1 = 1; f2 = 2; break; // [a,d].
6714     case 2: f1 = 2; f2 = 3; break; // [a,b].
6715     case 3: f1 = 0; f2 = 3; break; // [b,c].
6716     case 4: f1 = 2; f2 = 0; break; // [b,d].
6717     case 5: f1 = 1; f2 = 3; break; // [a,c].
6718     }
6719     cosd = -dot(N[f1], N[f2]);
6720     if (cosd < -1.0) cosd = -1.0; // Rounding.
6721     if (cosd >  1.0) cosd =  1.0; // Rounding.
6722     if (cosdd) cosdd[i] = cosd;
6723     if (cosmaxd || cosmind) {
6724       if (i == 0) {
6725         if (cosmaxd) *cosmaxd = cosd;
6726         if (cosmind) *cosmind = cosd;
6727       } else {
6728         if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
6729         if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
6730       }
6731     }
6732   }
6733 
6734   return true;
6735 }
6736 
6737 ///////////////////////////////////////////////////////////////////////////////
6738 //                                                                           //
6739 // tetallnormal()    Get the in-noramls of the four faces of a given tet.    //
6740 //                                                                           //
6741 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd,   //
6742 // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices   //
6743 // of the mesh data structure). These normals are unnormalized.              //
6744 //                                                                           //
6745 ///////////////////////////////////////////////////////////////////////////////
6746 
tetallnormal(point pa,point pb,point pc,point pd,REAL N[4][3],REAL * volume)6747 void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
6748                               REAL N[4][3], REAL* volume)
6749 {
6750   REAL A[4][4], rhs[4], D;
6751   int indx[4];
6752   int i, j;
6753 
6754   // get the entries of A[3][3].
6755   for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i];  // d->a vec
6756   for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i];  // d->b vec
6757   for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i];  // d->c vec
6758 
6759   // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
6760   if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
6761     if (volume != nullptr) {
6762       // Get the volume of the tet.
6763       *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
6764     }
6765     for (j = 0; j < 3; j++) {
6766       for (i = 0; i < 3; i++) rhs[i] = 0.0;
6767       rhs[j] = 1.0;  // Positive means the inside direction
6768       lu_solve(A, 3, indx, rhs, 0);
6769       for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6770     }
6771     // Get the fourth normal by summing up the first three.
6772     for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6773   } else {
6774     // The tet is degenerated.
6775     if (volume != nullptr) {
6776       *volume = 0;
6777     }
6778   }
6779 }
6780 
6781 ///////////////////////////////////////////////////////////////////////////////
6782 //                                                                           //
6783 // tetaspectratio()    Calculate the aspect ratio of the tetrahedron.        //
6784 //                                                                           //
6785 // The aspect ratio of a tet is R/h, where R is the circumradius and h is    //
6786 // the shortest height of the tet.                                           //
6787 //                                                                           //
6788 ///////////////////////////////////////////////////////////////////////////////
6789 
tetaspectratio(point pa,point pb,point pc,point pd)6790 REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
6791 {
6792   REAL vda[3], vdb[3], vdc[3];
6793   REAL N[4][3], A[4][4], rhs[4], D;
6794   REAL H[4], volume, radius2, minheightinv;
6795   int indx[4];
6796   int i, j;
6797 
6798   // Set the matrix A = [vda, vdb, vdc]^T.
6799   for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
6800   for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
6801   for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
6802   // Lu-decompose the matrix A.
6803   lu_decmp(A, 3, indx, &D, 0);
6804   // Get the volume of abcd.
6805   volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
6806   // Check if it is zero.
6807   if (volume == 0.0) return 1.0e+200; // A degenerate tet.
6808   // if (volume < 0.0) volume = -volume;
6809   // Check the radiu-edge ratio of the tet.
6810   rhs[0] = 0.5 * dot(vda, vda);
6811   rhs[1] = 0.5 * dot(vdb, vdb);
6812   rhs[2] = 0.5 * dot(vdc, vdc);
6813   lu_solve(A, 3, indx, rhs, 0);
6814   // Get the circumcenter.
6815   // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i];
6816   // Get the square of the circumradius.
6817   radius2 = dot(rhs, rhs);
6818 
6819   // Compute the 4 face normals (N[0], ..., N[3]).
6820   for (j = 0; j < 3; j++) {
6821     for (i = 0; i < 3; i++) rhs[i] = 0.0;
6822     rhs[j] = 1.0;  // Positive means the inside direction
6823     lu_solve(A, 3, indx, rhs, 0);
6824     for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6825   }
6826   // Get the fourth normal by summing up the first three.
6827   for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6828   // Normalized the normals.
6829   for (i = 0; i < 4; i++) {
6830     // H[i] is the inverse of the height of its corresponding face.
6831     H[i] = sqrt(dot(N[i], N[i]));
6832     // if (H[i] > 0.0) {
6833     //   for (j = 0; j < 3; j++) N[i][j] /= H[i];
6834     // }
6835   }
6836   // Get the radius of the inscribed sphere.
6837   // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
6838   // Get the biggest H[i] (corresponding to the smallest height).
6839   minheightinv = H[0];
6840   for (i = 1; i < 3; i++) {
6841     if (H[i] > minheightinv) minheightinv = H[i];
6842   }
6843 
6844   return sqrt(radius2) * minheightinv;
6845 }
6846 
6847 ///////////////////////////////////////////////////////////////////////////////
6848 //                                                                           //
6849 // circumsphere()    Calculate the smallest circumsphere (center and radius) //
6850 //                   of the given three or four points.                      //
6851 //                                                                           //
6852 // The circumsphere of four points (a tetrahedron) is unique if they are not //
6853 // degenerate. If 'pd = nullptr', the smallest circumsphere of three points is  //
6854 // the diametral sphere of the triangle if they are not degenerate.          //
6855 //                                                                           //
6856 // Return TRUE if the input points are not degenerate and the circumcenter   //
6857 // and circumradius are returned in 'cent' and 'radius' respectively if they //
6858 // are not nullptrs. Otherwise, return FALSE indicated the points are degenrate.//
6859 //                                                                           //
6860 ///////////////////////////////////////////////////////////////////////////////
6861 
circumsphere(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL * cent,REAL * radius)6862 bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6863                               REAL* cent, REAL* radius)
6864 {
6865   REAL A[4][4], rhs[4], D;
6866   int indx[4];
6867 
6868   // Compute the coefficient matrix A (3x3).
6869   A[0][0] = pb[0] - pa[0];
6870   A[0][1] = pb[1] - pa[1];
6871   A[0][2] = pb[2] - pa[2];
6872   A[1][0] = pc[0] - pa[0];
6873   A[1][1] = pc[1] - pa[1];
6874   A[1][2] = pc[2] - pa[2];
6875   if (pd != nullptr) {
6876     A[2][0] = pd[0] - pa[0];
6877     A[2][1] = pd[1] - pa[1];
6878     A[2][2] = pd[2] - pa[2];
6879   } else {
6880     cross(A[0], A[1], A[2]);
6881   }
6882 
6883   // Compute the right hand side vector b (3x1).
6884   rhs[0] = 0.5 * dot(A[0], A[0]);
6885   rhs[1] = 0.5 * dot(A[1], A[1]);
6886   if (pd != nullptr) {
6887     rhs[2] = 0.5 * dot(A[2], A[2]);
6888   } else {
6889     rhs[2] = 0.0;
6890   }
6891 
6892   // Solve the 3 by 3 equations use LU decomposition with partial pivoting
6893   //   and backward and forward substitute..
6894   if (!lu_decmp(A, 3, indx, &D, 0)) {
6895     if (radius != (REAL *) nullptr) *radius = 0.0;
6896     return false;
6897   }
6898   lu_solve(A, 3, indx, rhs, 0);
6899   if (cent != (REAL *) nullptr) {
6900     cent[0] = pa[0] + rhs[0];
6901     cent[1] = pa[1] + rhs[1];
6902     cent[2] = pa[2] + rhs[2];
6903   }
6904   if (radius != (REAL *) nullptr) {
6905     *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
6906   }
6907   return true;
6908 }
6909 
6910 ///////////////////////////////////////////////////////////////////////////////
6911 //                                                                           //
6912 // orthosphere()    Calulcate the orthosphere of four weighted points.       //
6913 //                                                                           //
6914 // A weighted point (p, P^2) can be interpreted as a sphere centered at the  //
6915 // point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 +    //
6916 // p[1]^2 + p[2]^2 - P^2.                                                    //
6917 //                                                                           //
6918 ///////////////////////////////////////////////////////////////////////////////
6919 
orthosphere(REAL * pa,REAL * pb,REAL * pc,REAL * pd,REAL aheight,REAL bheight,REAL cheight,REAL dheight,REAL * orthocent,REAL * radius)6920 bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6921                              REAL  aheight, REAL bheight, REAL cheight,
6922                              REAL  dheight, REAL* orthocent, REAL* radius)
6923 {
6924   REAL A[4][4], rhs[4], D;
6925   int indx[4];
6926 
6927   // Set the coefficient matrix A (4 x 4).
6928   A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
6929   A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
6930   A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
6931   A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
6932 
6933   // Set the right hand side vector (4 x 1).
6934   rhs[0] = 0.5 * aheight;
6935   rhs[1] = 0.5 * bheight;
6936   rhs[2] = 0.5 * cheight;
6937   rhs[3] = 0.5 * dheight;
6938 
6939   // Solve the 4 by 4 equations use LU decomposition with partial pivoting
6940   //   and backward and forward substitute..
6941   if (!lu_decmp(A, 4, indx, &D, 0)) {
6942     if (radius != (REAL *) nullptr) *radius = 0.0;
6943     return false;
6944   }
6945   lu_solve(A, 4, indx, rhs, 0);
6946 
6947   if (orthocent != (REAL *) nullptr) {
6948     orthocent[0] = rhs[1];
6949     orthocent[1] = rhs[2];
6950     orthocent[2] = rhs[3];
6951   }
6952   if (radius != (REAL *) nullptr) {
6953     // rhs[0] = - rheight / 2;
6954     // rheight  = - 2 * rhs[0];
6955     //          =  r[0]^2 + r[1]^2 + r[2]^2 - radius^2
6956     // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
6957     //          = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
6958     *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
6959                    + 2.0 * rhs[0]);
6960   }
6961   return true;
6962 }
6963 
6964 ///////////////////////////////////////////////////////////////////////////////
6965 //                                                                           //
6966 // planelineint()    Calculate the intersection of a line and a plane.       //
6967 //                                                                           //
6968 // The equation of a plane (points P are on the plane with normal N and P3   //
6969 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the  //
6970 // line (points P on the line passing through P1 and P2) can be written as:  //
6971 // P = P1 + u (P2 - P1). The intersection of these two occurs when:          //
6972 //   N dot (P1 + u (P2 - P1)) = N dot P3.                                    //
6973 // Solving for u gives:                                                      //
6974 //         N dot (P3 - P1)                                                   //
6975 //   u = ------------------.                                                 //
6976 //         N dot (P2 - P1)                                                   //
6977 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
6978 // to the line.  Thus the line is either parallel to the plane and there are //
6979 // no solutions or the line is on the plane in which case there are an infi- //
6980 // nite number of solutions.                                                 //
6981 //                                                                           //
6982 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the  //
6983 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
6984 //                                                                           //
6985 ///////////////////////////////////////////////////////////////////////////////
6986 
planelineint(REAL * pa,REAL * pb,REAL * pc,REAL * e1,REAL * e2,REAL * ip,REAL * u)6987 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
6988                               REAL* ip, REAL* u)
6989 {
6990   REAL n[3], det, det1;
6991 
6992   // Calculate N.
6993   facenormal(pa, pb, pc, n, 1, nullptr);
6994   // Calculate N dot (e2 - e1).
6995   det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
6996       + n[2] * (e2[2] - e1[2]);
6997   if (det != 0.0) {
6998     // Calculate N dot (pa - e1)
6999     det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
7000          + n[2] * (pa[2] - e1[2]);
7001     *u = det1 / det;
7002     ip[0] = e1[0] + *u * (e2[0] - e1[0]);
7003     ip[1] = e1[1] + *u * (e2[1] - e1[1]);
7004     ip[2] = e1[2] + *u * (e2[2] - e1[2]);
7005   } else {
7006     *u = 0.0;
7007   }
7008 }
7009 
7010 ///////////////////////////////////////////////////////////////////////////////
7011 //                                                                           //
7012 // linelineint()    Calculate the intersection(s) of two line segments.      //
7013 //                                                                           //
7014 // Calculate the line segment [P, Q] that is the shortest route betweeb two  //
7015 // lines from A to B and C to D. Calculate also the values of tp and tq      //
7016 // where: P = A + tp (B - A), and Q = C + tq (D - C).                        //
7017 //                                                                           //
7018 // Return 1 if the line segment exists. Otherwise, return 0.                 //
7019 //                                                                           //
7020 ///////////////////////////////////////////////////////////////////////////////
7021 
linelineint(REAL * A,REAL * B,REAL * C,REAL * D,REAL * P,REAL * Q,REAL * tp,REAL * tq)7022 int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P,
7023                             REAL* Q, REAL* tp, REAL* tq)
7024 {
7025   REAL vab[3], vcd[3], vca[3];
7026   REAL vab_vab, vcd_vcd, vab_vcd;
7027   REAL vca_vab, vca_vcd;
7028   REAL det, eps;
7029   int i;
7030 
7031   for (i = 0; i < 3; i++) {
7032     vab[i] = B[i] - A[i];
7033     vcd[i] = D[i] - C[i];
7034     vca[i] = A[i] - C[i];
7035   }
7036 
7037   vab_vab = dot(vab, vab);
7038   vcd_vcd = dot(vcd, vcd);
7039   vab_vcd = dot(vab, vcd);
7040 
7041   det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
7042   // Round the result.
7043   eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
7044   if (eps < b->epsilon) {
7045     return 0;
7046   }
7047 
7048   vca_vab = dot(vca, vab);
7049   vca_vcd = dot(vca, vcd);
7050 
7051   *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
7052   *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
7053 
7054   for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
7055   for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
7056 
7057   return 1;
7058 }
7059 
7060 ///////////////////////////////////////////////////////////////////////////////
7061 //                                                                           //
7062 // tetprismvol()    Calculate the volume of a tetrahedral prism in 4D.       //
7063 //                                                                           //
7064 // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
7065 // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular  //
7066 // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
7067 // vertices. (Wikipedia).                                                    //
7068 //                                                                           //
7069 // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
7070 // the lower tetrahedral facet of the prism.  The top tetrahedral facet is   //
7071 // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by     //
7072 // lifting each vertex of the lower facet into R^4 by a weight (height).  A  //
7073 // canonical choice of the weights is the square of Euclidean norm of of the //
7074 // points (vectors).                                                         //
7075 //                                                                           //
7076 //                                                                           //
7077 // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
7078 //                                                                           //
7079 ///////////////////////////////////////////////////////////////////////////////
7080 
tetprismvol(REAL * p0,REAL * p1,REAL * p2,REAL * p3)7081 REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
7082 {
7083   REAL *p4, *p5, *p6, *p7;
7084   REAL w4, w5, w6, w7;
7085   REAL vol[4];
7086 
7087   p4 = p0;
7088   p5 = p1;
7089   p6 = p2;
7090   p7 = p3;
7091 
7092   // TO DO: these weights can be pre-calculated!
7093   w4 = dot(p0, p0);
7094   w5 = dot(p1, p1);
7095   w6 = dot(p2, p2);
7096   w7 = dot(p3, p3);
7097 
7098   // Calculate the volume of the tet-prism.
7099   vol[0] = orient4d_numeric(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
7100   vol[1] = orient4d_numeric(p3, p6, p2, p0, p1,  0, w6,  0, 0,  0);
7101   vol[2] = orient4d_numeric(p4, p6, p3, p0, p1, w4, w6,  0, 0,  0);
7102   vol[3] = orient4d_numeric(p6, p5, p4, p3, p1, w6, w5, w4, 0,  0);
7103 
7104   return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
7105 }
7106 
7107 ///////////////////////////////////////////////////////////////////////////////
7108 //                                                                           //
7109 // calculateabovepoint()    Calculate a point above a facet in 'dummypoint'. //
7110 //                                                                           //
7111 ///////////////////////////////////////////////////////////////////////////////
7112 
calculateabovepoint(arraypool * facpoints,point * ppa,point * ppb,point * ppc)7113 bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
7114                                      point *ppb, point *ppc)
7115 {
7116   point *ppt, pa, pb, pc;
7117   REAL v1[3], v2[3], n[3];
7118   REAL lab, len, A, area;
7119   REAL x, y, z;
7120   int i;
7121 
7122   ppt = (point *) fastlookup(facpoints, 0);
7123   pa = *ppt; // a is the first point.
7124   pb = pc = nullptr; // Avoid compiler warnings.
7125 
7126   // Get a point b s.t. the length of [a, b] is maximal.
7127   lab = 0;
7128   for (i = 1; i < facpoints->objects; i++) {
7129     ppt = (point *) fastlookup(facpoints, i);
7130     x = (*ppt)[0] - pa[0];
7131     y = (*ppt)[1] - pa[1];
7132     z = (*ppt)[2] - pa[2];
7133     len = x * x + y * y + z * z;
7134     if (len > lab) {
7135       lab = len;
7136       pb = *ppt;
7137     }
7138   }
7139   lab = sqrt(lab);
7140   if (lab == 0) {
7141     if (!b->quiet) {
7142       printf("Warning:  All points of a facet are coincident with %d.\n",
7143         pointmark(pa));
7144     }
7145     return false;
7146   }
7147 
7148   // Get a point c s.t. the area of [a, b, c] is maximal.
7149   v1[0] = pb[0] - pa[0];
7150   v1[1] = pb[1] - pa[1];
7151   v1[2] = pb[2] - pa[2];
7152   A = 0;
7153   for (i = 1; i < facpoints->objects; i++) {
7154     ppt = (point *) fastlookup(facpoints, i);
7155     v2[0] = (*ppt)[0] - pa[0];
7156     v2[1] = (*ppt)[1] - pa[1];
7157     v2[2] = (*ppt)[2] - pa[2];
7158     cross(v1, v2, n);
7159     area = dot(n, n);
7160     if (area > A) {
7161       A = area;
7162       pc = *ppt;
7163     }
7164   }
7165   if (A == 0) {
7166     // All points are collinear. No above point.
7167     if (!b->quiet) {
7168       printf("Warning:  All points of a facet are collinaer with [%d, %d].\n",
7169         pointmark(pa), pointmark(pb));
7170     }
7171     return false;
7172   }
7173 
7174   // Calculate an above point of this facet.
7175   facenormal(pa, pb, pc, n, 1, nullptr);
7176   len = sqrt(dot(n, n));
7177   n[0] /= len;
7178   n[1] /= len;
7179   n[2] /= len;
7180   lab /= 2.0; // Half the maximal length.
7181   dummypoint[0] = pa[0] + lab * n[0];
7182   dummypoint[1] = pa[1] + lab * n[1];
7183   dummypoint[2] = pa[2] + lab * n[2];
7184 
7185   if (ppa != nullptr) {
7186     // Return the three points.
7187     *ppa = pa;
7188     *ppb = pb;
7189     *ppc = pc;
7190   }
7191 
7192   return true;
7193 }
7194 
7195 ///////////////////////////////////////////////////////////////////////////////
7196 //                                                                           //
7197 // Calculate an above point. It lies above the plane containing  the subface //
7198 //   [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
7199 //   is the normal of the plane.                                             //
7200 //                                                                           //
7201 ///////////////////////////////////////////////////////////////////////////////
7202 
calculateabovepoint4(point pa,point pb,point pc,point pd)7203 void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
7204 {
7205   REAL n1[3], n2[3], *norm;
7206   REAL len, len1, len2;
7207 
7208   // Select a base.
7209   facenormal(pa, pb, pc, n1, 1, nullptr);
7210   len1 = sqrt(dot(n1, n1));
7211   facenormal(pa, pb, pd, n2, 1, nullptr);
7212   len2 = sqrt(dot(n2, n2));
7213   if (len1 > len2) {
7214     norm = n1;
7215     len = len1;
7216   } else {
7217     norm = n2;
7218     len = len2;
7219   }
7220   assert(len > 0);
7221   norm[0] /= len;
7222   norm[1] /= len;
7223   norm[2] /= len;
7224   len = distance(pa, pb);
7225   dummypoint[0] = pa[0] + len * norm[0];
7226   dummypoint[1] = pa[1] + len * norm[1];
7227   dummypoint[2] = pa[2] + len * norm[2];
7228 }
7229 
7230 ////                                                                       ////
7231 ////                                                                       ////
7232 //// geom_cxx /////////////////////////////////////////////////////////////////
7233 
7234 //// flip_cxx /////////////////////////////////////////////////////////////////
7235 ////                                                                       ////
7236 ////                                                                       ////
7237 
7238 ///////////////////////////////////////////////////////////////////////////////
7239 //                                                                           //
7240 // flip23()    Perform a 2-to-3 flip (face-to-edge flip).                    //
7241 //                                                                           //
7242 // 'fliptets' is an array of three tets (handles), where the [0] and [1] are  //
7243 // [a,b,c,d] and [b,a,c,e].  The three new tets: [e,d,a,b], [e,d,b,c], and   //
7244 // [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'.  As a result,  //
7245 // The face [a,b,c] is removed, and the edge [d,e] is created.               //
7246 //                                                                           //
7247 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
7248 // the five vertices may be 'dummypoint'. There are two canonical cases:     //
7249 //   (1) d is 'dummypoint', then all three new tets are hull tets.  If e is  //
7250 //       'dummypoint', we reconfigure e to d, i.e., turn it up-side down.    //
7251 //   (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are  //
7252 //       hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
7253 //       rotate the three input tets counterclockwisely (right-hand rule)    //
7254 //       until a or b is in c's position.                                    //
7255 //                                                                           //
7256 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
7257 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
7258 // after the insertion of a new point.  It is assumed that 'd' is the new    //
7259 // point. IN this case, only link faces of 'd' are queued.                   //
7260 //                                                                           //
7261 ///////////////////////////////////////////////////////////////////////////////
7262 
flip23(triface * fliptets,int hullflag,flipconstraints * fc)7263 void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
7264 {
7265   triface topcastets[3], botcastets[3];
7266   triface newface, casface;
7267   point pa, pb, pc, pd, pe;
7268   REAL attrib, volume;
7269   int dummyflag = 0;  // range = {-1, 0, 1, 2}.
7270   int i;
7271 
7272   if (hullflag > 0) {
7273     // Check if e is dummypoint.
7274     if (oppo(fliptets[1]) == dummypoint) {
7275       // Swap the two old tets.
7276       newface = fliptets[0];
7277       fliptets[0] = fliptets[1];
7278       fliptets[1] = newface;
7279       dummyflag = -1;  // d is dummypoint.
7280     } else {
7281       // Check if either a or b is dummypoint.
7282       if (org(fliptets[0]) == dummypoint) {
7283         dummyflag = 1; // a is dummypoint.
7284         enextself(fliptets[0]);
7285         eprevself(fliptets[1]);
7286       } else if (dest(fliptets[0]) == dummypoint) {
7287         dummyflag = 2; // b is dummypoint.
7288         eprevself(fliptets[0]);
7289         enextself(fliptets[1]);
7290       } else {
7291         dummyflag = 0; // either c or d may be dummypoint.
7292       }
7293     }
7294   }
7295 
7296   pa =  org(fliptets[0]);
7297   pb = dest(fliptets[0]);
7298   pc = apex(fliptets[0]);
7299   pd = oppo(fliptets[0]);
7300   pe = oppo(fliptets[1]);
7301 
7302   flip23count++;
7303 
7304   // Get the outer boundary faces.
7305   for (i = 0; i < 3; i++) {
7306     fnext(fliptets[0], topcastets[i]);
7307     enextself(fliptets[0]);
7308   }
7309   for (i = 0; i < 3; i++) {
7310     fnext(fliptets[1], botcastets[i]);
7311     eprevself(fliptets[1]);
7312   }
7313 
7314   // Re-use fliptets[0] and fliptets[1].
7315   fliptets[0].ver = 11;
7316   fliptets[1].ver = 11;
7317   setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7318   setelemmarker(fliptets[1].tet, 0);
7319   // NOTE: the element attributes and volume constraint remain unchanged.
7320   if (checksubsegflag) {
7321     // Dealloc the space to subsegments.
7322     if (fliptets[0].tet[8] != nullptr) {
7323       tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7324       fliptets[0].tet[8] = nullptr;
7325     }
7326     if (fliptets[1].tet[8] != nullptr) {
7327       tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7328       fliptets[1].tet[8] = nullptr;
7329     }
7330   }
7331   if (checksubfaceflag) {
7332     // Dealloc the space to subfaces.
7333     if (fliptets[0].tet[9] != nullptr) {
7334       tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7335       fliptets[0].tet[9] = nullptr;
7336     }
7337     if (fliptets[1].tet[9] != nullptr) {
7338       tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7339       fliptets[1].tet[9] = nullptr;
7340     }
7341   }
7342   // Create a new tet.
7343   maketetrahedron(&(fliptets[2]));
7344   // The new tet have the same attributes from the old tet.
7345   for (i = 0; i < numelemattrib; i++) {
7346     attrib = elemattribute(fliptets[0].tet, i);
7347     setelemattribute(fliptets[2].tet, i, attrib);
7348   }
7349   if (b->varvolume) {
7350     volume = volumebound(fliptets[0].tet);
7351     setvolumebound(fliptets[2].tet, volume);
7352   }
7353 
7354   if (hullflag > 0) {
7355     // Check if d is dummytet.
7356     if (pd != dummypoint) {
7357       setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7358       setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7359       // Check if c is dummypoint.
7360       if (pc != dummypoint) {
7361         setvertices(fliptets[2], pe, pd, pc, pa);  // [e,d,c,a] *
7362       } else {
7363         setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
7364         esymself(fliptets[2]);                    // [e,d,c,a] *
7365       }
7366       // The hullsize does not change.
7367     } else {
7368       // d is dummypoint.
7369       setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
7370       setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
7371       setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
7372       // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
7373       for (i = 0; i < 3; i++) {
7374         eprevesymself(fliptets[i]);
7375         enextself(fliptets[i]);
7376       }
7377       // We deleted one hull tet, and created three hull tets.
7378       hullsize += 2;
7379     }
7380   } else {
7381     setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7382     setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7383     setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7384   }
7385 
7386   if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7387     REAL volneg[2], volpos[3], vol_diff;
7388     if (pd != dummypoint) {
7389       if (pc != dummypoint) {
7390         volpos[0] = tetprismvol(pe, pd, pa, pb);
7391         volpos[1] = tetprismvol(pe, pd, pb, pc);
7392         volpos[2] = tetprismvol(pe, pd, pc, pa);
7393         volneg[0] = tetprismvol(pa, pb, pc, pd);
7394         volneg[1] = tetprismvol(pb, pa, pc, pe);
7395       } else { // pc == dummypoint
7396         volpos[0] = tetprismvol(pe, pd, pa, pb);
7397         volpos[1] = 0.;
7398         volpos[2] = 0.;
7399         volneg[0] = 0.;
7400         volneg[1] = 0.;
7401       }
7402     } else { // pd == dummypoint.
7403       volpos[0] = 0.;
7404       volpos[1] = 0.;
7405       volpos[2] = 0.;
7406       volneg[0] = 0.;
7407       volneg[1] = tetprismvol(pb, pa, pc, pe);
7408     }
7409     vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
7410     fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
7411   }
7412 
7413   // Bond three new tets together.
7414   for (i = 0; i < 3; i++) {
7415     esym(fliptets[i], newface);
7416     bond(newface, fliptets[(i + 1) % 3]);
7417   }
7418   // Bond to top outer boundary faces (at [a,b,c,d]).
7419   for (i = 0; i < 3; i++) {
7420     eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
7421     bond(newface, topcastets[i]);
7422   }
7423   // Bond bottom outer boundary faces (at [b,a,c,e]).
7424   for (i = 0; i < 3; i++) {
7425     edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
7426     bond(newface, botcastets[i]);
7427   }
7428 
7429   if (checksubsegflag) {
7430     // Bond subsegments if there are.
7431     // Each new tet has 5 edges to be checked (except the edge [e,d]).
7432     face checkseg;
7433     // The middle three: [a,b], [b,c], [c,a].
7434     for (i = 0; i < 3; i++) {
7435       if (issubseg(topcastets[i])) {
7436         tsspivot1(topcastets[i], checkseg);
7437         eorgoppo(fliptets[i], newface);
7438         tssbond1(newface, checkseg);
7439         sstbond1(checkseg, newface);
7440         if (fc->chkencflag & 1) {
7441           enqueuesubface(badsubsegs, &checkseg);
7442         }
7443       }
7444     }
7445     // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
7446     for (i = 0; i < 3; i++) {
7447       eprev(topcastets[i], casface);
7448       if (issubseg(casface)) {
7449         tsspivot1(casface, checkseg);
7450         enext(fliptets[i], newface);
7451         tssbond1(newface, checkseg);
7452         sstbond1(checkseg, newface);
7453         esym(fliptets[(i + 2) % 3], newface);
7454         eprevself(newface);
7455         tssbond1(newface, checkseg);
7456         sstbond1(checkseg, newface);
7457         if (fc->chkencflag & 1) {
7458           enqueuesubface(badsubsegs, &checkseg);
7459         }
7460       }
7461     }
7462     // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
7463     for (i = 0; i < 3; i++) {
7464       enext(botcastets[i], casface);
7465       if (issubseg(casface)) {
7466         tsspivot1(casface, checkseg);
7467         eprev(fliptets[i], newface);
7468         tssbond1(newface, checkseg);
7469         sstbond1(checkseg, newface);
7470         esym(fliptets[(i + 2) % 3], newface);
7471         enextself(newface);
7472         tssbond1(newface, checkseg);
7473         sstbond1(checkseg, newface);
7474         if (fc->chkencflag & 1) {
7475           enqueuesubface(badsubsegs, &checkseg);
7476         }
7477       }
7478     }
7479   } // if (checksubsegflag)
7480 
7481   if (checksubfaceflag) {
7482     // Bond 6 subfaces if there are.
7483     face checksh;
7484     for (i = 0; i < 3; i++) {
7485       if (issubface(topcastets[i])) {
7486         tspivot(topcastets[i], checksh);
7487         eorgoppo(fliptets[i], newface);
7488         sesymself(checksh);
7489         tsbond(newface, checksh);
7490         if (fc->chkencflag & 2) {
7491           enqueuesubface(badsubfacs, &checksh);
7492         }
7493       }
7494     }
7495     for (i = 0; i < 3; i++) {
7496       if (issubface(botcastets[i])) {
7497         tspivot(botcastets[i], checksh);
7498         edestoppo(fliptets[i], newface);
7499         sesymself(checksh);
7500         tsbond(newface, checksh);
7501         if (fc->chkencflag & 2) {
7502           enqueuesubface(badsubfacs, &checksh);
7503         }
7504       }
7505     }
7506   } // if (checksubfaceflag)
7507 
7508   if (fc->chkencflag & 4) {
7509     // Put three new tets into check list.
7510     for (i = 0; i < 3; i++) {
7511       enqueuetetrahedron(&(fliptets[i]));
7512     }
7513   }
7514 
7515   // Update the point-to-tet map.
7516   setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7517   setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7518   setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
7519   setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7520   setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
7521 
7522   if (hullflag > 0) {
7523     if (dummyflag != 0) {
7524       // Restore the original position of the points (for flipnm()).
7525       if (dummyflag == -1) {
7526         // Reverse the edge.
7527         for (i = 0; i < 3; i++) {
7528           esymself(fliptets[i]);
7529         }
7530         // Swap the last two new tets.
7531         newface = fliptets[1];
7532         fliptets[1] = fliptets[2];
7533         fliptets[2] = newface;
7534       } else {
7535         // either a or b were swapped.
7536         if (dummyflag == 1) {
7537           // a is dummypoint.
7538           newface = fliptets[0];
7539           fliptets[0] = fliptets[2];
7540           fliptets[2] = fliptets[1];
7541           fliptets[1] = newface;
7542         } else { // dummyflag == 2
7543           // b is dummypoint.
7544           newface = fliptets[0];
7545           fliptets[0] = fliptets[1];
7546           fliptets[1] = fliptets[2];
7547           fliptets[2] = newface;
7548         }
7549       }
7550     }
7551   }
7552 
7553   if (fc->enqflag > 0) {
7554     // Queue faces which may be locally non-Delaunay.
7555     for (i = 0; i < 3; i++) {
7556       eprevesym(fliptets[i], newface);
7557       flippush(flipstack, &newface);
7558     }
7559     if (fc->enqflag > 1) {
7560       for (i = 0; i < 3; i++) {
7561         enextesym(fliptets[i], newface);
7562         flippush(flipstack, &newface);
7563       }
7564     }
7565   }
7566 
7567   recenttet = fliptets[0];
7568 }
7569 
7570 ///////////////////////////////////////////////////////////////////////////////
7571 //                                                                           //
7572 // flip32()    Perform a 3-to-2 flip (edge-to-face flip).                    //
7573 //                                                                           //
7574 // 'fliptets' is an array of three tets (handles),  which are [e,d,a,b],     //
7575 // [e,d,b,c], and [e,d,c,a].  The two new tets: [a,b,c,d] and [b,a,c,e] are  //
7576 // returned in [0] and [1] of 'fliptets'.  As a result, the edge [e,d] is    //
7577 // replaced by the face [a,b,c].                                             //
7578 //                                                                           //
7579 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of   //
7580 // the five vertices may be 'dummypoint'. There are two canonical cases:     //
7581 //   (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
7582 //       we reconfigure e to d, i.e., turnover it.                           //
7583 //   (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets.  //
7584 //       If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
7585 //       three old tets counterclockwisely (right-hand rule) until a or b    //
7586 //       is in c's position.                                                 //
7587 //                                                                           //
7588 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping.   //
7589 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip()   //
7590 // after the insertion of a new point.  It is assumed that 'a' is the new    //
7591 // point. In this case, only link faces of 'a' are queued.                   //
7592 //                                                                           //
7593 // If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a  //
7594 // segment. There may be two (interior) subfaces sharing at [e,d], which are //
7595 // [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c),  //
7596 // or (c,a)  In such case, a 2-to-2 flip is performed on these two subfaces  //
7597 // and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted   //
7598 // back into the tetrahedralization.                                         //
7599 //                                                                           //
7600 ///////////////////////////////////////////////////////////////////////////////
7601 
flip32(triface * fliptets,int hullflag,flipconstraints * fc)7602 void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
7603 {
7604   triface topcastets[3], botcastets[3];
7605   triface newface, casface;
7606   face flipshs[3];
7607   face checkseg;
7608   point pa, pb, pc, pd, pe;
7609   REAL attrib, volume;
7610   int dummyflag = 0;  // Rangle = {-1, 0, 1, 2}
7611   int spivot = -1, scount = 0; // for flip22()
7612   int t1ver;
7613   int i, j;
7614 
7615   if (hullflag > 0) {
7616     // Check if e is 'dummypoint'.
7617     if (org(fliptets[0]) == dummypoint) {
7618       // Reverse the edge.
7619       for (i = 0; i < 3; i++) {
7620         esymself(fliptets[i]);
7621       }
7622       // Swap the last two tets.
7623       newface = fliptets[1];
7624       fliptets[1] = fliptets[2];
7625       fliptets[2] = newface;
7626       dummyflag = -1; // e is dummypoint.
7627     } else {
7628       // Check if a or b is the 'dummypoint'.
7629       if (apex(fliptets[0]) == dummypoint) {
7630         dummyflag = 1;  // a is dummypoint.
7631         newface = fliptets[0];
7632         fliptets[0] = fliptets[1];
7633         fliptets[1] = fliptets[2];
7634         fliptets[2] = newface;
7635       } else if (apex(fliptets[1]) == dummypoint) {
7636         dummyflag = 2;  // b is dummypoint.
7637         newface = fliptets[0];
7638         fliptets[0] = fliptets[2];
7639         fliptets[2] = fliptets[1];
7640         fliptets[1] = newface;
7641       } else {
7642         dummyflag = 0;  // either c or d may be dummypoint.
7643       }
7644     }
7645   }
7646 
7647   pa = apex(fliptets[0]);
7648   pb = apex(fliptets[1]);
7649   pc = apex(fliptets[2]);
7650   pd = dest(fliptets[0]);
7651   pe = org(fliptets[0]);
7652 
7653   flip32count++;
7654 
7655   // Get the outer boundary faces.
7656   for (i = 0; i < 3; i++) {
7657     eorgoppo(fliptets[i], casface);
7658     fsym(casface, topcastets[i]);
7659   }
7660   for (i = 0; i < 3; i++) {
7661     edestoppo(fliptets[i], casface);
7662     fsym(casface, botcastets[i]);
7663   }
7664 
7665   if (checksubfaceflag) {
7666     // Check if there are interior subfaces at the edge [e,d].
7667     for (i = 0; i < 3; i++) {
7668       tspivot(fliptets[i], flipshs[i]);
7669       if (flipshs[i].sh != nullptr) {
7670         // Found an interior subface.
7671         stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
7672         scount++;
7673       } else {
7674         spivot = i;
7675       }
7676     }
7677   }
7678 
7679   // Re-use fliptets[0] and fliptets[1].
7680   fliptets[0].ver = 11;
7681   fliptets[1].ver = 11;
7682   setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7683   setelemmarker(fliptets[1].tet, 0);
7684   if (checksubsegflag) {
7685     // Dealloc the space to subsegments.
7686     if (fliptets[0].tet[8] != nullptr) {
7687       tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7688       fliptets[0].tet[8] = nullptr;
7689     }
7690     if (fliptets[1].tet[8] != nullptr) {
7691       tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7692       fliptets[1].tet[8] = nullptr;
7693     }
7694   }
7695   if (checksubfaceflag) {
7696     // Dealloc the space to subfaces.
7697     if (fliptets[0].tet[9] != nullptr) {
7698       tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7699       fliptets[0].tet[9] = nullptr;
7700     }
7701     if (fliptets[1].tet[9] != nullptr) {
7702       tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7703       fliptets[1].tet[9] = nullptr;
7704     }
7705   }
7706   if (checksubfaceflag) {
7707     if (scount > 0) {
7708       // The element attributes and volume constraint must be set correctly.
7709       // There are two subfaces involved in this flip. The three tets are
7710       //   separated into two different regions, one may be exterior. The
7711       //   first region has two tets, and the second region has only one.
7712       //   The two created tets must be in the same region as the first region.
7713       //   The element attributes and volume constraint must be set correctly.
7714       //assert(spivot != -1);
7715       // The tet fliptets[spivot] is in the first region.
7716       for (j = 0; j < 2; j++) {
7717         for (i = 0; i < numelemattrib; i++) {
7718           attrib = elemattribute(fliptets[spivot].tet, i);
7719           setelemattribute(fliptets[j].tet, i, attrib);
7720         }
7721         if (b->varvolume) {
7722           volume = volumebound(fliptets[spivot].tet);
7723           setvolumebound(fliptets[j].tet, volume);
7724         }
7725       }
7726     }
7727   }
7728   // Delete an old tet.
7729   tetrahedrondealloc(fliptets[2].tet);
7730 
7731   if (hullflag > 0) {
7732     // Check if c is dummypointc.
7733     if (pc != dummypoint) {
7734       // Check if d is dummypoint.
7735       if (pd != dummypoint) {
7736         // No hull tet is involved.
7737       } else {
7738         // We deleted three hull tets, and created one hull tet.
7739         hullsize -= 2;
7740       }
7741       setvertices(fliptets[0], pa, pb, pc, pd);
7742       setvertices(fliptets[1], pb, pa, pc, pe);
7743     } else {
7744       // c is dummypoint. The two new tets are hull tets.
7745       setvertices(fliptets[0], pb, pa, pd, pc);
7746       setvertices(fliptets[1], pa, pb, pe, pc);
7747       // Adjust badc -> abcd.
7748       esymself(fliptets[0]);
7749       // Adjust abec -> bace.
7750       esymself(fliptets[1]);
7751       // The hullsize does not change.
7752     }
7753   } else {
7754     setvertices(fliptets[0], pa, pb, pc, pd);
7755     setvertices(fliptets[1], pb, pa, pc, pe);
7756   }
7757 
7758   if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7759     REAL volneg[3], volpos[2], vol_diff;
7760     if (pc != dummypoint) {
7761       if (pd != dummypoint) {
7762         volneg[0] = tetprismvol(pe, pd, pa, pb);
7763         volneg[1] = tetprismvol(pe, pd, pb, pc);
7764         volneg[2] = tetprismvol(pe, pd, pc, pa);
7765         volpos[0] = tetprismvol(pa, pb, pc, pd);
7766         volpos[1] = tetprismvol(pb, pa, pc, pe);
7767       } else { // pd == dummypoint
7768         volneg[0] = 0.;
7769         volneg[1] = 0.;
7770         volneg[2] = 0.;
7771         volpos[0] = 0.;
7772         volpos[1] = tetprismvol(pb, pa, pc, pe);
7773       }
7774     } else { // pc == dummypoint.
7775       volneg[0] = tetprismvol(pe, pd, pa, pb);
7776       volneg[1] = 0.;
7777       volneg[2] = 0.;
7778       volpos[0] = 0.;
7779       volpos[1] = 0.;
7780     }
7781     vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
7782     fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
7783   }
7784 
7785   // Bond abcd <==> bace.
7786   bond(fliptets[0], fliptets[1]);
7787   // Bond new faces to top outer boundary faces (at abcd).
7788   for (i = 0; i < 3; i++) {
7789     esym(fliptets[0], newface);
7790     bond(newface, topcastets[i]);
7791     enextself(fliptets[0]);
7792   }
7793   // Bond new faces to bottom outer boundary faces (at bace).
7794   for (i = 0; i < 3; i++) {
7795     esym(fliptets[1], newface);
7796     bond(newface, botcastets[i]);
7797     eprevself(fliptets[1]);
7798   }
7799 
7800   if (checksubsegflag) {
7801     // Bond 9 segments to new (flipped) tets.
7802     for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
7803       if (issubseg(topcastets[i])) {
7804         tsspivot1(topcastets[i], checkseg);
7805         tssbond1(fliptets[0], checkseg);
7806         sstbond1(checkseg, fliptets[0]);
7807         tssbond1(fliptets[1], checkseg);
7808         sstbond1(checkseg, fliptets[1]);
7809         if (fc->chkencflag & 1) {
7810           enqueuesubface(badsubsegs, &checkseg);
7811         }
7812       }
7813       enextself(fliptets[0]);
7814       eprevself(fliptets[1]);
7815     }
7816     // The three top edges.
7817     for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
7818       esym(fliptets[0], newface);
7819       eprevself(newface);
7820       enext(topcastets[i], casface);
7821       if (issubseg(casface)) {
7822         tsspivot1(casface, checkseg);
7823         tssbond1(newface, checkseg);
7824         sstbond1(checkseg, newface);
7825         if (fc->chkencflag & 1) {
7826           enqueuesubface(badsubsegs, &checkseg);
7827         }
7828       }
7829       enextself(fliptets[0]);
7830     }
7831     // The three bot edges.
7832     for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
7833       esym(fliptets[1], newface);
7834       enextself(newface);
7835       eprev(botcastets[i], casface);
7836       if (issubseg(casface)) {
7837         tsspivot1(casface, checkseg);
7838         tssbond1(newface, checkseg);
7839         sstbond1(checkseg, newface);
7840         if (fc->chkencflag & 1) {
7841           enqueuesubface(badsubsegs, &checkseg);
7842         }
7843       }
7844       eprevself(fliptets[1]);
7845     }
7846   } // if (checksubsegflag)
7847 
7848   if (checksubfaceflag) {
7849     face checksh;
7850     // Bond the top three casing subfaces.
7851     for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
7852       if (issubface(topcastets[i])) {
7853         tspivot(topcastets[i], checksh);
7854         esym(fliptets[0], newface);
7855         sesymself(checksh);
7856         tsbond(newface, checksh);
7857         if (fc->chkencflag & 2) {
7858           enqueuesubface(badsubfacs, &checksh);
7859         }
7860       }
7861       enextself(fliptets[0]);
7862     }
7863     // Bond the bottom three casing subfaces.
7864     for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
7865       if (issubface(botcastets[i])) {
7866         tspivot(botcastets[i], checksh);
7867         esym(fliptets[1], newface);
7868         sesymself(checksh);
7869         tsbond(newface, checksh);
7870         if (fc->chkencflag & 2) {
7871           enqueuesubface(badsubfacs, &checksh);
7872         }
7873       }
7874       eprevself(fliptets[1]);
7875     }
7876 
7877     if (scount > 0) {
7878       face flipfaces[2];
7879       // Perform a 2-to-2 flip in subfaces.
7880       flipfaces[0] = flipshs[(spivot + 1) % 3];
7881       flipfaces[1] = flipshs[(spivot + 2) % 3];
7882       sesymself(flipfaces[1]);
7883       flip22(flipfaces, 0, fc->chkencflag);
7884       // Connect the flipped subfaces to flipped tets.
7885       // First go to the corresponding flipping edge.
7886       //   Re-use top- and botcastets[0].
7887       topcastets[0] = fliptets[0];
7888       botcastets[0] = fliptets[1];
7889       for (i = 0; i < ((spivot + 1) % 3); i++) {
7890         enextself(topcastets[0]);
7891         eprevself(botcastets[0]);
7892       }
7893       // Connect the top subface to the top tets.
7894       esymself(topcastets[0]);
7895       sesymself(flipfaces[0]);
7896       // Check if there already exists a subface.
7897       tspivot(topcastets[0], checksh);
7898       if (checksh.sh == nullptr) {
7899         tsbond(topcastets[0], flipfaces[0]);
7900         fsymself(topcastets[0]);
7901         sesymself(flipfaces[0]);
7902         tsbond(topcastets[0], flipfaces[0]);
7903       } else {
7904         // An invalid 2-to-2 flip.
7905         assert(0);
7906       }
7907       // Connect the bot subface to the bottom tets.
7908       esymself(botcastets[0]);
7909       sesymself(flipfaces[1]);
7910       // Check if there already exists a subface.
7911       tspivot(botcastets[0], checksh);
7912       if (checksh.sh == nullptr) {
7913         tsbond(botcastets[0], flipfaces[1]);
7914         fsymself(botcastets[0]);
7915         sesymself(flipfaces[1]);
7916         tsbond(botcastets[0], flipfaces[1]);
7917       } else {
7918         // An invalid 2-to-2 flip.
7919         assert(0);
7920       }
7921     } // if (scount > 0)
7922   } // if (checksubfaceflag)
7923 
7924   if (fc->chkencflag & 4) {
7925     // Put two new tets into check list.
7926     for (i = 0; i < 2; i++) {
7927       enqueuetetrahedron(&(fliptets[i]));
7928     }
7929   }
7930 
7931   setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
7932   setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
7933   setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
7934   setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
7935   setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
7936 
7937   if (hullflag > 0) {
7938     if (dummyflag != 0) {
7939       // Restore the original position of the points (for flipnm()).
7940       if (dummyflag == -1) {
7941         // e were dummypoint. Swap the two new tets.
7942         newface = fliptets[0];
7943         fliptets[0] = fliptets[1];
7944         fliptets[1] = newface;
7945       } else {
7946         // a or b was dummypoint.
7947         if (dummyflag == 1) {
7948           eprevself(fliptets[0]);
7949           enextself(fliptets[1]);
7950         } else { // dummyflag == 2
7951           enextself(fliptets[0]);
7952           eprevself(fliptets[1]);
7953         }
7954       }
7955     }
7956   }
7957 
7958   if (fc->enqflag > 0) {
7959     // Queue faces which may be locally non-Delaunay.
7960     // pa = org(fliptets[0]); // 'a' may be a new vertex.
7961     enextesym(fliptets[0], newface);
7962     flippush(flipstack, &newface);
7963     eprevesym(fliptets[1], newface);
7964     flippush(flipstack, &newface);
7965     if (fc->enqflag > 1) {
7966       //pb = dest(fliptets[0]);
7967       eprevesym(fliptets[0], newface);
7968       flippush(flipstack, &newface);
7969       enextesym(fliptets[1], newface);
7970       flippush(flipstack, &newface);
7971       //pc = apex(fliptets[0]);
7972       esym(fliptets[0], newface);
7973       flippush(flipstack, &newface);
7974       esym(fliptets[1], newface);
7975       flippush(flipstack, &newface);
7976     }
7977   }
7978 
7979   recenttet = fliptets[0];
7980 }
7981 
7982 ///////////////////////////////////////////////////////////////////////////////
7983 //                                                                           //
7984 // flip41()    Perform a 4-to-1 flip (Remove a vertex).                      //
7985 //                                                                           //
7986 // 'fliptets' is an array of four tetrahedra in the star of the removing     //
7987 // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
7988 // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
7989 // p].  On return, 'fliptets[0]' is the new tet [a,b,c,d].                   //
7990 //                                                                           //
7991 // If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
7992 // The 'hullsize' may be changed.  Note that p may be dummypoint.  In this   //
7993 // case, four hull tets are replaced by one real tet.                        //
7994 //                                                                           //
7995 // If 'checksubface' flag is set (>0), it is possible that there are three   //
7996 // interior subfaces connecting at p.  If so, a 3-to-1 flip is performed to  //
7997 // to remove p from the surface triangulation.                               //
7998 //                                                                           //
7999 // If it is called by the routine incrementalflip(), we assume that d is the //
8000 // newly inserted vertex.                                                    //
8001 //                                                                           //
8002 ///////////////////////////////////////////////////////////////////////////////
8003 
flip41(triface * fliptets,int hullflag,flipconstraints * fc)8004 void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
8005 {
8006   triface topcastets[3], botcastet;
8007   triface newface, neightet;
8008   face flipshs[4];
8009   point pa, pb, pc, pd, pp;
8010   int dummyflag = 0; // in {0, 1, 2, 3, 4}
8011   int spivot = -1, scount = 0;
8012   int t1ver;
8013   int i;
8014 
8015   pa =  org(fliptets[3]);
8016   pb = dest(fliptets[3]);
8017   pc = apex(fliptets[3]);
8018   pd = dest(fliptets[0]);
8019   pp =  org(fliptets[0]); // The removing vertex.
8020 
8021   flip41count++;
8022 
8023   // Get the outer boundary faces.
8024   for (i = 0; i < 3; i++) {
8025     enext(fliptets[i], topcastets[i]);
8026     fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
8027     enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
8028   }
8029   fsym(fliptets[3], botcastet); // [b,a,c,#]
8030 
8031   if (checksubfaceflag) {
8032     // Check if there are three subfaces at 'p'.
8033     //   Re-use 'newface'.
8034     for (i = 0; i < 3; i++) {
8035       fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
8036       tspivot(newface, flipshs[i]);
8037       if (flipshs[i].sh != nullptr) {
8038         spivot = i; // Remember this subface.
8039         scount++;
8040       }
8041       enextself(fliptets[3]);
8042     }
8043     if (scount > 0) {
8044       // There are three subfaces connecting at p.
8045       if (scount < 3) {
8046         // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
8047         assert(scount == 1); // spivot >= 0
8048         // Go to the tet containing the three subfaces.
8049         fsym(topcastets[spivot], neightet);
8050         // Get the three subfaces connecting at p.
8051         for (i = 0; i < 3; i++) {
8052           esym(neightet, newface);
8053           tspivot(newface, flipshs[i]);
8054           assert(flipshs[i].sh != nullptr);
8055           eprevself(neightet);
8056         }
8057       } else {
8058         spivot = 3; // The new subface is [a,b,c].
8059       }
8060     }
8061   } // if (checksubfaceflag)
8062 
8063 
8064   // Re-use fliptets[0] for [a,b,c,d].
8065   fliptets[0].ver = 11;
8066   setelemmarker(fliptets[0].tet, 0); // Clean all flags.
8067   // NOTE: the element attributes and volume constraint remain unchanged.
8068   if (checksubsegflag) {
8069     // Dealloc the space to subsegments.
8070     if (fliptets[0].tet[8] != nullptr) {
8071       tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
8072       fliptets[0].tet[8] = nullptr;
8073     }
8074   }
8075   if (checksubfaceflag) {
8076     // Dealloc the space to subfaces.
8077     if (fliptets[0].tet[9] != nullptr) {
8078       tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
8079       fliptets[0].tet[9] = nullptr;
8080     }
8081   }
8082   // Delete the other three tets.
8083   for (i = 1; i < 4; i++) {
8084     tetrahedrondealloc(fliptets[i].tet);
8085   }
8086 
8087   if (pp != dummypoint) {
8088     // Mark the point pp as unused.
8089     setpointtype(pp, UNUSEDVERTEX);
8090     unuverts++;
8091   }
8092 
8093   // Create the new tet [a,b,c,d].
8094   if (hullflag > 0) {
8095     // One of the five vertices may be 'dummypoint'.
8096     if (pa == dummypoint) {
8097       // pa is dummypoint.
8098       setvertices(fliptets[0], pc, pb, pd, pa);
8099       esymself(fliptets[0]);  // [b,c,a,d]
8100       eprevself(fliptets[0]); // [a,b,c,d]
8101       dummyflag = 1;
8102     } else if (pb == dummypoint) {
8103       setvertices(fliptets[0], pa, pc, pd, pb);
8104       esymself(fliptets[0]);  // [c,a,b,d]
8105       enextself(fliptets[0]); // [a,b,c,d]
8106       dummyflag = 2;
8107     } else if (pc == dummypoint) {
8108       setvertices(fliptets[0], pb, pa, pd, pc);
8109       esymself(fliptets[0]);  // [a,b,c,d]
8110       dummyflag = 3;
8111     } else if (pd == dummypoint) {
8112       setvertices(fliptets[0], pa, pb, pc, pd);
8113       dummyflag = 4;
8114     } else {
8115       setvertices(fliptets[0], pa, pb, pc, pd);
8116       if (pp == dummypoint) {
8117         dummyflag = -1;
8118       } else {
8119         dummyflag = 0;
8120       }
8121     }
8122     if (dummyflag > 0) {
8123       // We deleted 3 hull tets, and create 1 hull tet.
8124       hullsize -= 2;
8125     } else if (dummyflag < 0) {
8126       // We deleted 4 hull tets.
8127       hullsize -= 4;
8128       // meshedges does not change.
8129     }
8130   } else {
8131     setvertices(fliptets[0], pa, pb, pc, pd);
8132   }
8133 
8134   if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
8135     REAL volneg[4], volpos[1], vol_diff;
8136     if (dummyflag > 0) {
8137       if (pa == dummypoint) {
8138         volneg[0] = 0.;
8139         volneg[1] = tetprismvol(pp, pd, pb, pc);
8140         volneg[2] = 0.;
8141         volneg[3] = 0.;
8142       } else if (pb == dummypoint) {
8143         volneg[0] = 0.;
8144         volneg[1] = 0.;
8145         volneg[2] = tetprismvol(pp, pd, pc, pa);
8146         volneg[3] = 0.;
8147       } else if (pc == dummypoint) {
8148         volneg[0] = tetprismvol(pp, pd, pa, pb);
8149         volneg[1] = 0.;
8150         volneg[2] = 0.;
8151         volneg[3] = 0.;
8152       } else { // pd == dummypoint
8153         volneg[0] = 0.;
8154         volneg[1] = 0.;
8155         volneg[2] = 0.;
8156         volneg[3] = tetprismvol(pa, pb, pc, pp);
8157       }
8158       volpos[0] = 0.;
8159     } else if (dummyflag < 0) {
8160       volneg[0] = 0.;
8161       volneg[1] = 0.;
8162       volneg[2] = 0.;
8163       volneg[3] = 0.;
8164       volpos[0] = tetprismvol(pa, pb, pc, pd);
8165     } else {
8166       volneg[0] = tetprismvol(pp, pd, pa, pb);
8167       volneg[1] = tetprismvol(pp, pd, pb, pc);
8168       volneg[2] = tetprismvol(pp, pd, pc, pa);
8169       volneg[3] = tetprismvol(pa, pb, pc, pp);
8170       volpos[0] = tetprismvol(pa, pb, pc, pd);
8171     }
8172     vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
8173     fc->tetprism_vol_sum  += vol_diff; // Update the total sum.
8174   }
8175 
8176   // Bond the new tet to adjacent tets.
8177   for (i = 0; i < 3; i++) {
8178     esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
8179     bond(newface, topcastets[i]);
8180     enextself(fliptets[0]);
8181   }
8182   bond(fliptets[0], botcastet);
8183 
8184   if (checksubsegflag) {
8185     face checkseg;
8186     // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
8187     for (i = 0; i < 3; i++) {
8188       eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
8189       if (issubseg(newface)) {
8190         tsspivot1(newface, checkseg);
8191         esym(fliptets[0], newface);
8192         enextself(newface); // At edges [a,d], [b,d], [c,d].
8193         tssbond1(newface, checkseg);
8194         sstbond1(checkseg, newface);
8195         if (fc->chkencflag & 1) {
8196           enqueuesubface(badsubsegs, &checkseg);
8197         }
8198       }
8199       enextself(fliptets[0]);
8200     }
8201     for (i = 0; i < 3; i++) {
8202       if (issubseg(topcastets[i])) {
8203         tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
8204         tssbond1(fliptets[0], checkseg);
8205         sstbond1(checkseg, fliptets[0]);
8206         if (fc->chkencflag & 1) {
8207           enqueuesubface(badsubsegs, &checkseg);
8208         }
8209       }
8210       enextself(fliptets[0]);
8211     }
8212   }
8213 
8214   if (checksubfaceflag) {
8215     face checksh;
8216     // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
8217     for (i = 0; i < 3; i++) {
8218       if (issubface(topcastets[i])) {
8219         tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
8220         esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
8221         sesymself(checksh);
8222         tsbond(newface, checksh);
8223         if (fc->chkencflag & 2) {
8224           enqueuesubface(badsubfacs, &checksh);
8225         }
8226       }
8227       enextself(fliptets[0]);
8228     }
8229     if (issubface(botcastet)) {
8230       tspivot(botcastet, checksh); // At face [b,a,c]
8231       sesymself(checksh);
8232       tsbond(fliptets[0], checksh);
8233       if (fc->chkencflag & 2) {
8234         enqueuesubface(badsubfacs, &checksh);
8235       }
8236     }
8237 
8238     if (spivot >= 0) {
8239       // Perform a 3-to-1 flip in surface triangulation.
8240       // Depending on the value of 'spivot', the three subfaces are:
8241       //   - 0: [a,b,p], [b,d,p], [d,a,p]
8242       //   - 1: [b,c,p], [c,d,p], [d,b,p]
8243       //   - 2: [c,a,p], [a,d,p], [d,c,p]
8244       //   - 3: [a,b,p], [b,c,p], [c,a,p]
8245       // Adjust the three subfaces such that their origins are p, i.e.,
8246       //   - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
8247       for (i = 0; i < 3; i++) {
8248         senext2self(flipshs[i]);
8249       }
8250       flip31(flipshs, 0);
8251       // Delete the three old subfaces.
8252       for (i = 0; i < 3; i++) {
8253         shellfacedealloc(subfaces, flipshs[i].sh);
8254       }
8255       if (spivot < 3) {
8256         // // Bond the new subface to the new tet [a,b,c,d].
8257         tsbond(topcastets[spivot], flipshs[3]);
8258         fsym(topcastets[spivot], newface);
8259         sesym(flipshs[3], checksh);
8260         tsbond(newface, checksh);
8261       } else {
8262         // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
8263         tsbond(fliptets[0], flipshs[3]);
8264         fsym(fliptets[0], newface);
8265         sesym(flipshs[3], checksh);
8266         tsbond(newface, checksh);
8267       }
8268     } // if (spivot > 0)
8269   } // if (checksubfaceflag)
8270 
8271   if (fc->chkencflag & 4) {
8272     enqueuetetrahedron(&(fliptets[0]));
8273   }
8274 
8275   // Update the point-to-tet map.
8276   setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8277   setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8278   setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8279   setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8280 
8281   if (fc->enqflag > 0) {
8282     // Queue faces which may be locally non-Delaunay.
8283     flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
8284     if (fc->enqflag > 1) {
8285       for (i = 0; i < 3; i++) {
8286         esym(fliptets[0], newface);
8287         flippush(flipstack, &newface);
8288         enextself(fliptets[0]);
8289       }
8290     }
8291   }
8292 
8293   recenttet = fliptets[0];
8294 }
8295 
8296 ///////////////////////////////////////////////////////////////////////////////
8297 //                                                                           //
8298 // flipnm()    Flip an edge through a sequence of elementary flips.          //
8299 //                                                                           //
8300 // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
8301 // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
8302 // use the right-hand rule.                                                  //
8303 //                                                                           //
8304 // 'level' (>= 0) indicates the current link level. If 'level > 0', we are   //
8305 // flipping a link edge of an edge [a',b'],  and 'abedgepivot' indicates     //
8306 // which link edge, i.e., [c',b'] or [a',c'], is [a,b]  These two parameters //
8307 // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that   //
8308 // do not inside the reduced star of edge [a',b'].                           //
8309 //                                                                           //
8310 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8311 // in flipnm([a,b]) so that the mesh is returned to its original state       //
8312 // before doing the flipnm([a,b]) operation.                                 //
8313 //                                                                           //
8314 // The return value is an integer nn, where nn <= n.  If nn is 2, then the   //
8315 // edge is flipped.  The first and the second tets in 'abtets' are new tets. //
8316 // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets  //
8317 // in the current star of [a,b].                                             //
8318 //                                                                           //
8319 // ASSUMPTIONS:                                                              //
8320 //  - Neither a nor b is 'dummypoint'.                                       //
8321 //  - [a,b] must not be a segment.                                           //
8322 //                                                                           //
8323 ///////////////////////////////////////////////////////////////////////////////
8324 
flipnm(triface * abtets,int n,int level,int abedgepivot,flipconstraints * fc)8325 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
8326                        flipconstraints* fc)
8327 {
8328   triface fliptets[3], spintet, flipedge;
8329   triface *tmpabtets, *parytet;
8330   point pa, pb, pc, pd, pe, pf;
8331   REAL ori;
8332   int hullflag;
8333   int reducflag, rejflag;
8334   int reflexlinkedgecount;
8335   int edgepivot;
8336   int n1, nn;
8337   int t1ver;
8338   int i, j;
8339 
8340   pa = org(abtets[0]);
8341   pb = dest(abtets[0]);
8342 
8343   if (n > 3) {
8344     // Try to reduce the size of the Star(ab) by flipping a face in it.
8345     reflexlinkedgecount = 0;
8346 
8347     for (i = 0; i < n; i++) {
8348       // Let the face of 'abtets[i]' be [a,b,c].
8349       if (checksubfaceflag) {
8350         if (issubface(abtets[i])) {
8351           continue; // Skip a subface.
8352         }
8353       }
8354       // Do not flip this face if it is involved in two Stars.
8355       if ((elemcounter(abtets[i]) > 1) ||
8356           (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8357         continue;
8358       }
8359 
8360       pc = apex(abtets[i]);
8361       pd = apex(abtets[(i + 1) % n]);
8362       pe = apex(abtets[(i - 1 + n) % n]);
8363       if ((pd == dummypoint) || (pe == dummypoint)) {
8364         continue; // [a,b,c] is a hull face.
8365       }
8366 
8367 
8368       // Decide whether [a,b,c] is flippable or not.
8369       reducflag = 0;
8370 
8371       hullflag = (pc == dummypoint); // pc may be dummypoint.
8372       if (hullflag == 0) {
8373         ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
8374         if (ori > 0) {
8375           ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
8376           if (ori > 0) {
8377             // Test if [a,b] is locally convex OR flat.
8378             ori = orient3d(pa, pb, pd, pe);
8379             if (ori > 0) {
8380               // Found a 2-to-3 flip: [a,b,c] => [e,d]
8381               reducflag = 1;
8382             } else if (ori == 0) {
8383               // [a,b] is flat.
8384               if (n == 4) {
8385                 // The "flat" tet can be removed immedately by a 3-to-2 flip.
8386                 reducflag = 1;
8387               }
8388             }
8389           }
8390         }
8391         if (!reducflag) {
8392           reflexlinkedgecount++;
8393         }
8394       } else {
8395         // 'c' is dummypoint.
8396         if (n == 4) {
8397           // Let the vertex opposite to 'c' is 'f'.
8398           // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
8399           //   are valid tets.
8400           // Note: When the mesh is not convex, it is possible that [a,b] is
8401           //   locally non-convex (at hull faces [a,b,e] and [b,a,d]).
8402           //   In this case, an edge flip [a,b] to [e,d] is still possible.
8403           pf = apex(abtets[(i + 2) % n]);
8404           assert(pf != dummypoint);
8405           ori = orient3d(pd, pe, pf, pa);
8406           if (ori < 0) {
8407             ori = orient3d(pe, pd, pf, pb);
8408             if (ori < 0) {
8409               // Found a 4-to-4 flip: [a,b] => [e,d]
8410               reducflag = 1;
8411               ori = 0; // Signal as a 4-to-4 flip (like a co-palanar case).
8412             }
8413           }
8414         }
8415       } // if (hullflag)
8416 
8417       if (reducflag) {
8418         // [a,b,c] could be removed by a 2-to-3 flip.
8419         rejflag = 0;
8420         if (fc->checkflipeligibility) {
8421           // Check if the flip can be performed.
8422           rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
8423                                          abedgepivot, fc);
8424         }
8425         if (!rejflag) {
8426           // Do flip: [a,b,c] => [e,d].
8427           fliptets[0] = abtets[i];
8428           fsym(fliptets[0], fliptets[1]); // abtets[i-1].
8429           flip23(fliptets, hullflag, fc);
8430 
8431           // Shrink the array 'abtets', maintain the original order.
8432           //   Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
8433           //   are flipped, i.e., they do not in Star(ab) anymore.
8434           //   'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
8435           //   'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
8436           //
8437           //            before                   after
8438           //     [0] |___________|        [0] |___________|
8439           //     ... |___________|        ... |___________|
8440           //   [i-1] |_[a,b,e,c]_|      [i-1] |_[a,b,e,d]_|
8441           //     [i] |_[a,b,c,d]_| -->    [i] |_[a,b,d,#]_|
8442           //   [i+1] |_[a,b,d,#]_|      [i+1] |_[a,b,#,*]_|
8443           //     ... |___________|        ... |___________|
8444           //   [n-2] |___________|      [n-2] |___________|
8445           //   [n-1] |___________|      [n-1] |_[i]_2-t-3_|
8446           //
8447           edestoppoself(fliptets[0]); // [a,b,e,d]
8448           // Increase the counter of this new tet (it is in Star(ab)).
8449           increaseelemcounter(fliptets[0]);
8450           abtets[(i - 1 + n) % n] = fliptets[0];
8451           for (j = i; j < n - 1; j++) {
8452             abtets[j] = abtets[j + 1];  // Upshift
8453           }
8454           // The last entry 'abtets[n-1]' is empty. It is used in two ways:
8455           //   (i) it remebers the vertex 'c' (in 'abtets[n-1].tet'), and
8456           //  (ii) it remebers the position [i] where this flip took place.
8457           // These informations let us to either undo this flip or recover
8458           //   the original edge link (for collecting new created tets).
8459           //abtets[n - 1] = fliptets[1]; // [e,d,b,c] is remebered.
8460           abtets[n - 1].tet = (tetrahedron *) pc;
8461           abtets[n - 1].ver = 0; // Clear it.
8462           // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
8463           // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
8464           abtets[n - 1].ver |= (1 << 4);
8465           // The poisition [i] of this flip is saved above the 7th bit.
8466           abtets[n - 1].ver |= (i << 6);
8467 
8468           if (fc->collectnewtets) {
8469             // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
8470             //   Re-use the global array 'cavetetlist'.
8471             for (j = 1; j < 3; j++) {
8472               cavetetlist->newindex((void **) &parytet);
8473               *parytet = fliptets[j]; // fliptets[1], fliptets[2].
8474             }
8475           }
8476 
8477           // Star(ab) is reduced. Try to flip the edge [a,b].
8478           nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8479 
8480           if (nn == 2) {
8481             // The edge has been flipped.
8482             return nn;
8483           } else { // if (nn > 2)
8484             // The edge is not flipped.
8485             if (fc->unflip || (ori == 0)) {
8486               // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
8487               //   transform [e,d] => [a,b,c].
8488               // 'ori == 0' means that the previous flip created a degenrated
8489               //   tet. It must be removed.
8490               // Remeber that 'abtets[i-1]' is [a,b,e,d]. We can use it to
8491               //   find another two tets [e,d,b,c] and [e,d,c,a].
8492               fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
8493               edestoppoself(fliptets[0]); // [e,d,a,b]
8494               fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
8495               fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
8496               assert(apex(fliptets[0]) == oppo(fliptets[2])); // SELF_CHECK
8497               // Restore the two original tets in Star(ab).
8498               flip32(fliptets, hullflag, fc);
8499               // Marktest the two restored tets in Star(ab).
8500               for (j = 0; j < 2; j++) {
8501                 increaseelemcounter(fliptets[j]);
8502               }
8503               // Expand the array 'abtets', maintain the original order.
8504               for (j = n - 2; j>= i; j--) {
8505                 abtets[j + 1] = abtets[j];  // Downshift
8506               }
8507               // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
8508               //  'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
8509               //  respectively.
8510               esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
8511               abtets[i] = fliptets[0]; // [a,b,c,d]
8512               nn++;
8513               if (fc->collectnewtets) {
8514                 // Pop two (flipped) tets from the stack.
8515                 cavetetlist->objects -= 2;
8516               }
8517             } // if (upflip || (ori == 0))
8518           } // if (nn > 2)
8519 
8520           if (!fc->unflip) {
8521             // The flips are not reversed. The current Star(ab) can not be
8522             //   further reduced. Return its current size (# of tets).
8523             return nn;
8524           }
8525           // unflip is set.
8526           // Continue the search for flips.
8527         }
8528       } // if (reducflag)
8529     } // i
8530 
8531     // The Star(ab) is not reduced.
8532     if (reflexlinkedgecount > 0) {
8533       // There are reflex edges in the Link(ab).
8534       if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
8535           ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
8536         // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
8537         for (i = 0; i < n; i++) {
8538           // Do not flip this face [a,b,c] if there are two Stars involved.
8539           if ((elemcounter(abtets[i]) > 1) ||
8540               (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8541             continue;
8542           }
8543           pc = apex(abtets[i]);
8544           if (pc == dummypoint) {
8545             continue; // [a,b] is a hull edge.
8546           }
8547           pd = apex(abtets[(i + 1) % n]);
8548           pe = apex(abtets[(i - 1 + n) % n]);
8549           if ((pd == dummypoint) || (pe == dummypoint)) {
8550             continue; // [a,b,c] is a hull face.
8551           }
8552 
8553 
8554           edgepivot = 0; // No edge is selected yet.
8555 
8556           // Test if [b,c] is locally convex or flat.
8557           ori = orient3d(pb, pc, pd, pe);
8558           if (ori <= 0) {
8559             // Select the edge [c,b].
8560             enext(abtets[i], flipedge); // [b,c,a,d]
8561             edgepivot = 1;
8562           }
8563           if (!edgepivot) {
8564             // Test if [c,a] is locally convex or flat.
8565             ori = orient3d(pc, pa, pd, pe);
8566             if (ori <= 0) {
8567               // Select the edge [a,c].
8568               eprev(abtets[i], flipedge); // [c,a,b,d].
8569               edgepivot = 2;
8570             }
8571           }
8572 
8573           if (!edgepivot) continue;
8574 
8575           // An edge is selected.
8576           if (checksubsegflag) {
8577             // Do not flip it if it is a segment.
8578             if (issubseg(flipedge)) {
8579               if (fc->collectencsegflag) {
8580                 face checkseg, *paryseg;
8581                 tsspivot1(flipedge, checkseg);
8582                 if (!sinfected(checkseg)) {
8583                   // Queue this segment in list.
8584                   sinfect(checkseg);
8585                   caveencseglist->newindex((void **) &paryseg);
8586                   *paryseg = checkseg;
8587                 }
8588               }
8589               continue;
8590             }
8591           }
8592 
8593           // Try to flip the selected edge ([c,b] or [a,c]).
8594           esymself(flipedge);
8595           // Count the number of tets at the edge.
8596           n1 = 0;
8597           j = 0; // Sum of the star counters.
8598           spintet = flipedge;
8599           while (1) {
8600             n1++;
8601             j += (elemcounter(spintet));
8602             fnextself(spintet);
8603             if (spintet.tet == flipedge.tet) break;
8604           }
8605           assert(n1 >= 3);
8606           if (j > 2) {
8607             // The Star(flipedge) overlaps other Stars.
8608             continue; // Do not flip this edge.
8609           }
8610           // Only two tets can be marktested.
8611           assert(j == 2);
8612 
8613           if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
8614             // The star size exceeds the given limit.
8615             continue; // Do not flip it.
8616           }
8617 
8618           // Allocate spaces for Star(flipedge).
8619           tmpabtets = new triface[n1];
8620           // Form the Star(flipedge).
8621           j = 0;
8622           spintet = flipedge;
8623           while (1) {
8624             tmpabtets[j] = spintet;
8625             // Increase the star counter of this tet.
8626             increaseelemcounter(tmpabtets[j]);
8627             j++;
8628             fnextself(spintet);
8629             if (spintet.tet == flipedge.tet) break;
8630           }
8631 
8632           // Try to flip the selected edge away.
8633           nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
8634 
8635           if (nn == 2) {
8636             // The edge is flipped. Star(ab) is reduced.
8637             // Shrink the array 'abtets', maintain the original order.
8638             if (edgepivot == 1) {
8639               // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
8640               spintet = tmpabtets[0]; // [d,a,e,b]
8641               enextself(spintet);
8642               esymself(spintet);
8643               enextself(spintet); // [a,b,e,d]
8644             } else {
8645               // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
8646               spintet = tmpabtets[1]; // [b,d,e,a]
8647               eprevself(spintet);
8648               esymself(spintet);
8649               eprevself(spintet); // [a,b,e,d]
8650             } // edgepivot == 2
8651             assert(elemcounter(spintet) == 0); // It's a new tet.
8652             increaseelemcounter(spintet); // It is in Star(ab).
8653             // Put the new tet at [i-1]-th entry.
8654             abtets[(i - 1 + n) % n] = spintet;
8655             for (j = i; j < n - 1; j++) {
8656               abtets[j] = abtets[j + 1];  // Upshift
8657             }
8658             // Remember the flips in the last entry of the array 'abtets'.
8659             // They can be used to recover the flipped edge.
8660             abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
8661             abtets[n - 1].ver = 0; // Clear it.
8662             // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
8663             abtets[n - 1].ver |= edgepivot;
8664             // Use the 6th bit to signal this n1-to-m1 flip.
8665             abtets[n - 1].ver |= (1 << 5);
8666             // The poisition [i] of this flip is saved from 7th to 19th bit.
8667             abtets[n - 1].ver |= (i << 6);
8668             // The size of the star 'n1' is saved from 20th bit.
8669             abtets[n - 1].ver |= (n1 << 19);
8670 
8671             // Remember the flipped link vertex 'c'. It can be used to recover
8672             //   the original edge link of [a,b], and to collect new tets.
8673             tmpabtets[0].tet = (tetrahedron *) pc;
8674             tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
8675 
8676             // Continue to flip the edge [a,b].
8677             nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
8678 
8679             if (nn == 2) {
8680               // The edge has been flipped.
8681               return nn;
8682             } else { // if (nn > 2) {
8683               // The edge is not flipped.
8684               if (fc->unflip) {
8685                 // Recover the flipped edge ([c,b] or [a,c]).
8686                 assert(nn == (n - 1));
8687                 // The sequence of flips are saved in 'tmpabtets'.
8688                 // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
8689                 //   the flipping of edge [c,b] or [a,c].It must still exist in
8690                 //   Star(ab). It is the start tet to recover the flipped edge.
8691                 if (edgepivot == 1) {
8692                   // The flip edge is [c,b].
8693                   tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8694                   eprevself(tmpabtets[0]);
8695                   esymself(tmpabtets[0]);
8696                   eprevself(tmpabtets[0]); // [d,a,e,b]
8697                   fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
8698                 } else {
8699                   // The flip edge is [a,c].
8700                   tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
8701                   enextself(tmpabtets[1]);
8702                   esymself(tmpabtets[1]);
8703                   enextself(tmpabtets[1]); // [b,d,e,a]
8704                   fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
8705                 } // if (edgepivot == 2)
8706 
8707                 // Recover the flipped edge ([c,b] or [a,c]).
8708                 flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
8709 
8710                 // Insert the two recovered tets into Star(ab).
8711                 for (j = n - 2; j >= i; j--) {
8712                   abtets[j + 1] = abtets[j];  // Downshift
8713                 }
8714                 if (edgepivot == 1) {
8715                   // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
8716                   // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
8717                   // tmpabtets[2] is [c,b,e,d]
8718                   fliptets[0] = tmpabtets[1];
8719                   enextself(fliptets[0]);
8720                   esymself(fliptets[0]); // [a,b,e,c]
8721                   fliptets[1] = tmpabtets[0];
8722                   esymself(fliptets[1]);
8723                   eprevself(fliptets[1]); // [a,b,c,d]
8724                 } else {
8725                   // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
8726                   // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
8727                   // tmpabtets[2] is [a,c,e,d]
8728                   fliptets[0] = tmpabtets[1];
8729                   eprevself(fliptets[0]);
8730                   esymself(fliptets[0]); // [a,b,e,c]
8731                   fliptets[1] = tmpabtets[0];
8732                   esymself(fliptets[1]);
8733                   enextself(fliptets[1]); // [a,b,c,d]
8734                 } // edgepivot == 2
8735                 for (j = 0; j < 2; j++) {
8736                   assert(elemcounter(fliptets[j]) == 0); // SELF_CHECK
8737                   increaseelemcounter(fliptets[j]);
8738                 }
8739                 // Insert the two recovered tets into Star(ab).
8740                 abtets[(i - 1 + n) % n] = fliptets[0];
8741                 abtets[i] = fliptets[1];
8742                 nn++;
8743                 // Release the allocated spaces.
8744                 delete [] tmpabtets;
8745               } // if (unflip)
8746             } // if (nn > 2)
8747 
8748             if (!fc->unflip) {
8749               // The flips are not reversed. The current Star(ab) can not be
8750               //   further reduced. Return its size (# of tets).
8751               return nn;
8752             }
8753             // unflip is set.
8754             // Continue the search for flips.
8755           } else {
8756             // The seclected edge is not flipped.
8757             if (fc->unflip) {
8758               // The memory should already be freed.
8759               assert(nn == n1);
8760             } else {
8761               // Release the memory used in this attempted flip.
8762               flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
8763             }
8764             // Decrease the star counters of tets in Star(flipedge).
8765             for (j = 0; j < nn; j++) {
8766               assert(elemcounter(tmpabtets[j]) > 0); // SELF_CHECK
8767               decreaseelemcounter(tmpabtets[j]);
8768             }
8769             // Release the allocated spaces.
8770             delete [] tmpabtets;
8771           }
8772         } // i
8773       } // if (level...)
8774     } // if (reflexlinkedgecount > 0)
8775   } else {
8776     // Check if a 3-to-2 flip is possible.
8777     // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
8778     //   we rearrange them such that the vertex e is dummypoint.
8779     hullflag = 0;
8780 
8781     if (apex(abtets[0]) == dummypoint) {
8782       pc = apex(abtets[1]);
8783       pd = apex(abtets[2]);
8784       pe = apex(abtets[0]);
8785       hullflag = 1;
8786     } else if (apex(abtets[1]) == dummypoint) {
8787       pc = apex(abtets[2]);
8788       pd = apex(abtets[0]);
8789       pe = apex(abtets[1]);
8790       hullflag = 2;
8791     } else {
8792       pc = apex(abtets[0]);
8793       pd = apex(abtets[1]);
8794       pe = apex(abtets[2]);
8795       hullflag = (pe == dummypoint) ? 3 : 0;
8796     }
8797 
8798     reducflag = 0;
8799     rejflag = 0;
8800 
8801 
8802     if (hullflag == 0) {
8803       // Make sure that no inverted tet will be created, i.e. the new tets
8804       //   [d,c,e,a] and [c,d,e,b] must be valid tets.
8805       ori = orient3d(pd, pc, pe, pa);
8806       if (ori < 0) {
8807         ori = orient3d(pc, pd, pe, pb);
8808         if (ori < 0) {
8809           reducflag = 1;
8810         }
8811       }
8812     } else {
8813       // [a,b] is a hull edge.
8814       //   Note: This can happen when it is in the middle of a 4-to-4 flip.
8815       //   Note: [a,b] may even be a non-convex hull edge.
8816       if (!nonconvex) {
8817         //  The mesh is convex, only do flip if it is a coplanar hull edge.
8818         ori = orient3d(pa, pb, pc, pd);
8819         if (ori == 0) {
8820           reducflag = 1;
8821         }
8822       } else { // nonconvex
8823         reducflag = 1;
8824       }
8825       if (reducflag == 1) {
8826         // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
8827         // Make sure that no inverted tet will be created.
8828         point searchpt = nullptr, chkpt;
8829         REAL bigvol = 0.0, ori1, ori2;
8830         // Search an interior vertex which is an apex of edge [c,d].
8831         //   In principle, it can be arbitray interior vertex.  To avoid
8832         //   numerical issue, we choose the vertex which belongs to a tet
8833         //   't' at edge [c,d] and 't' has the biggest volume.
8834         fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
8835         eorgoppoself(fliptets[0]);  // [d,c,b,a]
8836         spintet = fliptets[0];
8837         while (1) {
8838           fnextself(spintet);
8839           chkpt = oppo(spintet);
8840           if (chkpt == pb) break;
8841           if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
8842             ori = -orient3d(pd, pc, apex(spintet), chkpt);
8843             assert(ori > 0);
8844             if (ori > bigvol) {
8845               bigvol = ori;
8846               searchpt = chkpt;
8847             }
8848           }
8849         }
8850         if (searchpt != nullptr) {
8851           // Now valid the configuration.
8852           ori1 = orient3d(pd, pc, searchpt, pa);
8853           ori2 = orient3d(pd, pc, searchpt, pb);
8854           if (ori1 * ori2 >= 0.0) {
8855             reducflag = 0; // Not valid.
8856           } else {
8857             ori1 = orient3d(pa, pb, searchpt, pc);
8858             ori2 = orient3d(pa, pb, searchpt, pd);
8859             if (ori1 * ori2 >= 0.0) {
8860               reducflag = 0; // Not valid.
8861             }
8862           }
8863         } else {
8864           // No valid searchpt is found.
8865           reducflag = 0; // Do not flip it.
8866         }
8867       } // if (reducflag == 1)
8868     } // if (hullflag == 1)
8869 
8870     if (reducflag) {
8871       // A 3-to-2 flip is possible.
8872       if (checksubfaceflag) {
8873         // This edge (must not be a segment) can be flipped ONLY IF it belongs
8874         //   to either 0 or 2 subfaces.  In the latter case, a 2-to-2 flip in
8875         //   the surface mesh will be automatically performed within the
8876         //   3-to-2 flip.
8877         nn = 0;
8878         edgepivot = -1; // Re-use it.
8879         for (j = 0; j < 3; j++) {
8880           if (issubface(abtets[j])) {
8881             nn++; // Found a subface.
8882           } else {
8883             edgepivot = j;
8884           }
8885         }
8886         assert(nn < 3);
8887         if (nn == 1) {
8888           // Found only 1 subface containing this edge. This can happen in
8889           //   the boundary recovery phase. The neighbor subface is not yet
8890           //   recovered. This edge should not be flipped at this moment.
8891           rejflag = 1;
8892         } else if (nn == 2) {
8893           // Found two subfaces. A 2-to-2 flip is possible. Validate it.
8894           // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
8895           eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
8896           if (issubface(spintet)) {
8897             rejflag = 1; // Conflict to a 2-to-2 flip.
8898           } else {
8899             esymself(spintet);
8900             if (issubface(spintet)) {
8901               rejflag = 1; // Conflict to a 2-to-2 flip.
8902             }
8903           }
8904         }
8905       }
8906       if (!rejflag && fc->checkflipeligibility) {
8907         // Here we must exchange 'a' and 'b'. Since in the check... function,
8908         //   we assume the following point sequence, 'a,b,c,d,e', where
8909         //   the face [a,b,c] will be flipped and the edge [e,d] will be
8910         //   created. The two new tets are [a,b,c,d] and [b,a,c,e].
8911         rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
8912                                        abedgepivot, fc);
8913       }
8914       if (!rejflag) {
8915         // Do flip: [a,b] => [c,d,e]
8916         flip32(abtets, hullflag, fc);
8917         if (fc->remove_ndelaunay_edge) {
8918           if (level == 0) {
8919             // It is the desired removing edge. Check if we have improved
8920             //   the objective function.
8921             if ((fc->tetprism_vol_sum >= 0.0) ||
8922                 (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
8923               // No improvement! flip back: [c,d,e] => [a,b].
8924               flip23(abtets, hullflag, fc);
8925               // Increase the element counter -- They are in cavity.
8926               for (j = 0; j < 3; j++) {
8927                 increaseelemcounter(abtets[j]);
8928               }
8929               return 3;
8930             }
8931           } // if (level == 0)
8932         }
8933         if (fc->collectnewtets) {
8934           // Collect new tets.
8935           if (level == 0) {
8936             // Push the two new tets into stack.
8937             for (j = 0; j < 2; j++) {
8938               cavetetlist->newindex((void **) &parytet);
8939               *parytet = abtets[j];
8940             }
8941           } else {
8942             // Only one of the new tets is collected. The other one is inside
8943             //   the reduced edge star. 'abedgepivot' is either '1' or '2'.
8944             cavetetlist->newindex((void **) &parytet);
8945             if (abedgepivot == 1) { // [c,b]
8946               *parytet = abtets[1];
8947             } else {
8948               assert(abedgepivot == 2); // [a,c]
8949               *parytet = abtets[0];
8950             }
8951           }
8952         } // if (fc->collectnewtets)
8953         return 2;
8954       }
8955     } // if (reducflag)
8956   } // if (n == 3)
8957 
8958   // The current (reduced) Star size.
8959   return n;
8960 }
8961 
8962 ///////////////////////////////////////////////////////////////////////////////
8963 //                                                                           //
8964 // flipnm_post()    Post process a n-to-m flip.                              //
8965 //                                                                           //
8966 // IMPORTANT: This routine only works when there is no other flip operation  //
8967 // is done after flipnm([a,b]) which attempts to remove an edge [a,b].       //
8968 //                                                                           //
8969 // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
8970 // [a,b] before flipnm([a,b]).  'nn' (< n) is the value returned by flipnm.  //
8971 // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
8972 // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
8973 // b] and its initial Star([a,b]).  If 'nn >= 3' edge [a,b] still exists in  //
8974 // current mesh and 'nn' is the current number of tets in Star([a,b]).       //
8975 //                                                                           //
8976 // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a      //
8977 // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet        //
8978 // 'abtets[t-1]', where '0 <= t <= i'.  These information can be used to     //
8979 // undo the flips performed in flipnm([a,b]) or to collect new tets created  //
8980 // by the flipnm([a,b]) operation.                                           //
8981 //                                                                           //
8982 // Default, this routine only walks through the flips and frees the spaces   //
8983 // allocated during the flipnm([a,b]) operation.                             //
8984 //                                                                           //
8985 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8986 // in flipnm([a,b]) so that the mesh is returned to its original state       //
8987 // before doing the flipnm([a,b]) operation.                                 //
8988 //                                                                           //
8989 //                                                                           //
8990 ///////////////////////////////////////////////////////////////////////////////
8991 
flipnm_post(triface * abtets,int n,int nn,int abedgepivot,flipconstraints * fc)8992 int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
8993                             flipconstraints* fc)
8994 {
8995   triface fliptets[3], flipface;
8996   triface *tmpabtets;
8997   int fliptype;
8998   int edgepivot;
8999   int t, n1;
9000   int i, j;
9001 
9002 
9003   if (nn == 2) {
9004     // The edge [a,b] has been flipped.
9005     // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
9006     // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
9007     if (fc->unflip) {
9008       // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
9009       flip23(abtets, 1, fc);
9010       if (fc->collectnewtets) {
9011         // Pop up new (flipped) tets from the stack.
9012         if (abedgepivot == 0) {
9013           // Two new tets were collected.
9014           cavetetlist->objects -= 2;
9015         } else {
9016           // Only one of the two new tets was collected.
9017           cavetetlist->objects -= 1;
9018         }
9019       }
9020     }
9021     // The initial size of Star(ab) is 3.
9022     nn++;
9023   }
9024 
9025   // Walk through the performed flips.
9026   for (i = nn; i < n; i++) {
9027     // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
9028     // At the end of this step, the size of the Star([a,b]) is 'i+1'.
9029     // The sizes of the Link([a,b]) are the same.
9030     fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
9031     if (fliptype == 1) {
9032       // It was a 2-to-3 flip: [a,b,c]->[e,d].
9033       t = (abtets[i].ver >> 6);
9034       assert(t <= i);
9035       if (fc->unflip) {
9036         if (b->verbose > 2) {
9037           printf("      Recover a 2-to-3 flip at f[%d].\n", t);
9038         }
9039         // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
9040         //   it is created by a 2-to-3 flip [a,b,c] => [e,d].
9041         fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
9042         eprevself(fliptets[0]);
9043         esymself(fliptets[0]);
9044         enextself(fliptets[0]); // [e,d,a,b]
9045         fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
9046         fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
9047         // Do a 3-to-2 flip: [e,d] => [a,b,c].
9048         // NOTE: hull tets may be invloved.
9049         flip32(fliptets, 1, fc);
9050         // Expand the array 'abtets', maintain the original order.
9051         // The new array length is (i+1).
9052         for (j = i - 1; j >= t; j--) {
9053           abtets[j + 1] = abtets[j];  // Downshift
9054         }
9055         // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
9056         //   'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
9057         //   the (t-1)-th and t-th entries, respectively.
9058         esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
9059         abtets[t] = fliptets[0]; // [a,b,c,d]
9060         if (fc->collectnewtets) {
9061           // Pop up two (flipped) tets from the stack.
9062           cavetetlist->objects -= 2;
9063         }
9064       }
9065     } else if (fliptype == 2) {
9066       tmpabtets = (triface *) (abtets[i].tet);
9067       n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
9068       edgepivot = (abtets[i].ver & 3);
9069       t = ((abtets[i].ver >> 6) & 8191);
9070       assert(t <= i);
9071       if (fc->unflip) {
9072         if (b->verbose > 2) {
9073           printf("      Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
9074                  edgepivot, t);
9075         }
9076         // Recover the flipped edge ([c,b] or [a,c]).
9077         // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
9078         //   the flipping of edge [c,b] or [a,c]. It must still exist in
9079         //   Star(ab). Use it to recover the flipped edge.
9080         if (edgepivot == 1) {
9081           // The flip edge is [c,b].
9082           tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9083           eprevself(tmpabtets[0]);
9084           esymself(tmpabtets[0]);
9085           eprevself(tmpabtets[0]); // [d,a,e,b]
9086           fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
9087         } else {
9088           // The flip edge is [a,c].
9089           tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9090           enextself(tmpabtets[1]);
9091           esymself(tmpabtets[1]);
9092           enextself(tmpabtets[1]); // [b,d,e,a]
9093           fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
9094         } // if (edgepivot == 2)
9095 
9096         // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
9097         flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9098 
9099         // Insert the two recovered tets into the original Star(ab).
9100         for (j = i - 1; j >= t; j--) {
9101           abtets[j + 1] = abtets[j];  // Downshift
9102         }
9103         if (edgepivot == 1) {
9104           // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
9105           // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
9106           // tmpabtets[2] is [c,b,e,d]
9107           fliptets[0] = tmpabtets[1];
9108           enextself(fliptets[0]);
9109           esymself(fliptets[0]); // [a,b,e,c]
9110           fliptets[1] = tmpabtets[0];
9111           esymself(fliptets[1]);
9112           eprevself(fliptets[1]); // [a,b,c,d]
9113         } else {
9114           // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
9115           // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
9116           // tmpabtets[2] is [a,c,e,d]
9117           fliptets[0] = tmpabtets[1];
9118           eprevself(fliptets[0]);
9119           esymself(fliptets[0]); // [a,b,e,c]
9120           fliptets[1] = tmpabtets[0];
9121           esymself(fliptets[1]);
9122           enextself(fliptets[1]); // [a,b,c,d]
9123         } // edgepivot == 2
9124         // Insert the two recovered tets into Star(ab).
9125         abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
9126         abtets[t] = fliptets[1];
9127       }
9128       else {
9129         // Only free the spaces.
9130         flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9131       } // if (!unflip)
9132       if (b->verbose > 2) {
9133         printf("      Release %d spaces at f[%d].\n", n1, i);
9134       }
9135       delete [] tmpabtets;
9136     }
9137   } // i
9138 
9139   return 1;
9140 }
9141 
9142 ///////////////////////////////////////////////////////////////////////////////
9143 //                                                                           //
9144 // insertpoint()    Insert a point into current tetrahedralization.          //
9145 //                                                                           //
9146 // The Bowyer-Watson (B-W) algorithm is used to add a new point p into the   //
9147 // tetrahedralization T. It first finds a "cavity", denoted as C, in T,  C   //
9148 // consists of tetrahedra in T that "conflict" with p.  If T is a Delaunay   //
9149 // tetrahedralization, then all boundary faces (triangles) of C are visible  //
9150 // by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
9151 // tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
9152 // C and p.  If T is not a DT, then C may be not star-shaped.  It must be    //
9153 // modified so that it becomes star-shaped.                                  //
9154 //                                                                           //
9155 ///////////////////////////////////////////////////////////////////////////////
9156 
insertpoint(point insertpt,triface * searchtet,face * splitsh,face * splitseg,insertvertexflags * ivf)9157 int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
9158                             face *splitseg, insertvertexflags *ivf)
9159 {
9160   arraypool *swaplist;
9161   triface *cavetet, spintet, neightet, neineitet, *parytet;
9162   triface oldtet, newtet, newneitet;
9163   face checksh, neighsh, *parysh;
9164   face checkseg, *paryseg;
9165   point *pts, pa, pb, pc, *parypt;
9166   enum locateresult loc = OUTSIDE;
9167   REAL sign, ori;
9168   REAL attrib, volume;
9169   bool enqflag;
9170   int t1ver;
9171   int i, j, k, s;
9172 
9173   if (b->verbose > 2) {
9174     printf("      Insert point %d\n", pointmark(insertpt));
9175   }
9176 
9177   // Locate the point.
9178   if (searchtet->tet != nullptr) {
9179     loc = (enum locateresult) ivf->iloc;
9180   }
9181 
9182   if (loc == OUTSIDE) {
9183     if (searchtet->tet == nullptr) {
9184       if (!b->weighted) {
9185         randomsample(insertpt, searchtet);
9186       } else {
9187         // Weighted DT. There may exist dangling vertex.
9188         *searchtet = recenttet;
9189       }
9190     }
9191     // Locate the point.
9192     loc = locate(insertpt, searchtet, ivf->chkencflag);
9193   }
9194 
9195   ivf->iloc = (int) loc; // The return value.
9196 
9197   if (b->weighted) {
9198     if (loc != OUTSIDE) {
9199       // Check if this vertex is regular.
9200       pts = (point *) searchtet->tet;
9201       assert(pts[7] != dummypoint);
9202       sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9203                         pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9204                         insertpt[3]);
9205       if (sign > 0) {
9206         // This new vertex does not lie below the lower hull. Skip it.
9207         setpointtype(insertpt, NREGULARVERTEX);
9208         nonregularcount++;
9209         ivf->iloc = (int) NONREGULAR;
9210         return 0;
9211       }
9212     }
9213   }
9214 
9215   // Create the initial cavity C(p) which contains all tetrahedra that
9216   //   intersect p. It may include 1, 2, or n tetrahedra.
9217   // If p lies on a segment or subface, also create the initial sub-cavity
9218   //   sC(p) which contains all subfaces (and segment) which intersect p.
9219 
9220   if (loc == OUTSIDE) {
9221     flip14count++;
9222     // The current hull will be enlarged.
9223     // Add four adjacent boundary tets into list.
9224     for (i = 0; i < 4; i++) {
9225       decode(searchtet->tet[i], neightet);
9226       neightet.ver = epivot[neightet.ver];
9227       cavebdrylist->newindex((void **) &parytet);
9228       *parytet = neightet;
9229     }
9230     infect(*searchtet);
9231     caveoldtetlist->newindex((void **) &parytet);
9232     *parytet = *searchtet;
9233   } else if (loc == INTETRAHEDRON) {
9234     flip14count++;
9235     // Add four adjacent boundary tets into list.
9236     for (i = 0; i < 4; i++) {
9237       decode(searchtet->tet[i], neightet);
9238       neightet.ver = epivot[neightet.ver];
9239       cavebdrylist->newindex((void **) &parytet);
9240       *parytet = neightet;
9241     }
9242     infect(*searchtet);
9243     caveoldtetlist->newindex((void **) &parytet);
9244     *parytet = *searchtet;
9245   } else if (loc == ONFACE) {
9246     flip26count++;
9247     // Add six adjacent boundary tets into list.
9248     j = (searchtet->ver & 3); // The current face number.
9249     for (i = 1; i < 4; i++) {
9250       decode(searchtet->tet[(j + i) % 4], neightet);
9251       neightet.ver = epivot[neightet.ver];
9252       cavebdrylist->newindex((void **) &parytet);
9253       *parytet = neightet;
9254     }
9255     decode(searchtet->tet[j], spintet);
9256     j = (spintet.ver & 3); // The current face number.
9257     for (i = 1; i < 4; i++) {
9258       decode(spintet.tet[(j + i) % 4], neightet);
9259       neightet.ver = epivot[neightet.ver];
9260       cavebdrylist->newindex((void **) &parytet);
9261       *parytet = neightet;
9262     }
9263     infect(spintet);
9264     caveoldtetlist->newindex((void **) &parytet);
9265     *parytet = spintet;
9266     infect(*searchtet);
9267     caveoldtetlist->newindex((void **) &parytet);
9268     *parytet = *searchtet;
9269 
9270     if (ivf->splitbdflag) {
9271       if ((splitsh != nullptr) && (splitsh->sh != nullptr)) {
9272         // Create the initial sub-cavity sC(p).
9273         smarktest(*splitsh);
9274         caveshlist->newindex((void **) &parysh);
9275         *parysh = *splitsh;
9276       }
9277     } // if (splitbdflag)
9278   } else if (loc == ONEDGE) {
9279     flipn2ncount++;
9280     // Add all adjacent boundary tets into list.
9281     spintet = *searchtet;
9282     while (1) {
9283       eorgoppo(spintet, neightet);
9284       decode(neightet.tet[neightet.ver & 3], neightet);
9285       neightet.ver = epivot[neightet.ver];
9286       cavebdrylist->newindex((void **) &parytet);
9287       *parytet = neightet;
9288       edestoppo(spintet, neightet);
9289       decode(neightet.tet[neightet.ver & 3], neightet);
9290       neightet.ver = epivot[neightet.ver];
9291       cavebdrylist->newindex((void **) &parytet);
9292       *parytet = neightet;
9293       infect(spintet);
9294       caveoldtetlist->newindex((void **) &parytet);
9295       *parytet = spintet;
9296       fnextself(spintet);
9297       if (spintet.tet == searchtet->tet) break;
9298     } // while (1)
9299 
9300     if (ivf->splitbdflag) {
9301       // Create the initial sub-cavity sC(p).
9302       if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
9303         smarktest(*splitseg);
9304         splitseg->shver = 0;
9305         spivot(*splitseg, *splitsh);
9306       }
9307       if (splitsh != nullptr) {
9308         if (splitsh->sh != nullptr) {
9309           // Collect all subfaces share at this edge.
9310           pa = sorg(*splitsh);
9311           neighsh = *splitsh;
9312           while (1) {
9313             // Adjust the origin of its edge to be 'pa'.
9314             if (sorg(neighsh) != pa) {
9315               sesymself(neighsh);
9316             }
9317             // Add this face into list (in B-W cavity).
9318             smarktest(neighsh);
9319             caveshlist->newindex((void **) &parysh);
9320             *parysh = neighsh;
9321             // Add this face into face-at-splitedge list.
9322             cavesegshlist->newindex((void **) &parysh);
9323             *parysh = neighsh;
9324             // Go to the next face at the edge.
9325             spivotself(neighsh);
9326             // Stop if all faces at the edge have been visited.
9327             if (neighsh.sh == splitsh->sh) break;
9328             if (neighsh.sh == nullptr) break;
9329           } // while (1)
9330         } // if (not a dangling segment)
9331       }
9332     } // if (splitbdflag)
9333   } else if (loc == INSTAR) {
9334     // We assume that all tets in the star are given in 'caveoldtetlist',
9335     //   and they are all infected.
9336     assert(caveoldtetlist->objects > 0);
9337     // Collect the boundary faces of the star.
9338     for (i = 0; i < caveoldtetlist->objects; i++) {
9339       cavetet = (triface *) fastlookup(caveoldtetlist, i);
9340       // Check its 4 neighbor tets.
9341       for (j = 0; j < 4; j++) {
9342         decode(cavetet->tet[j], neightet);
9343         if (!infected(neightet)) {
9344           // It's a boundary face.
9345           neightet.ver = epivot[neightet.ver];
9346           cavebdrylist->newindex((void **) &parytet);
9347           *parytet = neightet;
9348         }
9349       }
9350     }
9351   } else if (loc == ONVERTEX) {
9352     // The point already exist. Do nothing and return.
9353     return 0;
9354   } else if (loc == ENCSUBFACE) {
9355     // Treat it as outside.
9356     ivf->iloc = (int) OUTSIDE;
9357     return 0;
9358   }
9359 
9360 
9361   if (ivf->assignmeshsize) {
9362     // Assign mesh size for the new point.
9363     if (bgm != nullptr) {
9364       // Interpolate the mesh size from the background mesh.
9365       bgm->decode(point2bgmtet(org(*searchtet)), neightet);
9366       int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
9367       if (bgmloc != (int) OUTSIDE) {
9368         insertpt[pointmtrindex] =
9369           bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
9370         setpoint2bgmtet(insertpt, bgm->encode(neightet));
9371       }
9372     } else {
9373       insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
9374     }
9375   } // if (assignmeshsize)
9376 
9377   if (ivf->bowywat) {
9378     // Update the cavity C(p) using the Bowyer-Watson algorithm.
9379     swaplist = cavetetlist;
9380     cavetetlist = cavebdrylist;
9381     cavebdrylist = swaplist;
9382     for (i = 0; i < cavetetlist->objects; i++) {
9383       // 'cavetet' is an adjacent tet at outside of the cavity.
9384       cavetet = (triface *) fastlookup(cavetetlist, i);
9385       // The tet may be tested and included in the (enlarged) cavity.
9386       if (!infected(*cavetet)) {
9387         // Check for two possible cases for this tet:
9388         //   (1) It is a cavity tet, or
9389         //   (2) it is a cavity boundary face.
9390         enqflag = false;
9391         if (!marktested(*cavetet)) {
9392           // Do Delaunay (in-sphere) test.
9393           pts = (point *) cavetet->tet;
9394           if (pts[7] != dummypoint) {
9395             // A volume tet. Operate on it.
9396             if (b->weighted) {
9397               sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9398                                 pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9399                                 insertpt[3]);
9400             } else {
9401               sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
9402             }
9403             enqflag = (sign < 0.0);
9404           } else {
9405             if (!nonconvex) {
9406               // Test if this hull face is visible by the new point.
9407               ori = orient3d(pts[4], pts[5], pts[6], insertpt);
9408               if (ori < 0) {
9409                 // A visible hull face.
9410                 //if (!nonconvex) {
9411                 // Include it in the cavity. The convex hull will be enlarged.
9412                 enqflag = true; // (ori < 0.0);
9413                         //}
9414               } else if (ori == 0.0) {
9415                 // A coplanar hull face. We need to test if this hull face is
9416                 //   Delaunay or not. We test if the adjacent tet (not faked)
9417                 //   of this hull face is Delaunay or not.
9418                 decode(cavetet->tet[3], neineitet);
9419                 if (!infected(neineitet)) {
9420                   if (!marktested(neineitet)) {
9421                     // Do Delaunay test on this tet.
9422                     pts = (point *) neineitet.tet;
9423                     assert(pts[7] != dummypoint);
9424                     if (b->weighted) {
9425                       sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9426                                         pts[4][3], pts[5][3], pts[6][3],
9427                                         pts[7][3], insertpt[3]);
9428                     } else {
9429                       sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9430                     }
9431                     enqflag = (sign < 0.0);
9432                   }
9433                 } else {
9434                   // The adjacent tet is non-Delaunay. The hull face is non-
9435                   //   Delaunay as well. Include it in the cavity.
9436                   enqflag = true;
9437                 } // if (!infected(neineitet))
9438               } // if (ori == 0.0)
9439             } else {
9440               // A hull face (must be a subface).
9441               // We FIRST include it in the initial cavity if the adjacent tet
9442               //   (not faked) of this hull face is not Delaunay wrt p.
9443               //   Whether it belongs to the final cavity will be determined
9444               //   during the validation process. 'validflag'.
9445               decode(cavetet->tet[3], neineitet);
9446               if (!infected(neineitet)) {
9447                 if (!marktested(neineitet)) {
9448                   // Do Delaunay test on this tet.
9449                   pts = (point *) neineitet.tet;
9450                   assert(pts[7] != dummypoint);
9451                   if (b->weighted) {
9452                     sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9453                                       pts[4][3], pts[5][3], pts[6][3],
9454                                       pts[7][3], insertpt[3]);
9455                   } else {
9456                     sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9457                   }
9458                   enqflag = (sign < 0.0);
9459                 }
9460               } else {
9461                 // The adjacent tet is non-Delaunay. The hull face is non-
9462                 //   Delaunay as well. Include it in the cavity.
9463                 enqflag = true;
9464               } // if (infected(neineitet))
9465             } // if (nonconvex)
9466           } // if (pts[7] != dummypoint)
9467           marktest(*cavetet); // Only test it once.
9468         } // if (!marktested(*cavetet))
9469 
9470         if (enqflag) {
9471           // Found a tet in the cavity. Put other three faces in check list.
9472           k = (cavetet->ver & 3); // The current face number
9473           for (j = 1; j < 4; j++) {
9474             decode(cavetet->tet[(j + k) % 4], neightet);
9475             cavetetlist->newindex((void **) &parytet);
9476             *parytet = neightet;
9477           }
9478           infect(*cavetet);
9479           caveoldtetlist->newindex((void **) &parytet);
9480           *parytet = *cavetet;
9481         } else {
9482           // Found a boundary face of the cavity.
9483           cavetet->ver = epivot[cavetet->ver];
9484           cavebdrylist->newindex((void **) &parytet);
9485           *parytet = *cavetet;
9486         }
9487       } // if (!infected(*cavetet))
9488     } // i
9489 
9490     cavetetlist->restart(); // Clear the working list.
9491   } // if (ivf->bowywat)
9492 
9493   if (checksubsegflag) {
9494     // Collect all segments of C(p).
9495     shellface *ssptr;
9496     for (i = 0; i < caveoldtetlist->objects; i++) {
9497       cavetet = (triface *) fastlookup(caveoldtetlist, i);
9498       if ((ssptr = (shellface*) cavetet->tet[8]) != nullptr) {
9499         for (j = 0; j < 6; j++) {
9500           if (ssptr[j]) {
9501             sdecode(ssptr[j], checkseg);
9502             if (!sinfected(checkseg)) {
9503               sinfect(checkseg);
9504               cavetetseglist->newindex((void **) &paryseg);
9505               *paryseg = checkseg;
9506             }
9507           }
9508         } // j
9509       }
9510     } // i
9511     // Uninfect collected segments.
9512     for (i = 0; i < cavetetseglist->objects; i++) {
9513       paryseg = (face *) fastlookup(cavetetseglist, i);
9514       suninfect(*paryseg);
9515     }
9516 
9517     if (ivf->rejflag & 1) {
9518       // Reject this point if it encroaches upon any segment.
9519       face *paryseg1;
9520       for (i = 0; i < cavetetseglist->objects; i++) {
9521         paryseg1 = (face *) fastlookup(cavetetseglist, i);
9522         if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4],
9523                               insertpt)) {
9524           encseglist->newindex((void **) &paryseg);
9525           *paryseg = *paryseg1;
9526         }
9527       } // i
9528       if (encseglist->objects > 0) {
9529         insertpoint_abort(splitseg, ivf);
9530         ivf->iloc = (int) ENCSEGMENT;
9531         return 0;
9532       }
9533     }
9534   } // if (checksubsegflag)
9535 
9536   if (checksubfaceflag) {
9537     // Collect all subfaces of C(p).
9538     shellface *sptr;
9539     for (i = 0; i < caveoldtetlist->objects; i++) {
9540       cavetet = (triface *) fastlookup(caveoldtetlist, i);
9541       if ((sptr = (shellface*) cavetet->tet[9]) != nullptr) {
9542         for (j = 0; j < 4; j++) {
9543           if (sptr[j]) {
9544             sdecode(sptr[j], checksh);
9545             if (!sinfected(checksh)) {
9546               sinfect(checksh);
9547               cavetetshlist->newindex((void **) &parysh);
9548               *parysh = checksh;
9549             }
9550           }
9551         } // j
9552       }
9553     } // i
9554     // Uninfect collected subfaces.
9555     for (i = 0; i < cavetetshlist->objects; i++) {
9556       parysh = (face *) fastlookup(cavetetshlist, i);
9557       suninfect(*parysh);
9558     }
9559 
9560     if (ivf->rejflag & 2) {
9561       REAL rd, cent[3];
9562       badface *bface;
9563       // Reject this point if it encroaches upon any subface.
9564       for (i = 0; i < cavetetshlist->objects; i++) {
9565         parysh = (face *) fastlookup(cavetetshlist, i);
9566         if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4],
9567                               (point) parysh->sh[5], insertpt, cent, &rd)) {
9568           encshlist->newindex((void **) &bface);
9569           bface->ss = *parysh;
9570           bface->forg = (point) parysh->sh[3]; // Not a dad one.
9571           for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
9572           bface->key = rd;
9573         }
9574       }
9575       if (encshlist->objects > 0) {
9576         insertpoint_abort(splitseg, ivf);
9577         ivf->iloc = (int) ENCSUBFACE;
9578         return 0;
9579       }
9580     }
9581   } // if (checksubfaceflag)
9582 
9583   if (ivf->splitbdflag) {
9584     // The new point locates in surface mesh. Update the sC(p).
9585     // We have already 'smarktested' the subfaces which directly intersect
9586     //   with p in 'caveshlist'. From them, we 'smarktest' their neighboring
9587     //   subfaces which are included in C(p). Do not across a segment.
9588     for (i = 0; i < caveshlist->objects; i++) {
9589       parysh = (face *) fastlookup(caveshlist, i);
9590       assert(smarktested(*parysh));
9591       checksh = *parysh;
9592       for (j = 0; j < 3; j++) {
9593         if (!isshsubseg(checksh)) {
9594           spivot(checksh, neighsh);
9595           assert(neighsh.sh != nullptr);
9596           if (!smarktested(neighsh)) {
9597             stpivot(neighsh, neightet);
9598             if (infected(neightet)) {
9599               fsymself(neightet);
9600               if (infected(neightet)) {
9601                 // This subface is inside C(p).
9602                 // Check if its diametrical circumsphere encloses 'p'.
9603                 //   The purpose of this check is to avoid forming invalid
9604                 //   subcavity in surface mesh.
9605                 sign = incircle3d(sorg(neighsh), sdest(neighsh),
9606                                   sapex(neighsh), insertpt);
9607                 if (sign < 0) {
9608                   smarktest(neighsh);
9609                   caveshlist->newindex((void **) &parysh);
9610                   *parysh = neighsh;
9611                 }
9612               }
9613             }
9614           }
9615         }
9616         senextself(checksh);
9617       } // j
9618     } // i
9619   } // if (ivf->splitbdflag)
9620 
9621   if (ivf->validflag) {
9622     // Validate C(p) and update it if it is not star-shaped.
9623     int cutcount = 0;
9624 
9625     if (ivf->respectbdflag) {
9626       // The initial cavity may include subfaces which are not on the facets
9627       //   being splitting. Find them and make them as boundary of C(p).
9628       // Comment: We have already 'smarktested' the subfaces in sC(p). They
9629       //   are completely inside C(p).
9630       for (i = 0; i < cavetetshlist->objects; i++) {
9631         parysh = (face *) fastlookup(cavetetshlist, i);
9632         stpivot(*parysh, neightet);
9633         if (infected(neightet)) {
9634           fsymself(neightet);
9635           if (infected(neightet)) {
9636             // Found a subface inside C(p).
9637             if (!smarktested(*parysh)) {
9638               // It is possible that this face is a boundary subface.
9639               // Check if it is a hull face.
9640               //assert(apex(neightet) != dummypoint);
9641               if (oppo(neightet) != dummypoint) {
9642                 fsymself(neightet);
9643               }
9644               if (oppo(neightet) != dummypoint) {
9645                 ori = orient3d(org(neightet), dest(neightet), apex(neightet),
9646                                insertpt);
9647                 if (ori < 0) {
9648                   // A visible face, get its neighbor face.
9649                   fsymself(neightet);
9650                   ori = -ori; // It must be invisible by p.
9651                 }
9652               } else {
9653                 // A hull tet. It needs to be cut.
9654                 ori = 1;
9655               }
9656               // Cut this tet if it is either invisible by or coplanar with p.
9657               if (ori >= 0) {
9658                 uninfect(neightet);
9659                 unmarktest(neightet);
9660                 cutcount++;
9661                 neightet.ver = epivot[neightet.ver];
9662                 cavebdrylist->newindex((void **) &parytet);
9663                 *parytet = neightet;
9664                 // Add three new faces to find new boundaries.
9665                 for (j = 0; j < 3; j++) {
9666                   esym(neightet, neineitet);
9667                   neineitet.ver = epivot[neineitet.ver];
9668                   cavebdrylist->newindex((void **) &parytet);
9669                   *parytet = neineitet;
9670                   enextself(neightet);
9671                 }
9672               } // if (ori >= 0)
9673             }
9674           }
9675         }
9676       } // i
9677 
9678       // The initial cavity may include segments in its interior. We need to
9679       //   Update the cavity so that these segments are on the boundary of
9680       //   the cavity.
9681       for (i = 0; i < cavetetseglist->objects; i++) {
9682         paryseg = (face *) fastlookup(cavetetseglist, i);
9683         // Check this segment if it is not a splitting segment.
9684         if (!smarktested(*paryseg)) {
9685           sstpivot1(*paryseg, neightet);
9686           spintet = neightet;
9687           while (1) {
9688             if (!infected(spintet)) break;
9689             fnextself(spintet);
9690             if (spintet.tet == neightet.tet) break;
9691           }
9692           if (infected(spintet)) {
9693             // Find an adjacent tet at this segment such that both faces
9694             //   at this segment are not visible by p.
9695             pa = org(neightet);
9696             pb = dest(neightet);
9697             spintet = neightet;
9698             j = 0;
9699             while (1) {
9700               // Check if this face is visible by p.
9701               pc = apex(spintet);
9702               if (pc != dummypoint) {
9703                 ori = orient3d(pa, pb, pc, insertpt);
9704                 if (ori >= 0) {
9705                   // Not visible. Check another face in this tet.
9706                   esym(spintet, neineitet);
9707                   pc = apex(neineitet);
9708                   if (pc != dummypoint) {
9709                     ori = orient3d(pb, pa, pc, insertpt);
9710                     if (ori >= 0) {
9711                       // Not visible. Found this face.
9712                       j = 1; // Flag that it is found.
9713                       break;
9714                     }
9715                   }
9716                 }
9717               }
9718               fnextself(spintet);
9719               if (spintet.tet == neightet.tet) break;
9720             }
9721             if (j == 0) {
9722               // Not found such a face.
9723               assert(0); // debug this case.
9724             }
9725             neightet = spintet;
9726             if (b->verbose > 3) {
9727                printf("        Cut tet (%d, %d, %d, %d)\n",
9728                       pointmark(org(neightet)), pointmark(dest(neightet)),
9729                       pointmark(apex(neightet)), pointmark(oppo(neightet)));
9730             }
9731             uninfect(neightet);
9732             unmarktest(neightet);
9733             cutcount++;
9734             neightet.ver = epivot[neightet.ver];
9735             cavebdrylist->newindex((void **) &parytet);
9736             *parytet = neightet;
9737             // Add three new faces to find new boundaries.
9738             for (j = 0; j < 3; j++) {
9739               esym(neightet, neineitet);
9740               neineitet.ver = epivot[neineitet.ver];
9741               cavebdrylist->newindex((void **) &parytet);
9742               *parytet = neineitet;
9743               enextself(neightet);
9744             }
9745           }
9746         }
9747       } // i
9748     } // if (ivf->respectbdflag)
9749 
9750     // Update the cavity by removing invisible faces until it is star-shaped.
9751     for (i = 0; i < cavebdrylist->objects; i++) {
9752       cavetet = (triface *) fastlookup(cavebdrylist, i);
9753       // 'cavetet' is an exterior tet adjacent to the cavity.
9754       // Check if its neighbor is inside C(p).
9755       fsym(*cavetet, neightet);
9756       if (infected(neightet)) {
9757         if (apex(*cavetet) != dummypoint) {
9758           // It is a cavity boundary face. Check its visibility.
9759           if (oppo(neightet) != dummypoint) {
9760             ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
9761                            insertpt);
9762             enqflag = (ori > 0);
9763             // Comment: if ori == 0 (coplanar case), we also cut the tet.
9764           } else {
9765             // It is a hull face. And its adjacent tet (at inside of the
9766             //   domain) has been cut from the cavity. Cut it as well.
9767             //assert(nonconvex);
9768             enqflag = false;
9769           }
9770         } else {
9771           enqflag = true; // A hull edge.
9772         }
9773         if (enqflag) {
9774           // This face is valid, save it.
9775           cavetetlist->newindex((void **) &parytet);
9776           *parytet = *cavetet;
9777         } else {
9778           uninfect(neightet);
9779           unmarktest(neightet);
9780           cutcount++;
9781           // Add three new faces to find new boundaries.
9782           for (j = 0; j < 3; j++) {
9783             esym(neightet, neineitet);
9784             neineitet.ver = epivot[neineitet.ver];
9785             cavebdrylist->newindex((void **) &parytet);
9786             *parytet = neineitet;
9787             enextself(neightet);
9788           }
9789           // 'cavetet' is not on the cavity boundary anymore.
9790           unmarktest(*cavetet);
9791         }
9792       } else {
9793         // 'cavetet' is not on the cavity boundary anymore.
9794         unmarktest(*cavetet);
9795       }
9796     } // i
9797 
9798     if (cutcount > 0) {
9799       // The cavity has been updated.
9800       // Update the cavity boundary faces.
9801       cavebdrylist->restart();
9802       for (i = 0; i < cavetetlist->objects; i++) {
9803         cavetet = (triface *) fastlookup(cavetetlist, i);
9804         // 'cavetet' was an exterior tet adjacent to the cavity.
9805         fsym(*cavetet, neightet);
9806         if (infected(neightet)) {
9807           // It is a cavity boundary face.
9808           cavebdrylist->newindex((void **) &parytet);
9809           *parytet = *cavetet;
9810         } else {
9811           // Not a cavity boundary face.
9812           unmarktest(*cavetet);
9813         }
9814       }
9815 
9816       // Update the list of old tets.
9817       cavetetlist->restart();
9818       for (i = 0; i < caveoldtetlist->objects; i++) {
9819         cavetet = (triface *) fastlookup(caveoldtetlist, i);
9820         if (infected(*cavetet)) {
9821           cavetetlist->newindex((void **) &parytet);
9822           *parytet = *cavetet;
9823         }
9824       }
9825       // Swap 'cavetetlist' and 'caveoldtetlist'.
9826       swaplist = caveoldtetlist;
9827       caveoldtetlist = cavetetlist;
9828       cavetetlist = swaplist;
9829 
9830       // The cavity should contain at least one tet.
9831       if (caveoldtetlist->objects == 0l) {
9832         insertpoint_abort(splitseg, ivf);
9833         ivf->iloc = (int) BADELEMENT;
9834         return 0;
9835       }
9836 
9837       if (ivf->splitbdflag) {
9838         int cutshcount = 0;
9839         // Update the sub-cavity sC(p).
9840         for (i = 0; i < caveshlist->objects; i++) {
9841           parysh = (face *) fastlookup(caveshlist, i);
9842           if (smarktested(*parysh)) {
9843             enqflag = false;
9844             stpivot(*parysh, neightet);
9845             if (infected(neightet)) {
9846               fsymself(neightet);
9847               if (infected(neightet)) {
9848                 enqflag = true;
9849               }
9850             }
9851             if (!enqflag) {
9852               sunmarktest(*parysh);
9853               // Use the last entry of this array to fill this entry.
9854               j = caveshlist->objects - 1;
9855               checksh = * (face *) fastlookup(caveshlist, j);
9856               *parysh = checksh;
9857               cutshcount++;
9858               caveshlist->objects--; // The list is shrinked.
9859               i--;
9860             }
9861           }
9862         }
9863 
9864         if (cutshcount > 0) {
9865           i = 0; // Count the number of invalid subfaces/segments.
9866           // Valid the updated sub-cavity sC(p).
9867           if (loc == ONFACE) {
9868             if ((splitsh != nullptr) && (splitsh->sh != nullptr)) {
9869               // The to-be split subface should be in sC(p).
9870               if (!smarktested(*splitsh)) i++;
9871             }
9872           } else if (loc == ONEDGE) {
9873             if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
9874               // The to-be split segment should be in sC(p).
9875               if (!smarktested(*splitseg)) i++;
9876             }
9877             if ((splitsh != nullptr) && (splitsh->sh != nullptr)) {
9878               // All subfaces at this edge should be in sC(p).
9879               pa = sorg(*splitsh);
9880               neighsh = *splitsh;
9881               while (1) {
9882                 // Adjust the origin of its edge to be 'pa'.
9883                 if (sorg(neighsh) != pa) {
9884                   sesymself(neighsh);
9885                 }
9886                 // Add this face into list (in B-W cavity).
9887                 if (!smarktested(neighsh)) i++;
9888                 // Go to the next face at the edge.
9889                 spivotself(neighsh);
9890                 // Stop if all faces at the edge have been visited.
9891                 if (neighsh.sh == splitsh->sh) break;
9892                 if (neighsh.sh == nullptr) break;
9893               } // while (1)
9894             }
9895           }
9896 
9897           if (i > 0) {
9898             // The updated sC(p) is invalid. Do not insert this vertex.
9899             insertpoint_abort(splitseg, ivf);
9900             ivf->iloc = (int) BADELEMENT;
9901             return 0;
9902           }
9903         } // if (cutshcount > 0)
9904       } // if (ivf->splitbdflag)
9905     } // if (cutcount > 0)
9906 
9907   } // if (ivf->validflag)
9908 
9909   if (ivf->refineflag) {
9910     // The new point is inserted by Delaunay refinement, i.e., it is the
9911     //   circumcenter of a tetrahedron, or a subface, or a segment.
9912     //   Do not insert this point if the tetrahedron, or subface, or segment
9913     //   is not inside the final cavity.
9914     if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
9915         ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
9916       insertpoint_abort(splitseg, ivf);
9917       ivf->iloc = (int) BADELEMENT;
9918       return 0;
9919     }
9920   } // if (ivf->refineflag)
9921 
9922   if (b->plc && (loc != INSTAR)) {
9923     // Reject the new point if it lies too close to an existing point (b->plc),
9924     // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
9925     // Collect the list of vertices of the initial cavity.
9926     if (loc == OUTSIDE) {
9927       pts = (point *) &(searchtet->tet[4]);
9928       for (i = 0; i < 3; i++) {
9929         cavetetvertlist->newindex((void **) &parypt);
9930         *parypt = pts[i];
9931       }
9932     } else if (loc == INTETRAHEDRON) {
9933       pts = (point *) &(searchtet->tet[4]);
9934       for (i = 0; i < 4; i++) {
9935         cavetetvertlist->newindex((void **) &parypt);
9936         *parypt = pts[i];
9937       }
9938     } else if (loc == ONFACE) {
9939       pts = (point *) &(searchtet->tet[4]);
9940       for (i = 0; i < 3; i++) {
9941         cavetetvertlist->newindex((void **) &parypt);
9942         *parypt = pts[i];
9943       }
9944       if (pts[3] != dummypoint) {
9945         cavetetvertlist->newindex((void **) &parypt);
9946         *parypt = pts[3];
9947       }
9948       fsym(*searchtet, spintet);
9949       if (oppo(spintet) != dummypoint) {
9950         cavetetvertlist->newindex((void **) &parypt);
9951         *parypt = oppo(spintet);
9952       }
9953     } else if (loc == ONEDGE) {
9954       spintet = *searchtet;
9955       cavetetvertlist->newindex((void **) &parypt);
9956       *parypt = org(spintet);
9957       cavetetvertlist->newindex((void **) &parypt);
9958       *parypt = dest(spintet);
9959       while (1) {
9960         if (apex(spintet) != dummypoint) {
9961           cavetetvertlist->newindex((void **) &parypt);
9962           *parypt = apex(spintet);
9963         }
9964         fnextself(spintet);
9965         if (spintet.tet == searchtet->tet) break;
9966       }
9967     }
9968 
9969     int rejptflag = (ivf->rejflag & 4);
9970     REAL rd;
9971     pts = nullptr;
9972 
9973     for (i = 0; i < cavetetvertlist->objects; i++) {
9974       parypt = (point *) fastlookup(cavetetvertlist, i);
9975       rd = distance(*parypt, insertpt);
9976       // Is the point very close to an existing point?
9977       if (rd < b->minedgelength) {
9978         pts = parypt;
9979         loc = NEARVERTEX;
9980         break;
9981       }
9982       if (rejptflag) {
9983         // Is the point encroaches upon an existing point?
9984         if (rd < (*parypt)[pointmtrindex]) {
9985           pts = parypt;
9986           loc = ENCVERTEX;
9987           break;
9988         }
9989       }
9990     }
9991     cavetetvertlist->restart(); // Clear the work list.
9992 
9993     if (pts != nullptr) {
9994       // The point is either too close to an existing vertex (NEARVERTEX)
9995       //   or encroaches upon (isndie the protecting ball) of that vertex.
9996       if (loc == NEARVERTEX) {
9997         if (b->nomergevertex) { // -M0/1 option.
9998           // In this case, we still insert this vertex. Although it is very
9999           //   close to an existing vertex. Give a warning, anyway.
10000           if (!b->quiet) {
10001             printf("Warning:  Two points, %d and %d, are very close.\n",
10002                    pointmark(insertpt), pointmark(*pts));
10003             printf("  Creating a very short edge (len = %g) (< %g).\n",
10004                    rd, b->minedgelength);
10005             printf("  You may try a smaller tolerance (-T) (current is %g)\n",
10006                    b->epsilon);
10007             printf("  to avoid this warning.\n");
10008           }
10009         } else {
10010           insertpt[3] = rd; // Only for reporting.
10011           setpoint2ppt(insertpt, *pts);
10012           insertpoint_abort(splitseg, ivf);
10013           ivf->iloc = (int) loc;
10014           return 0;
10015         }
10016       } else { // loc == ENCVERTEX
10017         // The point lies inside the protection ball.
10018         setpoint2ppt(insertpt, *pts);
10019         insertpoint_abort(splitseg, ivf);
10020         ivf->iloc = (int) loc;
10021         return 0;
10022       }
10023     }
10024   } // if (b->plc && (loc != INSTAR))
10025 
10026   if (b->weighted || ivf->cdtflag
10027       ) {
10028     // There may be other vertices inside C(p). We need to find them.
10029     // Collect all vertices of C(p).
10030     for (i = 0; i < caveoldtetlist->objects; i++) {
10031       cavetet = (triface *) fastlookup(caveoldtetlist, i);
10032       //assert(infected(*cavetet));
10033       pts = (point *) &(cavetet->tet[4]);
10034       for (j = 0; j < 4; j++) {
10035         if (pts[j] != dummypoint) {
10036           if (!pinfected(pts[j])) {
10037             pinfect(pts[j]);
10038             cavetetvertlist->newindex((void **) &parypt);
10039             *parypt = pts[j];
10040           }
10041         }
10042       } // j
10043     } // i
10044     // Uninfect all collected (cavity) vertices.
10045     for (i = 0; i < cavetetvertlist->objects; i++) {
10046       parypt = (point *) fastlookup(cavetetvertlist, i);
10047       puninfect(*parypt);
10048     }
10049   }
10050 
10051 
10052   if (ivf->cdtflag) {
10053     // Unmark tets.
10054     for (i = 0; i < caveoldtetlist->objects; i++) {
10055       cavetet = (triface *) fastlookup(caveoldtetlist, i);
10056       unmarktest(*cavetet);
10057     }
10058     for (i = 0; i < cavebdrylist->objects; i++) {
10059       cavetet = (triface *) fastlookup(cavebdrylist, i);
10060       unmarktest(*cavetet);
10061     }
10062     // Clean up arrays which are not needed.
10063     cavetetlist->restart();
10064     if (checksubsegflag) {
10065       cavetetseglist->restart();
10066     }
10067     if (checksubfaceflag) {
10068       cavetetshlist->restart();
10069     }
10070     return 1;
10071   }
10072 
10073   // Before re-mesh C(p). Process the segments and subfaces which are on the
10074   //   boundary of C(p). Make sure that each such segment or subface is
10075   //   connecting to a tet outside C(p). So we can re-connect them to the
10076   //   new tets inside the C(p) later.
10077 
10078   if (checksubsegflag) {
10079     for (i = 0; i < cavetetseglist->objects; i++) {
10080       paryseg = (face *) fastlookup(cavetetseglist, i);
10081       // Operate on it if it is not the splitting segment, i.e., in sC(p).
10082       if (!smarktested(*paryseg)) {
10083         // Check if the segment is inside the cavity.
10084         //   'j' counts the num of adjacent tets of this seg.
10085         //   'k' counts the num of adjacent tets which are 'sinfected'.
10086         j = k = 0;
10087         sstpivot1(*paryseg, neightet);
10088         spintet = neightet;
10089         while (1) {
10090           j++;
10091           if (!infected(spintet)) {
10092             neineitet = spintet; // An outer tet. Remember it.
10093           } else {
10094             k++; // An in tet.
10095           }
10096           fnextself(spintet);
10097           if (spintet.tet == neightet.tet) break;
10098         }
10099         // assert(j > 0);
10100         if (k == 0) {
10101           // The segment is not connect to C(p) anymore. Remove it by
10102           //   Replacing it by the last entry of this list.
10103           s = cavetetseglist->objects - 1;
10104           checkseg = * (face *) fastlookup(cavetetseglist, s);
10105           *paryseg = checkseg;
10106           cavetetseglist->objects--;
10107           i--;
10108         } else if (k < j) {
10109           // The segment is on the boundary of C(p).
10110           sstbond1(*paryseg, neineitet);
10111         } else { // k == j
10112           // The segment is inside C(p).
10113           if (!ivf->splitbdflag) {
10114             checkseg = *paryseg;
10115             sinfect(checkseg); // Flag it as an interior segment.
10116             caveencseglist->newindex((void **) &paryseg);
10117             *paryseg = checkseg;
10118           } else {
10119             assert(0); // Not possible.
10120           }
10121         }
10122       } else {
10123         // assert(smarktested(*paryseg));
10124         // Flag it as an interior segment. Do not queue it, since it will
10125         //   be deleted after the segment splitting.
10126         sinfect(*paryseg);
10127       }
10128     } // i
10129   } // if (checksubsegflag)
10130 
10131   if (checksubfaceflag) {
10132     for (i = 0; i < cavetetshlist->objects; i++) {
10133       parysh = (face *) fastlookup(cavetetshlist, i);
10134       // Operate on it if it is not inside the sub-cavity sC(p).
10135       if (!smarktested(*parysh)) {
10136         // Check if this subface is inside the cavity.
10137         k = 0;
10138         for (j = 0; j < 2; j++) {
10139           stpivot(*parysh, neightet);
10140           if (!infected(neightet)) {
10141             checksh = *parysh; // Remeber this side.
10142           } else {
10143             k++;
10144           }
10145           sesymself(*parysh);
10146         }
10147         if (k == 0) {
10148           // The subface is not connected to C(p). Remove it.
10149           s = cavetetshlist->objects - 1;
10150           checksh = * (face *) fastlookup(cavetetshlist, s);
10151           *parysh = checksh;
10152           cavetetshlist->objects--;
10153           i--;
10154         } else if (k == 1) {
10155           // This side is the outer boundary of C(p).
10156           *parysh = checksh;
10157         } else { // k == 2
10158           if (!ivf->splitbdflag) {
10159             checksh = *parysh;
10160             sinfect(checksh); // Flag it.
10161             caveencshlist->newindex((void **) &parysh);
10162             *parysh = checksh;
10163           } else {
10164             assert(0); // Not possible.
10165           }
10166         }
10167       } else {
10168         // assert(smarktested(*parysh));
10169         // Flag it as an interior subface. Do not queue it. It will be
10170         //   deleted after the facet point insertion.
10171         sinfect(*parysh);
10172       }
10173     } // i
10174   } // if (checksubfaceflag)
10175 
10176   // Create new tetrahedra to fill the cavity.
10177 
10178   for (i = 0; i < cavebdrylist->objects; i++) {
10179     cavetet = (triface *) fastlookup(cavebdrylist, i);
10180     neightet = *cavetet;
10181     unmarktest(neightet); // Unmark it.
10182     // Get the oldtet (inside the cavity).
10183     fsym(neightet, oldtet);
10184     if (apex(neightet) != dummypoint) {
10185       // Create a new tet in the cavity.
10186       maketetrahedron(&newtet);
10187       setorg(newtet, dest(neightet));
10188       setdest(newtet, org(neightet));
10189       setapex(newtet, apex(neightet));
10190       setoppo(newtet, insertpt);
10191     } else {
10192       // Create a new hull tet.
10193       hullsize++;
10194       maketetrahedron(&newtet);
10195       setorg(newtet, org(neightet));
10196       setdest(newtet, dest(neightet));
10197       setapex(newtet, insertpt);
10198       setoppo(newtet, dummypoint); // It must opposite to face 3.
10199       // Adjust back to the cavity bounday face.
10200       esymself(newtet);
10201     }
10202     // The new tet inherits attribtes from the old tet.
10203     for (j = 0; j < numelemattrib; j++) {
10204       attrib = elemattribute(oldtet.tet, j);
10205       setelemattribute(newtet.tet, j, attrib);
10206     }
10207     if (b->varvolume) {
10208       volume = volumebound(oldtet.tet);
10209       setvolumebound(newtet.tet, volume);
10210     }
10211     // Connect newtet <==> neightet, this also disconnect the old bond.
10212     bond(newtet, neightet);
10213     // oldtet still connects to neightet.
10214     *cavetet = oldtet; // *cavetet = newtet;
10215   } // i
10216 
10217   // Set a handle for speeding point location.
10218   recenttet = newtet;
10219   //setpoint2tet(insertpt, encode(newtet));
10220   setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
10221 
10222   // Re-use this list to save new interior cavity faces.
10223   cavetetlist->restart();
10224 
10225   // Connect adjacent new tetrahedra together.
10226   for (i = 0; i < cavebdrylist->objects; i++) {
10227     cavetet = (triface *) fastlookup(cavebdrylist, i);
10228     // cavtet is an oldtet, get the newtet at this face.
10229     oldtet = *cavetet;
10230     fsym(oldtet, neightet);
10231     fsym(neightet, newtet);
10232     // Comment: oldtet and newtet must be at the same directed edge.
10233     // Connect the three other faces of this newtet.
10234     for (j = 0; j < 3; j++) {
10235       esym(newtet, neightet); // Go to the face.
10236       if (neightet.tet[neightet.ver & 3] == nullptr) {
10237         // Find the adjacent face of this newtet.
10238         spintet = oldtet;
10239         while (1) {
10240           fnextself(spintet);
10241           if (!infected(spintet)) break;
10242         }
10243         fsym(spintet, newneitet);
10244         esymself(newneitet);
10245         assert(newneitet.tet[newneitet.ver & 3] == nullptr);
10246         bond(neightet, newneitet);
10247         if (ivf->lawson > 1) {
10248           cavetetlist->newindex((void **) &parytet);
10249           *parytet = neightet;
10250         }
10251       }
10252       //setpoint2tet(org(newtet), encode(newtet));
10253       setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
10254       enextself(newtet);
10255       enextself(oldtet);
10256     }
10257     *cavetet = newtet; // Save the new tet.
10258   } // i
10259 
10260   if (checksubfaceflag) {
10261     // Connect subfaces on the boundary of the cavity to the new tets.
10262     for (i = 0; i < cavetetshlist->objects; i++) {
10263       parysh = (face *) fastlookup(cavetetshlist, i);
10264       // Connect it if it is not a missing subface.
10265       if (!sinfected(*parysh)) {
10266         stpivot(*parysh, neightet);
10267         fsym(neightet, spintet);
10268         sesymself(*parysh);
10269         tsbond(spintet, *parysh);
10270       }
10271     }
10272   }
10273 
10274   if (checksubsegflag) {
10275     // Connect segments on the boundary of the cavity to the new tets.
10276     for (i = 0; i < cavetetseglist->objects; i++) {
10277       paryseg = (face *) fastlookup(cavetetseglist, i);
10278       // Connect it if it is not a missing segment.
10279       if (!sinfected(*paryseg)) {
10280         sstpivot1(*paryseg, neightet);
10281         spintet = neightet;
10282         while (1) {
10283           tssbond1(spintet, *paryseg);
10284           fnextself(spintet);
10285           if (spintet.tet == neightet.tet) break;
10286         }
10287       }
10288     }
10289   }
10290 
10291   if (((splitsh != nullptr) && (splitsh->sh != nullptr)) ||
10292       ((splitseg != nullptr) && (splitseg->sh != nullptr))) {
10293     // Split a subface or a segment.
10294     sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
10295   }
10296 
10297   if (checksubfaceflag) {
10298     if (ivf->splitbdflag) {
10299       // Recover new subfaces in C(p).
10300       for (i = 0; i < caveshbdlist->objects; i++) {
10301         // Get an old subface at edge [a, b].
10302         parysh = (face *) fastlookup(caveshbdlist, i);
10303         spivot(*parysh, checksh); // The new subface [a, b, p].
10304         // Do not recover a deleted new face (degenerated).
10305         if (checksh.sh[3] != nullptr) {
10306           // Note that the old subface still connects to adjacent old tets
10307           //   of C(p), which still connect to the tets outside C(p).
10308           stpivot(*parysh, neightet);
10309           assert(infected(neightet));
10310           // Find the adjacent tet containing the edge [a,b] outside C(p).
10311           spintet = neightet;
10312           while (1) {
10313             fnextself(spintet);
10314             if (!infected(spintet)) break;
10315             assert(spintet.tet != neightet.tet);
10316           }
10317           // The adjacent tet connects to a new tet in C(p).
10318           fsym(spintet, neightet);
10319           assert(!infected(neightet));
10320           // Find the tet containing the face [a, b, p].
10321           spintet = neightet;
10322           while (1) {
10323             fnextself(spintet);
10324             if (apex(spintet) == insertpt) break;
10325             assert(spintet.tet != neightet.tet);
10326           }
10327           // Adjust the edge direction in spintet and checksh.
10328           if (sorg(checksh) != org(spintet)) {
10329             sesymself(checksh);
10330             assert(sorg(checksh) == org(spintet));
10331           }
10332           assert(sdest(checksh) == dest(spintet));
10333           // Connect the subface to two adjacent tets.
10334           tsbond(spintet, checksh);
10335           fsymself(spintet);
10336           sesymself(checksh);
10337           tsbond(spintet, checksh);
10338         } // if (checksh.sh[3] != nullptr)
10339       }
10340       // There should be no missing interior subfaces in C(p).
10341       assert(caveencshlist->objects == 0l);
10342     } else {
10343       // The Boundary reocvery phase.
10344       // Put all new subfaces into stack for recovery.
10345       for (i = 0; i < caveshbdlist->objects; i++) {
10346         // Get an old subface at edge [a, b].
10347         parysh = (face *) fastlookup(caveshbdlist, i);
10348         spivot(*parysh, checksh); // The new subface [a, b, p].
10349         // Do not recover a deleted new face (degenerated).
10350         if (checksh.sh[3] != nullptr) {
10351           subfacstack->newindex((void **) &parysh);
10352           *parysh = checksh;
10353         }
10354       }
10355       // Put all interior subfaces into stack for recovery.
10356       for (i = 0; i < caveencshlist->objects; i++) {
10357         parysh = (face *) fastlookup(caveencshlist, i);
10358         assert(sinfected(*parysh));
10359         // Some subfaces inside C(p) might be split in sinsertvertex().
10360         //   Only queue those faces which are not split.
10361         if (!smarktested(*parysh)) {
10362           checksh = *parysh;
10363           suninfect(checksh);
10364           stdissolve(checksh); // Detach connections to old tets.
10365           subfacstack->newindex((void **) &parysh);
10366           *parysh = checksh;
10367         }
10368       }
10369     }
10370   } // if (checksubfaceflag)
10371 
10372   if (checksubsegflag) {
10373     if (ivf->splitbdflag) {
10374       if (splitseg != nullptr) {
10375         // Recover the two new subsegments in C(p).
10376         for (i = 0; i < cavesegshlist->objects; i++) {
10377           paryseg = (face *) fastlookup(cavesegshlist, i);
10378           // Insert this subsegment into C(p).
10379           checkseg = *paryseg;
10380           // Get the adjacent new subface.
10381           checkseg.shver = 0;
10382           spivot(checkseg, checksh);
10383           if (checksh.sh != nullptr) {
10384             // Get the adjacent new tetrahedron.
10385             stpivot(checksh, neightet);
10386           } else {
10387             // It's a dangling segment.
10388             point2tetorg(sorg(checkseg), neightet);
10389             finddirection(&neightet, sdest(checkseg));
10390             assert(dest(neightet) == sdest(checkseg));
10391           }
10392           assert(!infected(neightet));
10393           sstbond1(checkseg, neightet);
10394           spintet = neightet;
10395           while (1) {
10396             tssbond1(spintet, checkseg);
10397             fnextself(spintet);
10398             if (spintet.tet == neightet.tet) break;
10399           }
10400         }
10401       } // if (splitseg != nullptr)
10402       // There should be no interior segment in C(p).
10403       assert(caveencseglist->objects == 0l);
10404     } else {
10405       // The Boundary Recovery Phase.
10406       // Queue missing segments in C(p) for recovery.
10407       if (splitseg != nullptr) {
10408         // Queue two new subsegments in C(p) for recovery.
10409         for (i = 0; i < cavesegshlist->objects; i++) {
10410           paryseg = (face *) fastlookup(cavesegshlist, i);
10411           checkseg = *paryseg;
10412           //sstdissolve1(checkseg); // It has not been connected yet.
10413           s = randomnation(subsegstack->objects + 1);
10414           subsegstack->newindex((void **) &paryseg);
10415           *paryseg = * (face *) fastlookup(subsegstack, s);
10416           paryseg = (face *) fastlookup(subsegstack, s);
10417           *paryseg = checkseg;
10418         }
10419       } // if (splitseg != nullptr)
10420       for (i = 0; i < caveencseglist->objects; i++) {
10421         paryseg = (face *) fastlookup(caveencseglist, i);
10422         assert(sinfected(*paryseg));
10423         if (!smarktested(*paryseg)) { // It may be split.
10424           checkseg = *paryseg;
10425           suninfect(checkseg);
10426           sstdissolve1(checkseg); // Detach connections to old tets.
10427           s = randomnation(subsegstack->objects + 1);
10428           subsegstack->newindex((void **) &paryseg);
10429           *paryseg = * (face *) fastlookup(subsegstack, s);
10430           paryseg = (face *) fastlookup(subsegstack, s);
10431           *paryseg = checkseg;
10432         }
10433       }
10434     }
10435   } // if (checksubsegflag)
10436 
10437   if (b->weighted
10438       ) {
10439     // Some vertices may be completed inside the cavity. They must be
10440     //   detected and added to recovering list.
10441     // Since every "live" vertex must contain a pointer to a non-dead
10442     //   tetrahedron, we can check for each vertex this pointer.
10443     for (i = 0; i < cavetetvertlist->objects; i++) {
10444       pts = (point *) fastlookup(cavetetvertlist, i);
10445       decode(point2tet(*pts), *searchtet);
10446       assert(searchtet->tet != nullptr); // No tet has been deleted yet.
10447       if (infected(*searchtet)) {
10448         if (b->weighted) {
10449           if (b->verbose > 1) {
10450             printf("    Point #%d is non-regular after the insertion of #%d.\n",
10451                    pointmark(*pts), pointmark(insertpt));
10452           }
10453           setpointtype(*pts, NREGULARVERTEX);
10454           nonregularcount++;
10455         }
10456       }
10457     }
10458   }
10459 
10460   if (ivf->chkencflag & 1) {
10461     // Queue all segment outside C(p).
10462     for (i = 0; i < cavetetseglist->objects; i++) {
10463       paryseg = (face *) fastlookup(cavetetseglist, i);
10464       // Skip if it is the split segment.
10465       if (!sinfected(*paryseg)) {
10466         enqueuesubface(badsubsegs, paryseg);
10467       }
10468     }
10469     if (splitseg != nullptr) {
10470       // Queue the two new subsegments inside C(p).
10471       for (i = 0; i < cavesegshlist->objects; i++) {
10472         paryseg = (face *) fastlookup(cavesegshlist, i);
10473         enqueuesubface(badsubsegs, paryseg);
10474       }
10475     }
10476   } // if (chkencflag & 1)
10477 
10478   if (ivf->chkencflag & 2) {
10479     // Queue all subfaces outside C(p).
10480     for (i = 0; i < cavetetshlist->objects; i++) {
10481       parysh = (face *) fastlookup(cavetetshlist, i);
10482       // Skip if it is a split subface.
10483       if (!sinfected(*parysh)) {
10484         enqueuesubface(badsubfacs, parysh);
10485       }
10486     }
10487     // Queue all new subfaces inside C(p).
10488     for (i = 0; i < caveshbdlist->objects; i++) {
10489       // Get an old subface at edge [a, b].
10490       parysh = (face *) fastlookup(caveshbdlist, i);
10491       spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
10492       // Do not recover a deleted new face (degenerated).
10493       if (checksh.sh[3] != nullptr) {
10494         enqueuesubface(badsubfacs, &checksh);
10495       }
10496     }
10497   } // if (chkencflag & 2)
10498 
10499   if (ivf->chkencflag & 4) {
10500     // Queue all new tetrahedra in C(p).
10501     for (i = 0; i < cavebdrylist->objects; i++) {
10502       cavetet = (triface *) fastlookup(cavebdrylist, i);
10503       enqueuetetrahedron(cavetet);
10504     }
10505   }
10506 
10507   // C(p) is re-meshed successfully.
10508 
10509   // Delete the old tets in C(p).
10510   for (i = 0; i < caveoldtetlist->objects; i++) {
10511     searchtet = (triface *) fastlookup(caveoldtetlist, i);
10512     if (ishulltet(*searchtet)) {
10513       hullsize--;
10514     }
10515     tetrahedrondealloc(searchtet->tet);
10516   }
10517 
10518   if (((splitsh != nullptr) && (splitsh->sh != nullptr)) ||
10519       ((splitseg != nullptr) && (splitseg->sh != nullptr))) {
10520     // Delete the old subfaces in sC(p).
10521     for (i = 0; i < caveshlist->objects; i++) {
10522       parysh = (face *) fastlookup(caveshlist, i);
10523       if (checksubfaceflag) {//if (bowywat == 2) {
10524         // It is possible that this subface still connects to adjacent
10525         //   tets which are not in C(p). If so, clear connections in the
10526         //   adjacent tets at this subface.
10527         stpivot(*parysh, neightet);
10528         if (neightet.tet != nullptr) {
10529           if (neightet.tet[4] != nullptr) {
10530             // Found an adjacent tet. It must be not in C(p).
10531             assert(!infected(neightet));
10532             tsdissolve(neightet);
10533             fsymself(neightet);
10534             assert(!infected(neightet));
10535             tsdissolve(neightet);
10536           }
10537         }
10538       }
10539       shellfacedealloc(subfaces, parysh->sh);
10540     }
10541     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
10542       // Delete the old segment in sC(p).
10543       shellfacedealloc(subsegs, splitseg->sh);
10544     }
10545   }
10546 
10547   if (ivf->lawson) {
10548     for (i = 0; i < cavebdrylist->objects; i++) {
10549       searchtet = (triface *) fastlookup(cavebdrylist, i);
10550       flippush(flipstack, searchtet);
10551     }
10552     if (ivf->lawson > 1) {
10553       for (i = 0; i < cavetetlist->objects; i++) {
10554         searchtet = (triface *) fastlookup(cavetetlist, i);
10555         flippush(flipstack, searchtet);
10556       }
10557     }
10558   }
10559 
10560   // Set the point type if it is not set yet.
10561   if (pointtype(insertpt) == UNUSEDVERTEX) {
10562     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
10563       setpointtype(insertpt, FREESEGVERTEX);
10564     } else if ((splitsh != nullptr) && (splitsh->sh != nullptr)) {
10565       setpointtype(insertpt, FREEFACETVERTEX);
10566     } else {
10567       setpointtype(insertpt, FREEVOLVERTEX);
10568     }
10569   }
10570 
10571   // Clean the working lists.
10572 
10573   caveoldtetlist->restart();
10574   cavebdrylist->restart();
10575   cavetetlist->restart();
10576 
10577   if (checksubsegflag) {
10578     cavetetseglist->restart();
10579     caveencseglist->restart();
10580   }
10581 
10582   if (checksubfaceflag) {
10583     cavetetshlist->restart();
10584     caveencshlist->restart();
10585   }
10586 
10587   if (b->weighted || ivf->validflag) {
10588     cavetetvertlist->restart();
10589   }
10590 
10591   if (((splitsh != nullptr) && (splitsh->sh != nullptr)) ||
10592       ((splitseg != nullptr) && (splitseg->sh != nullptr))) {
10593     caveshlist->restart();
10594     caveshbdlist->restart();
10595     cavesegshlist->restart();
10596   }
10597 
10598   return 1; // Point is inserted.
10599 }
10600 
10601 ///////////////////////////////////////////////////////////////////////////////
10602 //                                                                           //
10603 // insertpoint_abort()    Abort the insertion of a new vertex.               //
10604 //                                                                           //
10605 // The cavity will be restored.  All working lists are cleared.              //
10606 //                                                                           //
10607 ///////////////////////////////////////////////////////////////////////////////
10608 
insertpoint_abort(face * splitseg,insertvertexflags * ivf)10609 void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
10610 {
10611   triface *cavetet;
10612   face *parysh;
10613   int i;
10614 
10615   for (i = 0; i < caveoldtetlist->objects; i++) {
10616     cavetet = (triface *) fastlookup(caveoldtetlist, i);
10617     uninfect(*cavetet);
10618     unmarktest(*cavetet);
10619   }
10620   for (i = 0; i < cavebdrylist->objects; i++) {
10621     cavetet = (triface *) fastlookup(cavebdrylist, i);
10622     unmarktest(*cavetet);
10623   }
10624   cavetetlist->restart();
10625   cavebdrylist->restart();
10626   caveoldtetlist->restart();
10627   cavetetseglist->restart();
10628   cavetetshlist->restart();
10629   if (ivf->splitbdflag) {
10630     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
10631       sunmarktest(*splitseg);
10632     }
10633     for (i = 0; i < caveshlist->objects; i++) {
10634       parysh = (face *) fastlookup(caveshlist, i);
10635       assert(smarktested(*parysh));
10636       sunmarktest(*parysh);
10637     }
10638     caveshlist->restart();
10639     cavesegshlist->restart();
10640   }
10641 }
10642 
10643 ////                                                                       ////
10644 ////                                                                       ////
10645 //// flip_cxx /////////////////////////////////////////////////////////////////
10646 
10647 //// delaunay_cxx /////////////////////////////////////////////////////////////
10648 ////                                                                       ////
10649 ////                                                                       ////
10650 
10651 ///////////////////////////////////////////////////////////////////////////////
10652 //                                                                           //
10653 // transfernodes()    Read the vertices from the input (tetgenio).           //
10654 //                                                                           //
10655 // Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
10656 // All points are indexed (the first point index is 'in->firstnumber'). Each //
10657 // point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
10658 // ...) and the diameter (longest) of the point set are calculated.          //
10659 //                                                                           //
10660 ///////////////////////////////////////////////////////////////////////////////
10661 
transfernodes()10662 void tetgenmesh::transfernodes()
10663 {
10664   point pointloop;
10665   REAL x, y, z, w;
10666   int coordindex;
10667   int attribindex;
10668   int mtrindex;
10669   int i, j;
10670 
10671   if (b->psc) {
10672     assert(in->pointparamlist != nullptr);
10673   }
10674 
10675   // Read the points.
10676   coordindex = 0;
10677   attribindex = 0;
10678   mtrindex = 0;
10679   for (i = 0; i < in->numberofpoints; i++) {
10680     makepoint(&pointloop, UNUSEDVERTEX);
10681     // Read the point coordinates.
10682     x = pointloop[0] = in->pointlist[coordindex++];
10683     y = pointloop[1] = in->pointlist[coordindex++];
10684     z = pointloop[2] = in->pointlist[coordindex++];
10685     // Read the point attributes. (Including point weights.)
10686     for (j = 0; j < in->numberofpointattributes; j++) {
10687       pointloop[3 + j] = in->pointattributelist[attribindex++];
10688     }
10689     // Read the point metric tensor.
10690     for (j = 0; j < in->numberofpointmtrs; j++) {
10691       pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
10692     }
10693     if (b->weighted) { // -w option
10694       if (in->numberofpointattributes > 0) {
10695         // The first point attribute is its weight.
10696         //w = in->pointattributelist[in->numberofpointattributes * i];
10697         w = pointloop[3];
10698       } else {
10699         // No given weight available. Default choose the maximum
10700         //   absolute value among its coordinates.
10701         w = fabs(x);
10702         if (w < fabs(y)) w = fabs(y);
10703         if (w < fabs(z)) w = fabs(z);
10704       }
10705       if (b->weighted_param == 0) {
10706         pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
10707       } else { // -w1 option
10708         pointloop[3] = w;  // Regular tetrahedralization.
10709       }
10710     }
10711     // Determine the smallest and largests x, y and z coordinates.
10712     if (i == 0) {
10713       xmin = xmax = x;
10714       ymin = ymax = y;
10715       zmin = zmax = z;
10716     } else {
10717       xmin = (x < xmin) ? x : xmin;
10718       xmax = (x > xmax) ? x : xmax;
10719       ymin = (y < ymin) ? y : ymin;
10720       ymax = (y > ymax) ? y : ymax;
10721       zmin = (z < zmin) ? z : zmin;
10722       zmax = (z > zmax) ? z : zmax;
10723     }
10724     if (b->psc) {
10725       // Read the geometry parameters.
10726       setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
10727       setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
10728       setpointgeomtag(pointloop, in->pointparamlist[i].tag);
10729       if (in->pointparamlist[i].type == 0) {
10730         setpointtype(pointloop, RIDGEVERTEX);
10731       } else if (in->pointparamlist[i].type == 1) {
10732         setpointtype(pointloop, FREESEGVERTEX);
10733       } else if (in->pointparamlist[i].type == 2) {
10734         setpointtype(pointloop, FREEFACETVERTEX);
10735       } else if (in->pointparamlist[i].type == 3) {
10736         setpointtype(pointloop, FREEVOLVERTEX);
10737       }
10738     }
10739   }
10740 
10741   // 'longest' is the largest possible edge length formed by input vertices.
10742   x = xmax - xmin;
10743   y = ymax - ymin;
10744   z = zmax - zmin;
10745   longest = sqrt(x * x + y * y + z * z);
10746   if (longest == 0.0) {
10747     printf("Error:  The point set is trivial.\n");
10748     terminatetetgen(3);
10749   }
10750 
10751   // Two identical points are distinguished by 'lengthlimit'.
10752   if (b->minedgelength == 0.0) {
10753     b->minedgelength = longest * b->epsilon;
10754   }
10755 }
10756 
10757 ///////////////////////////////////////////////////////////////////////////////
10758 //                                                                           //
10759 // hilbert_init()    Initialize the Gray code permutation table.             //
10760 //                                                                           //
10761 // The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray  //
10762 // code sequences traveled by the 1st order Hilbert curve in 3 dimensions.   //
10763 // The first column is the Gray code of the entry point of the curve, and    //
10764 // the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
10765 // the exit point of curve lies.                                             //
10766 //                                                                           //
10767 // The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
10768 // indices from 0 to 7, modulo by '3'. The code for generating this table is //
10769 // from: http://graphics.stanford.edu/~seander/bithacks.html.                //
10770 //                                                                           //
10771 ///////////////////////////////////////////////////////////////////////////////
10772 
hilbert_init(int n)10773 void tetgenmesh::hilbert_init(int n)
10774 {
10775   int gc[8], N, mask, travel_bit;
10776   int e, d, f, k, g;
10777   int v, c;
10778   int i;
10779 
10780   N = (n == 2) ? 4 : 8;
10781   mask = (n == 2) ? 3 : 7;
10782 
10783   // Generate the Gray code sequence.
10784   for (i = 0; i < N; i++) {
10785     gc[i] = i ^ (i >> 1);
10786   }
10787 
10788   for (e = 0; e < N; e++) {
10789     for (d = 0; d < n; d++) {
10790       // Calculate the end point (f).
10791       f = e ^ (1 << d);  // Toggle the d-th bit of 'e'.
10792       // travel_bit = 2**p, the bit we want to travel.
10793       travel_bit = e ^ f;
10794       for (i = 0; i < N; i++) {
10795         // // Rotate gc[i] left by (p + 1) % n bits.
10796         k = gc[i] * (travel_bit * 2);
10797         g = ((k | (k / N)) & mask);
10798         // Calculate the permuted Gray code by xor with the start point (e).
10799         transgc[e][d][i] = (g ^ e);
10800       }
10801       assert(transgc[e][d][0] == e);
10802       assert(transgc[e][d][N - 1] == f);
10803     } // d
10804   } // e
10805 
10806   // Count the consecutive '1' bits (trailing) on the right.
10807   tsb1mod3[0] = 0;
10808   for (i = 1; i < N; i++) {
10809     v = ~i; // Count the 0s.
10810     v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
10811     for (c = 0; v; c++) {
10812       v >>= 1;
10813     }
10814     tsb1mod3[i] = c % n;
10815   }
10816 }
10817 
10818 ///////////////////////////////////////////////////////////////////////////////
10819 //                                                                           //
10820 // hilbert_sort3()    Sort points using the 3d Hilbert curve.                //
10821 //                                                                           //
10822 ///////////////////////////////////////////////////////////////////////////////
10823 
hilbert_split(point * vertexarray,int arraysize,int gc0,int gc1,REAL bxmin,REAL bxmax,REAL bymin,REAL bymax,REAL bzmin,REAL bzmax)10824 int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
10825                               REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10826                               REAL bzmin, REAL bzmax)
10827 {
10828   point swapvert;
10829   int axis, d;
10830   REAL split;
10831   int i, j;
10832 
10833 
10834   // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
10835   //   correspoding to x-, or y- or z-axis.
10836   axis = (gc0 ^ gc1) >> 1;
10837 
10838   // Calulate the split position along the axis.
10839   if (axis == 0) {
10840     split = 0.5 * (bxmin + bxmax);
10841   } else if (axis == 1) {
10842     split = 0.5 * (bymin + bymax);
10843   } else { // == 2
10844     split = 0.5 * (bzmin + bzmax);
10845   }
10846 
10847   // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
10848   //   of the axis is to the positive of the axis, otherwise, it is -1.
10849   d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
10850 
10851 
10852   // Partition the vertices into left- and right-arraies such that left points
10853   //   have Hilbert indices lower than the right points.
10854   i = 0;
10855   j = arraysize - 1;
10856 
10857   // Partition the vertices into left- and right-arraies.
10858   if (d > 0) {
10859     do {
10860       for (; i < arraysize; i++) {
10861         if (vertexarray[i][axis] >= split) break;
10862       }
10863       for (; j >= 0; j--) {
10864         if (vertexarray[j][axis] < split) break;
10865       }
10866       // Is the partition finished?
10867       if (i == (j + 1)) break;
10868       // Swap i-th and j-th vertices.
10869       swapvert = vertexarray[i];
10870       vertexarray[i] = vertexarray[j];
10871       vertexarray[j] = swapvert;
10872       // Continue patitioning the array;
10873     } while (true);
10874   } else {
10875     do {
10876       for (; i < arraysize; i++) {
10877         if (vertexarray[i][axis] <= split) break;
10878       }
10879       for (; j >= 0; j--) {
10880         if (vertexarray[j][axis] > split) break;
10881       }
10882       // Is the partition finished?
10883       if (i == (j + 1)) break;
10884       // Swap i-th and j-th vertices.
10885       swapvert = vertexarray[i];
10886       vertexarray[i] = vertexarray[j];
10887       vertexarray[j] = swapvert;
10888       // Continue patitioning the array;
10889     } while (true);
10890   }
10891 
10892   return i;
10893 }
10894 
hilbert_sort3(point * vertexarray,int arraysize,int e,int d,REAL bxmin,REAL bxmax,REAL bymin,REAL bymax,REAL bzmin,REAL bzmax,int depth)10895 void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
10896                                REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
10897                                REAL bzmin, REAL bzmax, int depth)
10898 {
10899   REAL x1, x2, y1, y2, z1, z2;
10900   int p[9], w, e_w, d_w, k, ei, di;
10901   int n = 3, mask = 7;
10902 
10903   p[0] = 0;
10904   p[8] = arraysize;
10905 
10906   // Sort the points according to the 1st order Hilbert curve in 3d.
10907   p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
10908                        bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10909   p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
10910                        bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10911   p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
10912                        bxmin, bxmax, bymin, bymax, bzmin, bzmax);
10913   p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
10914                        transgc[e][d][2], transgc[e][d][3],
10915                        bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
10916   p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
10917                        transgc[e][d][5], transgc[e][d][6],
10918                        bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10919   p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
10920                        transgc[e][d][4], transgc[e][d][5],
10921                        bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
10922   p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
10923                        transgc[e][d][6], transgc[e][d][7],
10924                        bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
10925 
10926   if (b->hilbert_order > 0) {
10927     // A maximum order is prescribed.
10928     if ((depth + 1) == b->hilbert_order) {
10929       // The maximum prescribed order is reached.
10930       return;
10931     }
10932   }
10933 
10934   // Recursivly sort the points in sub-boxes.
10935   for (w = 0; w < 8; w++) {
10936     // w is the local Hilbert index (NOT Gray code).
10937     // Sort into the sub-box either there are more than 2 points in it, or
10938     //   the prescribed order of the curve is not reached yet.
10939     //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
10940     if ((p[w+1] - p[w]) > b->hilbert_limit) {
10941       // Calulcate the start point (ei) of the curve in this sub-box.
10942       //   update e = e ^ (e(w) left_rotate (d+1)).
10943       if (w == 0) {
10944         e_w = 0;
10945       } else {
10946         //   calculate e(w) = gc(2 * floor((w - 1) / 2)).
10947         k = 2 * ((w - 1) / 2);
10948         e_w = k ^ (k >> 1); // = gc(k).
10949       }
10950       k = e_w;
10951       e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
10952       ei = e ^ e_w;
10953       // Calulcate the direction (di) of the curve in this sub-box.
10954       //   update d = (d + d(w) + 1) % n
10955       if (w == 0) {
10956         d_w = 0;
10957       } else {
10958         d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
10959       }
10960       di = (d + d_w + 1) % n;
10961       // Calculate the bounding box of the sub-box.
10962       if (transgc[e][d][w] & 1) { // x-axis
10963         x1 = 0.5 * (bxmin + bxmax);
10964         x2 = bxmax;
10965       } else {
10966         x1 = bxmin;
10967         x2 = 0.5 * (bxmin + bxmax);
10968       }
10969       if (transgc[e][d][w] & 2) { // y-axis
10970         y1 = 0.5 * (bymin + bymax);
10971         y2 = bymax;
10972       } else {
10973         y1 = bymin;
10974         y2 = 0.5 * (bymin + bymax);
10975       }
10976       if (transgc[e][d][w] & 4) { // z-axis
10977         z1 = 0.5 * (bzmin + bzmax);
10978         z2 = bzmax;
10979       } else {
10980         z1 = bzmin;
10981         z2 = 0.5 * (bzmin + bzmax);
10982       }
10983       hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
10984                     x1, x2, y1, y2, z1, z2, depth+1);
10985     } // if (p[w+1] - p[w] > 1)
10986   } // w
10987 }
10988 
10989 ///////////////////////////////////////////////////////////////////////////////
10990 //                                                                           //
10991 // brio_multiscale_sort()    Sort the points using BRIO and Hilbert curve.   //
10992 //                                                                           //
10993 ///////////////////////////////////////////////////////////////////////////////
10994 
brio_multiscale_sort(point * vertexarray,int arraysize,int threshold,REAL ratio,int * depth)10995 void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
10996                                       int threshold, REAL ratio, int *depth)
10997 {
10998   int middle;
10999 
11000   middle = 0;
11001   if (arraysize >= threshold) {
11002     (*depth)++;
11003     middle = (int)(arraysize * ratio);
11004     brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
11005   }
11006   // Sort the right-array (rnd-th round) using the Hilbert curve.
11007   hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
11008                 xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
11009 }
11010 
11011 ///////////////////////////////////////////////////////////////////////////////
11012 //                                                                           //
11013 // randomnation()    Generate a random number between 0 and 'choices' - 1.   //
11014 //                                                                           //
11015 ///////////////////////////////////////////////////////////////////////////////
11016 
randomnation(unsigned int choices)11017 unsigned long tetgenmesh::randomnation(unsigned int choices)
11018 {
11019   unsigned long newrandom;
11020 
11021   if (choices >= 714025l) {
11022     newrandom = (randomseed * 1366l + 150889l) % 714025l;
11023     randomseed = (newrandom * 1366l + 150889l) % 714025l;
11024     newrandom = newrandom * (choices / 714025l) + randomseed;
11025     if (newrandom >= choices) {
11026       return newrandom - choices;
11027     } else {
11028       return newrandom;
11029     }
11030   } else {
11031     randomseed = (randomseed * 1366l + 150889l) % 714025l;
11032     return randomseed % choices;
11033   }
11034 }
11035 
11036 ///////////////////////////////////////////////////////////////////////////////
11037 //                                                                           //
11038 // randomsample()    Randomly sample the tetrahedra for point loation.       //
11039 //                                                                           //
11040 // Searching begins from one of handles:  the input 'searchtet', a recently  //
11041 // encountered tetrahedron 'recenttet',  or from one chosen from a random    //
11042 // sample.  The choice is made by determining which one's origin is closest  //
11043 // to the point we are searcing for.                                         //
11044 //                                                                           //
11045 ///////////////////////////////////////////////////////////////////////////////
11046 
randomsample(point searchpt,triface * searchtet)11047 void tetgenmesh::randomsample(point searchpt,triface *searchtet)
11048 {
11049   tetrahedron *firsttet, *tetptr;
11050   point torg;
11051   void **sampleblock;
11052   uintptr_t alignptr;
11053   long sampleblocks, samplesperblock, samplenum;
11054   long tetblocks, i, j;
11055   REAL searchdist, dist;
11056 
11057   if (b->verbose > 2) {
11058     printf("      Random sampling tetrahedra for searching point %d.\n",
11059            pointmark(searchpt));
11060   }
11061 
11062   if (!nonconvex) {
11063     if (searchtet->tet == nullptr) {
11064       // A null tet. Choose the recenttet as the starting tet.
11065       *searchtet = recenttet;
11066       // Recenttet should not be dead.
11067       assert(recenttet.tet[4] != nullptr);
11068     }
11069 
11070     // 'searchtet' should be a valid tetrahedron. Choose the base face
11071     //   whose vertices must not be 'dummypoint'.
11072     searchtet->ver = 3;
11073     // Record the distance from its origin to the searching point.
11074     torg = org(*searchtet);
11075     searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11076                  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11077                  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11078 
11079     // If a recently encountered tetrahedron has been recorded and has not
11080     //   been deallocated, test it as a good starting point.
11081     if (recenttet.tet != searchtet->tet) {
11082       recenttet.ver = 3;
11083       torg = org(recenttet);
11084       dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11085              (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11086              (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11087       if (dist < searchdist) {
11088         *searchtet = recenttet;
11089         searchdist = dist;
11090       }
11091     }
11092   } else {
11093     // The mesh is non-convex. Do not use 'recenttet'.
11094     assert(samples >= 1l); // Make sure at least 1 sample.
11095     searchdist = longest;
11096   }
11097 
11098   // Select "good" candidate using k random samples, taking the closest one.
11099   //   The number of random samples taken is proportional to the fourth root
11100   //   of the number of tetrahedra in the mesh.
11101   while (samples * samples * samples * samples < tetrahedrons->items) {
11102     samples++;
11103   }
11104   // Find how much blocks in current tet pool.
11105   tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
11106             / b->tetrahedraperblock;
11107   // Find the average samples per block. Each block at least have 1 sample.
11108   samplesperblock = 1 + (samples / tetblocks);
11109   sampleblocks = samples / samplesperblock;
11110   sampleblock = tetrahedrons->firstblock;
11111   for (i = 0; i < sampleblocks; i++) {
11112     alignptr = (uintptr_t) (sampleblock + 1);
11113     firsttet = (tetrahedron *)
11114                (alignptr + (uintptr_t) tetrahedrons->alignbytes
11115                - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
11116     for (j = 0; j < samplesperblock; j++) {
11117       if (i == tetblocks - 1) {
11118         // This is the last block.
11119         samplenum = randomnation((int)
11120                       (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
11121       } else {
11122         samplenum = randomnation(b->tetrahedraperblock);
11123       }
11124       tetptr = (tetrahedron *)
11125                (firsttet + (samplenum * tetrahedrons->itemwords));
11126       torg = (point) tetptr[4];
11127       if (torg != (point) nullptr) {
11128         dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11129                (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11130                (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11131         if (dist < searchdist) {
11132           searchtet->tet = tetptr;
11133           searchtet->ver = 11; // torg = org(t);
11134           searchdist = dist;
11135         }
11136       } else {
11137         // A dead tet. Re-sample it.
11138         if (i != tetblocks - 1) j--;
11139       }
11140     }
11141     sampleblock = (void **) *sampleblock;
11142   }
11143 }
11144 
11145 ///////////////////////////////////////////////////////////////////////////////
11146 //                                                                           //
11147 // locate()    Find a tetrahedron containing a given point.                  //
11148 //                                                                           //
11149 // Begins its search from 'searchtet', assume there is a line segment L from //
11150 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk    //
11151 // towards 'searchpt' by traversing all faces intersected by L.              //
11152 //                                                                           //
11153 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
11154 // returned value indicates one of the following cases:                      //
11155 //   - ONVERTEX, the search point lies on the origin of 'searchtet'.         //
11156 //   - ONEDGE, the search point lies on an edge of 'searchtet'.              //
11157 //   - ONFACE, the search point lies on a face of 'searchtet'.               //
11158 //   - INTET, the search point lies in the interior of 'searchtet'.          //
11159 //   - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a     //
11160 //              hull face which is visible by the search point.              //
11161 //                                                                           //
11162 // WARNING: This routine is designed for convex triangulations, and will not //
11163 // generally work after the holes and concavities have been carved.          //
11164 //                                                                           //
11165 ///////////////////////////////////////////////////////////////////////////////
11166 
11167 enum tetgenmesh::locateresult
locate(point searchpt,triface * searchtet,int chkencflag)11168   tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag)
11169 {
11170   point torg, tdest, tapex, toppo;
11171   enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
11172   REAL ori, oriorg, oridest, oriapex;
11173   enum locateresult loc = OUTSIDE;
11174   int t1ver;
11175   int s;
11176 
11177   if (searchtet->tet == nullptr) {
11178     // A null tet. Choose the recenttet as the starting tet.
11179     searchtet->tet = recenttet.tet;
11180   }
11181 
11182   // Check if we are in the outside of the convex hull.
11183   if (ishulltet(*searchtet)) {
11184     // Get its adjacent tet (inside the hull).
11185     searchtet->ver = 3;
11186     fsymself(*searchtet);
11187   }
11188 
11189   // Let searchtet be the face such that 'searchpt' lies above to it.
11190   for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
11191     torg = org(*searchtet);
11192     tdest = dest(*searchtet);
11193     tapex = apex(*searchtet);
11194     ori = orient3d(torg, tdest, tapex, searchpt);
11195     if (ori < 0.0) break;
11196   }
11197   assert(searchtet->ver != 4);
11198 
11199   // Walk through tetrahedra to locate the point.
11200   while (true) {
11201 
11202     toppo = oppo(*searchtet);
11203 
11204     // Check if the vertex is we seek.
11205     if (toppo == searchpt) {
11206       // Adjust the origin of searchtet to be searchpt.
11207       esymself(*searchtet);
11208       eprevself(*searchtet);
11209       loc = ONVERTEX; // return ONVERTEX;
11210       break;
11211     }
11212 
11213     // We enter from one of serarchtet's faces, which face do we exit?
11214     oriorg = orient3d(tdest, tapex, toppo, searchpt);
11215     oridest = orient3d(tapex, torg, toppo, searchpt);
11216     oriapex = orient3d(torg, tdest, toppo, searchpt);
11217 
11218     // Now decide which face to move. It is possible there are more than one
11219     //   faces are viable moves. If so, randomly choose one.
11220     if (oriorg < 0) {
11221       if (oridest < 0) {
11222         if (oriapex < 0) {
11223           // All three faces are possible.
11224           s = randomnation(3); // 's' is in {0,1,2}.
11225           if (s == 0) {
11226             nextmove = ORGMOVE;
11227           } else if (s == 1) {
11228             nextmove = DESTMOVE;
11229           } else {
11230             nextmove = APEXMOVE;
11231           }
11232         } else {
11233           // Two faces, opposite to origin and destination, are viable.
11234           //s = randomnation(2); // 's' is in {0,1}.
11235           if (randomnation(2)) {
11236             nextmove = ORGMOVE;
11237           } else {
11238             nextmove = DESTMOVE;
11239           }
11240         }
11241       } else {
11242         if (oriapex < 0) {
11243           // Two faces, opposite to origin and apex, are viable.
11244           //s = randomnation(2); // 's' is in {0,1}.
11245           if (randomnation(2)) {
11246             nextmove = ORGMOVE;
11247           } else {
11248             nextmove = APEXMOVE;
11249           }
11250         } else {
11251           // Only the face opposite to origin is viable.
11252           nextmove = ORGMOVE;
11253         }
11254       }
11255     } else {
11256       if (oridest < 0) {
11257         if (oriapex < 0) {
11258           // Two faces, opposite to destination and apex, are viable.
11259           //s = randomnation(2); // 's' is in {0,1}.
11260           if (randomnation(2)) {
11261             nextmove = DESTMOVE;
11262           } else {
11263             nextmove = APEXMOVE;
11264           }
11265         } else {
11266           // Only the face opposite to destination is viable.
11267           nextmove = DESTMOVE;
11268         }
11269       } else {
11270         if (oriapex < 0) {
11271           // Only the face opposite to apex is viable.
11272           nextmove = APEXMOVE;
11273         } else {
11274           // The point we seek must be on the boundary of or inside this
11275           //   tetrahedron. Check for boundary cases.
11276           if (oriorg == 0) {
11277             // Go to the face opposite to origin.
11278             enextesymself(*searchtet);
11279             if (oridest == 0) {
11280               eprevself(*searchtet); // edge oppo->apex
11281               if (oriapex == 0) {
11282                 // oppo is duplicated with p.
11283                 loc = ONVERTEX; // return ONVERTEX;
11284                 break;
11285               }
11286               loc = ONEDGE; // return ONEDGE;
11287               break;
11288             }
11289             if (oriapex == 0) {
11290               enextself(*searchtet); // edge dest->oppo
11291               loc = ONEDGE; // return ONEDGE;
11292               break;
11293             }
11294             loc = ONFACE; // return ONFACE;
11295             break;
11296           }
11297           if (oridest == 0) {
11298             // Go to the face opposite to destination.
11299             eprevesymself(*searchtet);
11300             if (oriapex == 0) {
11301               eprevself(*searchtet); // edge oppo->org
11302               loc = ONEDGE; // return ONEDGE;
11303               break;
11304             }
11305             loc = ONFACE; // return ONFACE;
11306             break;
11307           }
11308           if (oriapex == 0) {
11309             // Go to the face opposite to apex
11310             esymself(*searchtet);
11311             loc = ONFACE; // return ONFACE;
11312             break;
11313           }
11314           loc = INTETRAHEDRON; // return INTETRAHEDRON;
11315           break;
11316         }
11317       }
11318     }
11319 
11320     // Move to the selected face.
11321     if (nextmove == ORGMOVE) {
11322       enextesymself(*searchtet);
11323     } else if (nextmove == DESTMOVE) {
11324       eprevesymself(*searchtet);
11325     } else {
11326       esymself(*searchtet);
11327     }
11328     if (chkencflag) {
11329       // Check if we are walking across a subface.
11330       if (issubface(*searchtet)) {
11331         loc = ENCSUBFACE;
11332         break;
11333       }
11334     }
11335     // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
11336     fsymself(*searchtet);
11337     if (oppo(*searchtet) == dummypoint) {
11338       loc = OUTSIDE; // return OUTSIDE;
11339       break;
11340     }
11341 
11342     // Retreat the three vertices of the base face.
11343     torg = org(*searchtet);
11344     tdest = dest(*searchtet);
11345     tapex = apex(*searchtet);
11346 
11347   } // while (true)
11348 
11349   return loc;
11350 }
11351 
11352 ///////////////////////////////////////////////////////////////////////////////
11353 //                                                                           //
11354 // flippush()    Push a face (possibly will be flipped) into flipstack.      //
11355 //                                                                           //
11356 // The face is marked. The flag is used to check the validity of the face on //
11357 // its popup.  Some other flips may change it already.                       //
11358 //                                                                           //
11359 ///////////////////////////////////////////////////////////////////////////////
11360 
flippush(badface * & fstack,triface * flipface)11361 void tetgenmesh::flippush(badface*& fstack, triface* flipface)
11362 {
11363   badface *newflipface;
11364 
11365   if (!facemarked(*flipface)) {
11366     newflipface = (badface *) flippool->alloc();
11367     newflipface->tt = *flipface;
11368     markface(newflipface->tt);
11369     // Push this face into stack.
11370     newflipface->nextitem = fstack;
11371     fstack = newflipface;
11372   }
11373 }
11374 
11375 ///////////////////////////////////////////////////////////////////////////////
11376 //                                                                           //
11377 // incrementalflip()    Incrementally flipping to construct DT.              //
11378 //                                                                           //
11379 // Faces need to be checked for flipping are already queued in 'flipstack'.  //
11380 // Return the total number of performed flips.                               //
11381 //                                                                           //
11382 // Comment:  This routine should be only used in the incremental Delaunay    //
11383 // construction.  In other cases, lawsonflip3d() should be used.             //
11384 //                                                                           //
11385 // If the new point lies outside of the convex hull ('hullflag' is set). The //
11386 // incremental flip algorithm still works as usual.  However, we must ensure //
11387 // that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
11388 // edge or face. Otherwise, the underlying space of the triangulation becomes//
11389 // non-manifold and it is not possible to flip further.                      //
11390 // Thanks to Joerg Rambau and Frank Lutz for helping in this issue.          //
11391 //                                                                           //
11392 ///////////////////////////////////////////////////////////////////////////////
11393 
incrementalflip(point newpt,int hullflag,flipconstraints * fc)11394 int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
11395 {
11396   badface *popface;
11397   triface fliptets[5], *parytet;
11398   point *pts, *parypt, pe;
11399   REAL sign, ori;
11400   int flipcount = 0;
11401   int t1ver;
11402   int i;
11403 
11404   if (b->verbose > 2) {
11405     printf("      Lawson flip (%ld faces).\n", flippool->items);
11406   }
11407 
11408   if (hullflag) {
11409     // 'newpt' lies in the outside of the convex hull.
11410     // Mark all hull vertices which are connecting to it.
11411     popface = flipstack;
11412     while (popface != nullptr) {
11413       pts = (point *) popface->tt.tet;
11414       for (i = 4; i < 8; i++) {
11415         if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
11416           if (!pinfected(pts[i])) {
11417             pinfect(pts[i]);
11418             cavetetvertlist->newindex((void **) &parypt);
11419             *parypt = pts[i];
11420           }
11421         }
11422       }
11423       popface = popface->nextitem;
11424     }
11425   }
11426 
11427   // Loop until the queue is empty.
11428   while (flipstack != nullptr) {
11429 
11430     // Pop a face from the stack.
11431     popface = flipstack;
11432     fliptets[0] = popface->tt;
11433     flipstack = flipstack->nextitem; // The next top item in stack.
11434     flippool->dealloc((void *) popface);
11435 
11436     // Skip it if it is a dead tet (destroyed by previous flips).
11437     if (isdeadtet(fliptets[0])) continue;
11438     // Skip it if it is not the same tet as we saved.
11439     if (!facemarked(fliptets[0])) continue;
11440 
11441     unmarkface(fliptets[0]);
11442 
11443     if ((point) fliptets[0].tet[7] == dummypoint) {
11444       // It must be a hull edge.
11445       fliptets[0].ver = epivot[fliptets[0].ver];
11446       // A hull edge. The current convex hull may be enlarged.
11447       fsym(fliptets[0], fliptets[1]);
11448       pts = (point *) fliptets[1].tet;
11449       ori = orient3d(pts[4], pts[5], pts[6], newpt);
11450       if (ori < 0) {
11451         // Visible. The convex hull will be enlarged.
11452         // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
11453         // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
11454         enext(fliptets[1], fliptets[2]);
11455         eprev(fliptets[1], fliptets[3]);
11456         fnextself(fliptets[2]); // [a,c,e,*]
11457         fnextself(fliptets[3]); // [c,b,e,*]
11458         if (oppo(fliptets[2]) == newpt) {
11459           if (oppo(fliptets[3]) == newpt) {
11460             // Both tets exist! A 4-to-1 flip is found.
11461             assert(0);
11462           } else {
11463             esym(fliptets[2], fliptets[0]);
11464             fnext(fliptets[0], fliptets[1]);
11465             fnext(fliptets[1], fliptets[2]);
11466             // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
11467             // This corresponds to my standard labels, where edge [e,d] is
11468             //   repalced by face [a,b,c], and a is the new vertex.
11469             //   [0] [c,a,d,e] (d = newpt)
11470             //   [1] [c,a,e,b] (c = dummypoint)
11471             //   [2] [c,a,b,d]
11472             flip32(fliptets, 1, fc);
11473           }
11474         } else {
11475           if (oppo(fliptets[3]) == newpt) {
11476             fnext(fliptets[3], fliptets[0]);
11477             fnext(fliptets[0], fliptets[1]);
11478             fnext(fliptets[1], fliptets[2]);
11479             // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
11480             //   [0] [c,b,d,a] (d = newpt)
11481             //   [1] [c,b,a,e] (c = dummypoint)
11482             //   [2] [c,b,e,d]
11483             flip32(fliptets, 1, fc);
11484           } else {
11485             if (hullflag) {
11486               // Reject this flip if pe is already marked.
11487               pe = oppo(fliptets[1]);
11488               if (!pinfected(pe)) {
11489                 pinfect(pe);
11490                 cavetetvertlist->newindex((void **) &parypt);
11491                 *parypt = pe;
11492                 // Perform a 2-to-3 flip.
11493                 flip23(fliptets, 1, fc);
11494               } else {
11495                 // Reject this flip.
11496                 flipcount--;
11497               }
11498             } else {
11499               // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
11500               //   [0] [a,b,c,d], d = newpt.
11501               //   [1] [b,a,c,e], c = dummypoint.
11502               flip23(fliptets, 1, fc);
11503             }
11504           }
11505         }
11506         flipcount++;
11507       } else if (ori == 0) {
11508         if (oppo(fliptets[1]) != newpt) {
11509           // A coplanar convex hull face!
11510           // Treat it as unflippable.
11511         } else {
11512           // Two identical hull faces were bonded together!
11513           assert(0);
11514         }
11515       } // ori
11516       continue;
11517     } // if (dummypoint)
11518 
11519     fsym(fliptets[0], fliptets[1]);
11520     if ((point) fliptets[1].tet[7] == dummypoint) {
11521       // A hull face is locally Delaunay.
11522       continue;
11523     }
11524     // Check if the adjacent tet has already been tested.
11525     if (marktested(fliptets[1])) {
11526       // It has been tested and it is Delaunay.
11527       continue;
11528     }
11529 
11530     // Test whether the face is locally Delaunay or not.
11531     pts = (point *) fliptets[1].tet;
11532     if (b->weighted) {
11533       sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
11534                         pts[4][3], pts[5][3], pts[6][3], pts[7][3],
11535                         newpt[3]);
11536     } else {
11537       sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
11538     }
11539 
11540 
11541     if (sign < 0) {
11542       point pd = newpt;
11543       point pe = oppo(fliptets[1]);
11544       // Check the convexity of its three edges. Stop checking either a
11545       //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
11546       //   encountered, and 'fliptet' represents that edge.
11547       for (i = 0; i < 3; i++) {
11548         ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
11549         if (ori <= 0) break;
11550         enextself(fliptets[0]);
11551       }
11552       if (ori > 0) {
11553         // A 2-to-3 flip is found.
11554         //   [0] [a,b,c,d],
11555         //   [1] [b,a,c,e]. no dummypoint.
11556         flip23(fliptets, 0, fc);
11557         flipcount++;
11558       } else { // ori <= 0
11559         // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
11560         //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
11561         // Check if there are three or four tets sharing at this edge.
11562         esymself(fliptets[0]); // [b,a,d,c]
11563         for (i = 0; i < 3; i++) {
11564           fnext(fliptets[i], fliptets[i+1]);
11565         }
11566         if (fliptets[3].tet == fliptets[0].tet) {
11567           // A 3-to-2 flip is found. (No hull tet.)
11568           flip32(fliptets, 0, fc);
11569           flipcount++;
11570         } else {
11571           // There are more than 3 tets at this edge.
11572           fnext(fliptets[3], fliptets[4]);
11573           if (fliptets[4].tet == fliptets[0].tet) {
11574             if (ori == 0) {
11575               // A 4-to-4 flip is found. (Two hull tets may be involved.)
11576               // Current tets in 'fliptets':
11577               //   [0] [b,a,d,c] (d may be newpt)
11578               //   [1] [b,a,c,e]
11579               //   [2] [b,a,e,f] (f may be dummypoint)
11580               //   [3] [b,a,f,d]
11581               esymself(fliptets[0]); // [a,b,c,d]
11582               // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
11583               //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
11584               //   It will be removed by the followed 3-to-2 flip.
11585               flip23(fliptets, 0, fc); // No hull tet.
11586               fnext(fliptets[3], fliptets[1]);
11587               fnext(fliptets[1], fliptets[2]);
11588               // Current tets in 'fliptets':
11589               //   [0] [...]
11590               //   [1] [b,a,d,e] (degenerated, d may be new point).
11591               //   [2] [b,a,e,f] (f may be dummypoint)
11592               //   [3] [b,a,f,d]
11593               // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
11594               //   Hull tets may be involved (f may be dummypoint).
11595               flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
11596               flipcount++;
11597             }
11598           }
11599         }
11600       } // ori
11601     } else {
11602       // The adjacent tet is Delaunay. Mark it to avoid testing it again.
11603       marktest(fliptets[1]);
11604       // Save it for unmarking it later.
11605       cavebdrylist->newindex((void **) &parytet);
11606       *parytet = fliptets[1];
11607     }
11608 
11609   } // while (flipstack)
11610 
11611   // Unmark saved tetrahedra.
11612   for (i = 0; i < cavebdrylist->objects; i++) {
11613     parytet = (triface *) fastlookup(cavebdrylist, i);
11614     unmarktest(*parytet);
11615   }
11616   cavebdrylist->restart();
11617 
11618   if (hullflag) {
11619     // Unmark infected vertices.
11620     for (i = 0; i < cavetetvertlist->objects; i++) {
11621       parypt = (point *) fastlookup(cavetetvertlist, i);
11622       puninfect(*parypt);
11623     }
11624     cavetetvertlist->restart();
11625   }
11626 
11627 
11628   return flipcount;
11629 }
11630 
11631 ///////////////////////////////////////////////////////////////////////////////
11632 //                                                                           //
11633 // initialdelaunay()    Create an initial Delaunay tetrahedralization.       //
11634 //                                                                           //
11635 // The tetrahedralization contains only one tetrahedron abcd, and four hull  //
11636 // tetrahedra. The points pa, pb, pc, and pd must be linearly independent.   //
11637 //                                                                           //
11638 ///////////////////////////////////////////////////////////////////////////////
11639 
initialdelaunay(point pa,point pb,point pc,point pd)11640 void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
11641 {
11642   triface firsttet, tetopa, tetopb, tetopc, tetopd;
11643   triface worktet, worktet1;
11644 
11645   if (b->verbose > 2) {
11646     printf("      Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
11647            pointmark(pb), pointmark(pc), pointmark(pd));
11648   }
11649 
11650   // Create the first tetrahedron.
11651   maketetrahedron(&firsttet);
11652   setvertices(firsttet, pa, pb, pc, pd);
11653   // Create four hull tetrahedra.
11654   maketetrahedron(&tetopa);
11655   setvertices(tetopa, pb, pc, pd, dummypoint);
11656   maketetrahedron(&tetopb);
11657   setvertices(tetopb, pc, pa, pd, dummypoint);
11658   maketetrahedron(&tetopc);
11659   setvertices(tetopc, pa, pb, pd, dummypoint);
11660   maketetrahedron(&tetopd);
11661   setvertices(tetopd, pb, pa, pc, dummypoint);
11662   hullsize += 4;
11663 
11664   // Connect hull tetrahedra to firsttet (at four faces of firsttet).
11665   bond(firsttet, tetopd);
11666   esym(firsttet, worktet);
11667   bond(worktet, tetopc); // ab
11668   enextesym(firsttet, worktet);
11669   bond(worktet, tetopa); // bc
11670   eprevesym(firsttet, worktet);
11671   bond(worktet, tetopb); // ca
11672 
11673   // Connect hull tetrahedra together (at six edges of firsttet).
11674   esym(tetopc, worktet);
11675   esym(tetopd, worktet1);
11676   bond(worktet, worktet1); // ab
11677   esym(tetopa, worktet);
11678   eprevesym(tetopd, worktet1);
11679   bond(worktet, worktet1); // bc
11680   esym(tetopb, worktet);
11681   enextesym(tetopd, worktet1);
11682   bond(worktet, worktet1); // ca
11683   eprevesym(tetopc, worktet);
11684   enextesym(tetopb, worktet1);
11685   bond(worktet, worktet1); // da
11686   eprevesym(tetopa, worktet);
11687   enextesym(tetopc, worktet1);
11688   bond(worktet, worktet1); // db
11689   eprevesym(tetopb, worktet);
11690   enextesym(tetopa, worktet1);
11691   bond(worktet, worktet1); // dc
11692 
11693   // Set the vertex type.
11694   if (pointtype(pa) == UNUSEDVERTEX) {
11695     setpointtype(pa, VOLVERTEX);
11696   }
11697   if (pointtype(pb) == UNUSEDVERTEX) {
11698     setpointtype(pb, VOLVERTEX);
11699   }
11700   if (pointtype(pc) == UNUSEDVERTEX) {
11701     setpointtype(pc, VOLVERTEX);
11702   }
11703   if (pointtype(pd) == UNUSEDVERTEX) {
11704     setpointtype(pd, VOLVERTEX);
11705   }
11706 
11707   setpoint2tet(pa, encode(firsttet));
11708   setpoint2tet(pb, encode(firsttet));
11709   setpoint2tet(pc, encode(firsttet));
11710   setpoint2tet(pd, encode(firsttet));
11711 
11712   // Remember the first tetrahedron.
11713   recenttet = firsttet;
11714 }
11715 
11716 ///////////////////////////////////////////////////////////////////////////////
11717 //                                                                           //
11718 // incrementaldelaunay()    Create a Delaunay tetrahedralization by          //
11719 //                          the incremental approach.                        //
11720 //                                                                           //
11721 ///////////////////////////////////////////////////////////////////////////////
11722 
11723 
incrementaldelaunay(clock_t & tv)11724 void tetgenmesh::incrementaldelaunay(clock_t& tv)
11725 {
11726   triface searchtet;
11727   point *permutarray, swapvertex;
11728   REAL v1[3], v2[3], n[3];
11729   REAL bboxsize, bboxsize2, bboxsize3, ori;
11730   int randindex;
11731   int ngroup = 0;
11732   int i, j;
11733 
11734   if (!b->quiet) {
11735     printf("Delaunizing vertices...\n");
11736   }
11737 
11738   // Form a random permuation (uniformly at random) of the set of vertices.
11739   permutarray = new point[in->numberofpoints];
11740   points->traversalinit();
11741 
11742   if (b->no_sort) {
11743     if (b->verbose) {
11744       printf("  Using the input order.\n");
11745     }
11746     for (i = 0; i < in->numberofpoints; i++) {
11747       permutarray[i] = (point) points->traverse();
11748     }
11749   } else {
11750     if (b->verbose) {
11751       printf("  Permuting vertices.\n");
11752     }
11753     srand(in->numberofpoints);
11754     for (i = 0; i < in->numberofpoints; i++) {
11755       randindex = rand() % (i + 1); // randomnation(i + 1);
11756       permutarray[i] = permutarray[randindex];
11757       permutarray[randindex] = (point) points->traverse();
11758     }
11759     if (b->brio_hilbert) { // -b option
11760       if (b->verbose) {
11761         printf("  Sorting vertices.\n");
11762       }
11763       hilbert_init(in->mesh_dim);
11764       brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold,
11765                            b->brio_ratio, &ngroup);
11766     }
11767   }
11768 
11769   tv = clock(); // Remember the time for sorting points.
11770 
11771   // Calculate the diagonal size of its bounding box.
11772   bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
11773   bboxsize2 = bboxsize * bboxsize;
11774   bboxsize3 = bboxsize2 * bboxsize;
11775 
11776   // Make sure the second vertex is not identical with the first one.
11777   i = 1;
11778   while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
11779     i++;
11780     if (i == in->numberofpoints - 1) {
11781       printf("Exception:  All vertices are (nearly) identical (Tol = %g).\n",
11782              b->epsilon);
11783       terminatetetgen(10);
11784     }
11785   }
11786   if (i > 1) {
11787     // Swap to move the non-indetical vertex from index i to index 1.
11788     swapvertex = permutarray[i];
11789     permutarray[i] = permutarray[1];
11790     permutarray[1] = swapvertex;
11791   }
11792 
11793   // Make sure the third vertex is not collinear with the first two.
11794   i = 2;
11795   for (j = 0; j < 3; j++) {
11796     v1[j] = permutarray[1][j] - permutarray[0][j];
11797     v2[j] = permutarray[i][j] - permutarray[0][j];
11798   }
11799   cross(v1, v2, n);
11800   while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) < b->epsilon) {
11801     i++;
11802     if (i == in->numberofpoints - 1) {
11803       printf("Exception:  All vertices are (nearly) collinear (Tol = %g).\n",
11804              b->epsilon);
11805       terminatetetgen(10);
11806     }
11807     for (j = 0; j < 3; j++) {
11808       v2[j] = permutarray[i][j] - permutarray[0][j];
11809     }
11810     cross(v1, v2, n);
11811   }
11812   if (i > 2) {
11813     // Swap to move the non-indetical vertex from index i to index 1.
11814     swapvertex = permutarray[i];
11815     permutarray[i] = permutarray[2];
11816     permutarray[2] = swapvertex;
11817   }
11818 
11819   // Make sure the fourth vertex is not coplanar with the first three.
11820   i = 3;
11821   ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11822                      permutarray[i]);
11823   while ((fabs(ori) / bboxsize3) < b->epsilon) {
11824     i++;
11825     if (i == in->numberofpoints) {
11826       printf("Exception:  All vertices are coplanar (Tol = %g).\n",
11827              b->epsilon);
11828       terminatetetgen(10);
11829     }
11830     ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
11831                        permutarray[i]);
11832   }
11833   if (i > 3) {
11834     // Swap to move the non-indetical vertex from index i to index 1.
11835     swapvertex = permutarray[i];
11836     permutarray[i] = permutarray[3];
11837     permutarray[3] = swapvertex;
11838   }
11839 
11840   // Orient the first four vertices in permutarray so that they follow the
11841   //   right-hand rule.
11842   if (ori > 0.0) {
11843     // Swap the first two vertices.
11844     swapvertex = permutarray[0];
11845     permutarray[0] = permutarray[1];
11846     permutarray[1] = swapvertex;
11847   }
11848 
11849   // Create the initial Delaunay tetrahedralization.
11850   initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
11851                   permutarray[3]);
11852 
11853   if (b->verbose) {
11854     printf("  Incrementally inserting vertices.\n");
11855   }
11856   insertvertexflags ivf;
11857   flipconstraints fc;
11858   // int loc;
11859 
11860   // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
11861   if (b->incrflip) {
11862     ivf.bowywat = 0;
11863     ivf.lawson = 1;
11864     fc.enqflag = 1;
11865   } else {
11866     ivf.bowywat = 1;
11867     ivf.lawson = 0;
11868   }
11869 
11870 
11871   for (i = 4; i < in->numberofpoints; i++) {
11872     if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
11873       setpointtype(permutarray[i], VOLVERTEX);
11874     }
11875     if (b->brio_hilbert || b->no_sort) { // -b or -b/1
11876       // Start the last updated tet.
11877       searchtet.tet = recenttet.tet;
11878     } else { // -b0
11879       // Randomly choose the starting tet for point location.
11880       searchtet.tet = nullptr;
11881     }
11882     ivf.iloc = (int) OUTSIDE;
11883     // Insert the vertex.
11884     if (insertpoint(permutarray[i], &searchtet, nullptr, nullptr, &ivf)) {
11885       if (flipstack != nullptr) {
11886         // Perform flip to recover Delaunayness.
11887         incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
11888       }
11889     } else {
11890       if (ivf.iloc == (int) ONVERTEX) {
11891         // The point already exists. Mark it and do nothing on it.
11892         swapvertex = org(searchtet);
11893         assert(swapvertex != permutarray[i]); // SELF_CHECK
11894         if (b->object != tetgenbehavior::STL) {
11895           if (!b->quiet) {
11896             printf("Warning:  Point #%d is coincident with #%d. Ignored!\n",
11897                    pointmark(permutarray[i]), pointmark(swapvertex));
11898           }
11899         }
11900         setpoint2ppt(permutarray[i], swapvertex);
11901         setpointtype(permutarray[i], DUPLICATEDVERTEX);
11902         dupverts++;
11903       } else if (ivf.iloc == (int) NEARVERTEX) {
11904         swapvertex = point2ppt(permutarray[i]);
11905         if (!b->quiet) {
11906           printf("Warning:  Point %d is replaced by point %d.\n",
11907                  pointmark(permutarray[i]), pointmark(swapvertex));
11908           printf("  Avoid creating a very short edge (len = %g) (< %g).\n",
11909                  permutarray[i][3], b->minedgelength);
11910           printf("  You may try a smaller tolerance (-T) (current is %g)\n",
11911                  b->epsilon);
11912           printf("  or use the option -M0/1 to avoid such replacement.\n");
11913         }
11914         // Remember it is a duplicated point.
11915         setpointtype(permutarray[i], DUPLICATEDVERTEX);
11916         // Count the number of duplicated points.
11917         dupverts++;
11918       }
11919     }
11920   }
11921 
11922 
11923 
11924   delete [] permutarray;
11925 }
11926 
11927 ////                                                                       ////
11928 ////                                                                       ////
11929 //// delaunay_cxx /////////////////////////////////////////////////////////////
11930 
11931 //// surface_cxx //////////////////////////////////////////////////////////////
11932 ////                                                                       ////
11933 ////                                                                       ////
11934 
11935 ///////////////////////////////////////////////////////////////////////////////
11936 //                                                                           //
11937 // flipshpush()    Push a facet edge into flip stack.                        //
11938 //                                                                           //
11939 ///////////////////////////////////////////////////////////////////////////////
11940 
flipshpush(face * flipedge)11941 void tetgenmesh::flipshpush(face* flipedge)
11942 {
11943   badface *newflipface;
11944 
11945   newflipface = (badface *) flippool->alloc();
11946   newflipface->ss = *flipedge;
11947   newflipface->forg = sorg(*flipedge);
11948   newflipface->fdest = sdest(*flipedge);
11949   newflipface->nextitem = flipstack;
11950   flipstack = newflipface;
11951 }
11952 
11953 ///////////////////////////////////////////////////////////////////////////////
11954 //                                                                           //
11955 // flip22()    Perform a 2-to-2 flip in surface mesh.                        //
11956 //                                                                           //
11957 // 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and   //
11958 // [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
11959 // is replaced by edge [c,d].                                                //
11960 //                                                                           //
11961 ///////////////////////////////////////////////////////////////////////////////
11962 
flip22(face * flipfaces,int flipflag,int chkencflag)11963 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
11964 {
11965   face bdedges[4], outfaces[4], infaces[4];
11966   face bdsegs[4];
11967   face checkface;
11968   point pa, pb, pc, pd;
11969   int i;
11970 
11971   pa = sorg(flipfaces[0]);
11972   pb = sdest(flipfaces[0]);
11973   pc = sapex(flipfaces[0]);
11974   pd = sapex(flipfaces[1]);
11975 
11976   if (sorg(flipfaces[1]) != pb) {
11977     sesymself(flipfaces[1]);
11978   }
11979 
11980   flip22count++;
11981 
11982   // Collect the four boundary edges.
11983   senext(flipfaces[0], bdedges[0]);
11984   senext2(flipfaces[0], bdedges[1]);
11985   senext(flipfaces[1], bdedges[2]);
11986   senext2(flipfaces[1], bdedges[3]);
11987 
11988   // Collect outer boundary faces.
11989   for (i = 0; i < 4; i++) {
11990     spivot(bdedges[i], outfaces[i]);
11991     infaces[i] = outfaces[i];
11992     sspivot(bdedges[i], bdsegs[i]);
11993     if (outfaces[i].sh != nullptr) {
11994       if (isshsubseg(bdedges[i])) {
11995         spivot(infaces[i], checkface);
11996         while (checkface.sh != bdedges[i].sh) {
11997           infaces[i] = checkface;
11998           spivot(infaces[i], checkface);
11999         }
12000       }
12001     }
12002   }
12003 
12004   // The flags set in these two subfaces do not change.
12005   // Shellmark does not change.
12006   // area constraint does not change.
12007 
12008   // Transform [a,b,c] -> [c,d,b].
12009   setshvertices(flipfaces[0], pc, pd, pb);
12010   // Transform [b,a,d] -> [d,c,a].
12011   setshvertices(flipfaces[1], pd, pc, pa);
12012 
12013   // Update the point-to-subface map.
12014   if (pointtype(pa) == FREEFACETVERTEX) {
12015     setpoint2sh(pa, sencode(flipfaces[1]));
12016   }
12017   if (pointtype(pb) == FREEFACETVERTEX) {
12018     setpoint2sh(pb, sencode(flipfaces[0]));
12019   }
12020   if (pointtype(pc) == FREEFACETVERTEX) {
12021     setpoint2sh(pc, sencode(flipfaces[0]));
12022   }
12023   if (pointtype(pd) == FREEFACETVERTEX) {
12024     setpoint2sh(pd, sencode(flipfaces[0]));
12025   }
12026 
12027   // Reconnect boundary edges to outer boundary faces.
12028   for (i = 0; i < 4; i++) {
12029     if (outfaces[(3 + i) % 4].sh != nullptr) {
12030       // Make sure that the subface has the ori as the segment.
12031       if (bdsegs[(3 + i) % 4].sh != nullptr) {
12032         bdsegs[(3 + i) % 4].shver = 0;
12033         if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
12034           sesymself(bdedges[i]);
12035         }
12036       }
12037       sbond1(bdedges[i], outfaces[(3 + i) % 4]);
12038       sbond1(infaces[(3 + i) % 4], bdedges[i]);
12039     } else {
12040       sdissolve(bdedges[i]);
12041     }
12042     if (bdsegs[(3 + i) % 4].sh != nullptr) {
12043       ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
12044       if (chkencflag & 1) {
12045         // Queue this segment for encroaching check.
12046         enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
12047       }
12048     } else {
12049       ssdissolve(bdedges[i]);
12050     }
12051   }
12052 
12053   if (chkencflag & 2) {
12054     // Queue the flipped subfaces for quality/encroaching checks.
12055     for (i = 0; i < 2; i++) {
12056       enqueuesubface(badsubfacs, &(flipfaces[i]));
12057     }
12058   }
12059 
12060   recentsh = flipfaces[0];
12061 
12062   if (flipflag) {
12063     // Put the boundary edges into flip stack.
12064     for (i = 0; i < 4; i++) {
12065       flipshpush(&(bdedges[i]));
12066     }
12067   }
12068 }
12069 
12070 ///////////////////////////////////////////////////////////////////////////////
12071 //                                                                           //
12072 // flip31()    Remove a vertex by transforming 3-to-1 subfaces.              //
12073 //                                                                           //
12074 // 'flipfaces' is an array of subfaces. Its length is at least 4.  On input, //
12075 // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine    //
12076 // replaces them by one face [a,b,c], it is returned in flipfaces[3].        //
12077 //                                                                           //
12078 // NOTE: The three old subfaces are not deleted within this routine.  They   //
12079 // still hold pointers to their adjacent subfaces. These informations are    //
12080 // needed by the routine 'sremovevertex()' for recovering a segment.         //
12081 // The caller of this routine must delete the old subfaces after their uses. //
12082 //                                                                           //
12083 ///////////////////////////////////////////////////////////////////////////////
12084 
flip31(face * flipfaces,int flipflag)12085 void tetgenmesh::flip31(face* flipfaces, int flipflag)
12086 {
12087   face bdedges[3], outfaces[3], infaces[3];
12088   face bdsegs[3];
12089   face checkface;
12090   point pa, pb, pc;
12091   int i;
12092 
12093   pa = sdest(flipfaces[0]);
12094   pb = sdest(flipfaces[1]);
12095   pc = sdest(flipfaces[2]);
12096 
12097   flip31count++;
12098 
12099   // Collect all infos at the three boundary edges.
12100   for (i = 0; i < 3; i++) {
12101     senext(flipfaces[i], bdedges[i]);
12102     spivot(bdedges[i], outfaces[i]);
12103     infaces[i] = outfaces[i];
12104     sspivot(bdedges[i], bdsegs[i]);
12105     if (outfaces[i].sh != nullptr) {
12106       if (isshsubseg(bdedges[i])) {
12107         spivot(infaces[i], checkface);
12108         while (checkface.sh != bdedges[i].sh) {
12109           infaces[i] = checkface;
12110           spivot(infaces[i], checkface);
12111         }
12112       }
12113     }
12114   } // i
12115 
12116   // Create a new subface.
12117   makeshellface(subfaces, &(flipfaces[3]));
12118   setshvertices(flipfaces[3], pa, pb,pc);
12119   setshellmark(flipfaces[3], shellmark(flipfaces[0]));
12120   if (checkconstraints) {
12121     //area = areabound(flipfaces[0]);
12122     setareabound(flipfaces[3], areabound(flipfaces[0]));
12123   }
12124 
12125   // Update the point-to-subface map.
12126   if (pointtype(pa) == FREEFACETVERTEX) {
12127     setpoint2sh(pa, sencode(flipfaces[3]));
12128   }
12129   if (pointtype(pb) == FREEFACETVERTEX) {
12130     setpoint2sh(pb, sencode(flipfaces[3]));
12131   }
12132   if (pointtype(pc) == FREEFACETVERTEX) {
12133     setpoint2sh(pc, sencode(flipfaces[3]));
12134   }
12135 
12136   // Update the three new boundary edges.
12137   bdedges[0] = flipfaces[3];         // [a,b]
12138   senext(flipfaces[3], bdedges[1]);  // [b,c]
12139   senext2(flipfaces[3], bdedges[2]); // [c,a]
12140 
12141   // Reconnect boundary edges to outer boundary faces.
12142   for (i = 0; i < 3; i++) {
12143     if (outfaces[i].sh != nullptr) {
12144       // Make sure that the subface has the ori as the segment.
12145       if (bdsegs[i].sh != nullptr) {
12146         bdsegs[i].shver = 0;
12147         if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
12148           sesymself(bdedges[i]);
12149         }
12150       }
12151       sbond1(bdedges[i], outfaces[i]);
12152       sbond1(infaces[i], bdedges[i]);
12153     }
12154     if (bdsegs[i].sh != nullptr) {
12155       ssbond(bdedges[i], bdsegs[i]);
12156     }
12157   }
12158 
12159   recentsh = flipfaces[3];
12160 
12161   if (flipflag) {
12162     // Put the boundary edges into flip stack.
12163     for (i = 0; i < 3; i++) {
12164       flipshpush(&(bdedges[i]));
12165     }
12166   }
12167 }
12168 
12169 ///////////////////////////////////////////////////////////////////////////////
12170 //                                                                           //
12171 // lawsonflip()    Flip non-locally Delaunay edges.                          //
12172 //                                                                           //
12173 ///////////////////////////////////////////////////////////////////////////////
12174 
lawsonflip()12175 long tetgenmesh::lawsonflip()
12176 {
12177   badface *popface;
12178   face flipfaces[2];
12179   point pa, pb, pc, pd;
12180   REAL sign;
12181   long flipcount = 0;
12182 
12183   if (b->verbose > 2) {
12184     printf("      Lawson flip %ld edges.\n", flippool->items);
12185   }
12186 
12187   while (flipstack != (badface *) nullptr) {
12188 
12189     // Pop an edge from the stack.
12190     popface = flipstack;
12191     flipfaces[0] = popface->ss;
12192     pa = popface->forg;
12193     pb = popface->fdest;
12194     flipstack = popface->nextitem; // The next top item in stack.
12195     flippool->dealloc((void *) popface);
12196 
12197     // Skip it if it is dead.
12198     if (flipfaces[0].sh[3] == nullptr) continue;
12199     // Skip it if it is not the same edge as we saved.
12200     if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
12201     // Skip it if it is a subsegment.
12202     if (isshsubseg(flipfaces[0])) continue;
12203 
12204     // Get the adjacent face.
12205     spivot(flipfaces[0], flipfaces[1]);
12206     if (flipfaces[1].sh == nullptr) continue; // Skip a hull edge.
12207     pc = sapex(flipfaces[0]);
12208     pd = sapex(flipfaces[1]);
12209 
12210     sign = incircle3d(pa, pb, pc, pd);
12211 
12212     if (sign < 0) {
12213       // It is non-locally Delaunay. Flip it.
12214       flip22(flipfaces, 1, 0);
12215       flipcount++;
12216     }
12217   }
12218 
12219   if (b->verbose > 2) {
12220     printf("      Performed %ld flips.\n", flipcount);
12221   }
12222 
12223   return flipcount;
12224 }
12225 
12226 ///////////////////////////////////////////////////////////////////////////////
12227 //                                                                           //
12228 // sinsertvertex()    Insert a vertex into a triangulation of a facet.       //
12229 //                                                                           //
12230 // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
12231 // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p),   //
12232 // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a  //
12233 // segment, 'cavesegshlist' returns the two new subsegments.                 //
12234 //                                                                           //
12235 // 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
12236 // will first locate the point. It starts searching from 'searchsh' or 'rec- //
12237 // entsh' if 'searchsh' is nullptr.                                             //
12238 //                                                                           //
12239 // If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert    //
12240 // the vertex. Otherwise, only insert the vertex in the initial cavity.      //
12241 //                                                                           //
12242 // If 'iloc' is 'INSTAR', this means the cavity of this vertex was already   //
12243 // provided in the list 'caveshlist'.                                        //
12244 //                                                                           //
12245 // If 'splitseg' is not nullptr, the new vertex lies on the segment and it will //
12246 // be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'.                     //
12247 //                                                                           //
12248 // 'rflag' (rounding) is a parameter passed to slocate() function.  If it is //
12249 // set, after the location of the point is found, either ONEDGE or ONFACE,   //
12250 // round the result using an epsilon.                                        //
12251 //                                                                           //
12252 // NOTE: the old subfaces in C(p) are not deleted. Theyare needed in case we //
12253 // want to remove the new point immedately.                                  //
12254 //                                                                           //
12255 ///////////////////////////////////////////////////////////////////////////////
12256 
sinsertvertex(point insertpt,face * searchsh,face * splitseg,int iloc,int bowywat,int rflag)12257 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
12258                               int iloc, int bowywat, int rflag)
12259 {
12260   face cavesh, neighsh, *parysh;
12261   face newsh, casout, casin;
12262   face checkseg;
12263   point pa, pb;
12264   enum locateresult loc = OUTSIDE;
12265   REAL sign, ori;
12266   int i, j;
12267 
12268   if (b->verbose > 2) {
12269     printf("      Insert facet point %d.\n", pointmark(insertpt));
12270   }
12271 
12272   if (bowywat == 3) {
12273     loc = INSTAR;
12274   }
12275 
12276   if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
12277     // A segment is going to be split, no point location.
12278     spivot(*splitseg, *searchsh);
12279     if (loc != INSTAR) loc = ONEDGE;
12280   } else {
12281     if (loc != INSTAR) loc = (enum locateresult) iloc;
12282     if (loc == OUTSIDE) {
12283       // Do point location in surface mesh.
12284       if (searchsh->sh == nullptr) {
12285         *searchsh = recentsh;
12286       }
12287       // Search the vertex. An above point must be provided ('aflag' = 1).
12288       loc = slocate(insertpt, searchsh, 1, 1, rflag);
12289     }
12290   }
12291 
12292 
12293   // Form the initial sC(p).
12294   if (loc == ONFACE) {
12295     // Add the face into list (in B-W cavity).
12296     smarktest(*searchsh);
12297     caveshlist->newindex((void **) &parysh);
12298     *parysh = *searchsh;
12299   } else if (loc == ONEDGE) {
12300     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
12301       splitseg->shver = 0;
12302       pa = sorg(*splitseg);
12303     } else {
12304       pa = sorg(*searchsh);
12305     }
12306     if (searchsh->sh != nullptr) {
12307       // Collect all subfaces share at this edge.
12308       neighsh = *searchsh;
12309       while (1) {
12310         // Adjust the origin of its edge to be 'pa'.
12311         if (sorg(neighsh) != pa) sesymself(neighsh);
12312         // Add this face into list (in B-W cavity).
12313         smarktest(neighsh);
12314         caveshlist->newindex((void **) &parysh);
12315         *parysh = neighsh;
12316         // Add this face into face-at-splitedge list.
12317         cavesegshlist->newindex((void **) &parysh);
12318         *parysh = neighsh;
12319         // Go to the next face at the edge.
12320         spivotself(neighsh);
12321         // Stop if all faces at the edge have been visited.
12322         if (neighsh.sh == searchsh->sh) break;
12323         if (neighsh.sh == nullptr) break;
12324       }
12325     } // If (not a non-dangling segment).
12326   } else if (loc == ONVERTEX) {
12327     return (int) loc;
12328   } else if (loc == OUTSIDE) {
12329     // Comment: This should only happen during the surface meshing step.
12330     // Enlarge the convex hull of the triangulation by including p.
12331     // An above point of the facet is set in 'dummypoint' to replace
12332     // orient2d tests by orient3d tests.
12333     // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
12334     //   plane, and a->b is directed from left to right, p lies above a->b.
12335     //   Find the right-most edge of the triangulation which is visible by p.
12336     neighsh = *searchsh;
12337     while (1) {
12338       senext2self(neighsh);
12339       spivot(neighsh, casout);
12340       if (casout.sh == nullptr) {
12341         // A convex hull edge. Is it visible by p.
12342         ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
12343         if (ori < 0) {
12344           *searchsh = neighsh; // Visible, update 'searchsh'.
12345         } else {
12346           break; // 'searchsh' is the right-most visible edge.
12347         }
12348       } else {
12349         if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12350         neighsh = casout;
12351       }
12352     }
12353     // Create new triangles for all visible edges of p (from right to left).
12354     casin.sh = nullptr;  // No adjacent face at right.
12355     pa = sorg(*searchsh);
12356     pb = sdest(*searchsh);
12357     while (1) {
12358       // Create a new subface on top of the (visible) edge.
12359       makeshellface(subfaces, &newsh);
12360       setshvertices(newsh, pb, pa, insertpt);
12361       setshellmark(newsh, shellmark(*searchsh));
12362       if (checkconstraints) {
12363         //area = areabound(*searchsh);
12364         setareabound(newsh, areabound(*searchsh));
12365       }
12366       // Connect the new subface to the bottom subfaces.
12367       sbond1(newsh, *searchsh);
12368       sbond1(*searchsh, newsh);
12369       // Connect the new subface to its right-adjacent subface.
12370       if (casin.sh != nullptr) {
12371         senext(newsh, casout);
12372         sbond1(casout, casin);
12373         sbond1(casin, casout);
12374       }
12375       // The left-adjacent subface has not been created yet.
12376       senext2(newsh, casin);
12377       // Add the new face into list (inside the B-W cavity).
12378       smarktest(newsh);
12379       caveshlist->newindex((void **) &parysh);
12380       *parysh = newsh;
12381       // Move to the convex hull edge at the left of 'searchsh'.
12382       neighsh = *searchsh;
12383       while (1) {
12384         senextself(neighsh);
12385         spivot(neighsh, casout);
12386         if (casout.sh == nullptr) {
12387           *searchsh = neighsh;
12388           break;
12389         }
12390         if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12391         neighsh = casout;
12392       }
12393       // A convex hull edge. Is it visible by p.
12394       pa = sorg(*searchsh);
12395       pb = sdest(*searchsh);
12396       ori = orient3d(pa, pb, dummypoint, insertpt);
12397       // Finish the process if p is not visible by the hull edge.
12398       if (ori >= 0) break;
12399     }
12400   } else if (loc == INSTAR) {
12401     // Under this case, the sub-cavity sC(p) has already been formed in
12402     //   insertvertex().
12403   }
12404 
12405   // Form the Bowyer-Watson cavity sC(p).
12406   for (i = 0; i < caveshlist->objects; i++) {
12407     cavesh = * (face *) fastlookup(caveshlist, i);
12408     for (j = 0; j < 3; j++) {
12409       if (!isshsubseg(cavesh)) {
12410         spivot(cavesh, neighsh);
12411         if (neighsh.sh != nullptr) {
12412           // The adjacent face exists.
12413           if (!smarktested(neighsh)) {
12414             if (bowywat) {
12415               if (loc == INSTAR) { // if (bowywat > 2) {
12416                 // It must be a boundary edge.
12417                 sign = 1;
12418               } else {
12419                 // Check if this subface is connected to adjacent tet(s).
12420                 if (!isshtet(neighsh)) {
12421                   // Check if the subface is non-Delaunay wrt. the new pt.
12422                   sign = incircle3d(sorg(neighsh), sdest(neighsh),
12423                                     sapex(neighsh), insertpt);
12424                 } else {
12425                   // It is connected to an adjacent tet. A boundary edge.
12426                   sign = 1;
12427                 }
12428               }
12429               if (sign < 0) {
12430                 // Add the adjacent face in list (in B-W cavity).
12431                 smarktest(neighsh);
12432                 caveshlist->newindex((void **) &parysh);
12433                 *parysh = neighsh;
12434               }
12435             } else {
12436               sign = 1; // A boundary edge.
12437             }
12438           } else {
12439             sign = -1; // Not a boundary edge.
12440           }
12441         } else {
12442           // No adjacent face. It is a hull edge.
12443           if (loc == OUTSIDE) {
12444             // It is a boundary edge if it does not contain p.
12445             if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
12446               sign = -1; // Not a boundary edge.
12447             } else {
12448               sign = 1; // A boundary edge.
12449             }
12450           } else {
12451             sign = 1; // A boundary edge.
12452           }
12453         }
12454       } else {
12455         // Do not across a segment. It is a boundary edge.
12456         sign = 1;
12457       }
12458       if (sign >= 0) {
12459         // Add a boundary edge.
12460         caveshbdlist->newindex((void **) &parysh);
12461         *parysh = cavesh;
12462       }
12463       senextself(cavesh);
12464     } // j
12465   } // i
12466 
12467 
12468   // Creating new subfaces.
12469   for (i = 0; i < caveshbdlist->objects; i++) {
12470     parysh = (face *) fastlookup(caveshbdlist, i);
12471     sspivot(*parysh, checkseg);
12472     if ((parysh->shver & 01) != 0) sesymself(*parysh);
12473     pa = sorg(*parysh);
12474     pb = sdest(*parysh);
12475     // Create a new subface.
12476     makeshellface(subfaces, &newsh);
12477     setshvertices(newsh, pa, pb, insertpt);
12478     setshellmark(newsh, shellmark(*parysh));
12479     setshelltype(newsh, shelltype(*parysh));
12480     if (checkconstraints) {
12481       //area = areabound(*parysh);
12482       setareabound(newsh, areabound(*parysh));
12483     }
12484     // Update the point-to-subface map.
12485     if (pointtype(pa) == FREEFACETVERTEX) {
12486       setpoint2sh(pa, sencode(newsh));
12487     }
12488     if (pointtype(pb) == FREEFACETVERTEX) {
12489       setpoint2sh(pb, sencode(newsh));
12490     }
12491     // Connect newsh to outer subfaces.
12492     spivot(*parysh, casout);
12493     if (casout.sh != nullptr) {
12494       casin = casout;
12495       if (checkseg.sh != nullptr) {
12496         // Make sure that newsh has the right ori at this segment.
12497         checkseg.shver = 0;
12498         if (sorg(newsh) != sorg(checkseg)) {
12499           sesymself(newsh);
12500           sesymself(*parysh); // This side should also be inversed.
12501         }
12502         spivot(casin, neighsh);
12503         while (neighsh.sh != parysh->sh) {
12504           casin = neighsh;
12505           spivot(casin, neighsh);
12506         }
12507       }
12508       sbond1(newsh, casout);
12509       sbond1(casin, newsh);
12510     }
12511     if (checkseg.sh != nullptr) {
12512       ssbond(newsh, checkseg);
12513     }
12514     // Connect oldsh <== newsh (for connecting adjacent new subfaces).
12515     //   *parysh and newsh point to the same edge and the same ori.
12516     sbond1(*parysh, newsh);
12517   }
12518 
12519   if (newsh.sh != nullptr) {
12520     // Set a handle for searching.
12521     recentsh = newsh;
12522   }
12523 
12524   // Update the point-to-subface map.
12525   if (pointtype(insertpt) == FREEFACETVERTEX) {
12526     setpoint2sh(insertpt, sencode(newsh));
12527   }
12528 
12529   // Connect adjacent new subfaces together.
12530   for (i = 0; i < caveshbdlist->objects; i++) {
12531     // Get an old subface at edge [a, b].
12532     parysh = (face *) fastlookup(caveshbdlist, i);
12533     spivot(*parysh, newsh); // The new subface [a, b, p].
12534     senextself(newsh); // At edge [b, p].
12535     spivot(newsh, neighsh);
12536     if (neighsh.sh == nullptr) {
12537       // Find the adjacent new subface at edge [b, p].
12538       pb = sdest(*parysh);
12539       neighsh = *parysh;
12540       while (1) {
12541         senextself(neighsh);
12542         spivotself(neighsh);
12543         if (neighsh.sh == nullptr) break;
12544         if (!smarktested(neighsh)) break;
12545         if (sdest(neighsh) != pb) sesymself(neighsh);
12546       }
12547       if (neighsh.sh != nullptr) {
12548         // Now 'neighsh' is a new subface at edge [b, #].
12549         if (sorg(neighsh) != pb) sesymself(neighsh);
12550         senext2self(neighsh); // Go to the open edge [p, b].
12551         sbond(newsh, neighsh);
12552       } else {
12553         // There is no adjacent new face at this side.
12554         assert(loc == OUTSIDE); // SELF_CHECK
12555       }
12556     }
12557     spivot(*parysh, newsh); // The new subface [a, b, p].
12558     senext2self(newsh); // At edge [p, a].
12559     spivot(newsh, neighsh);
12560     if (neighsh.sh == nullptr) {
12561       // Find the adjacent new subface at edge [p, a].
12562       pa = sorg(*parysh);
12563       neighsh = *parysh;
12564       while (1) {
12565         senext2self(neighsh);
12566         spivotself(neighsh);
12567         if (neighsh.sh == nullptr) break;
12568         if (!smarktested(neighsh)) break;
12569         if (sorg(neighsh) != pa) sesymself(neighsh);
12570       }
12571       if (neighsh.sh != nullptr) {
12572         // Now 'neighsh' is a new subface at edge [#, a].
12573         if (sdest(neighsh) != pa) sesymself(neighsh);
12574         senextself(neighsh); // Go to the open edge [a, p].
12575         sbond(newsh, neighsh);
12576       } else {
12577         // There is no adjacent new face at this side.
12578         assert(loc == OUTSIDE); // SELF_CHECK
12579       }
12580     }
12581   }
12582 
12583   if ((loc == ONEDGE) || ((splitseg != nullptr) && (splitseg->sh != nullptr))
12584       || (cavesegshlist->objects > 0l)) {
12585     // An edge is being split. We distinguish two cases:
12586     //   (1) the edge is not on the boundary of the cavity;
12587     //   (2) the edge is on the boundary of the cavity.
12588     // In case (2), the edge is either a segment or a hull edge. There are
12589     //   degenerated new faces in the cavity. They must be removed.
12590     face aseg, bseg, aoutseg, boutseg;
12591 
12592     for (i = 0; i < cavesegshlist->objects; i++) {
12593       // Get the saved old subface.
12594       parysh = (face *) fastlookup(cavesegshlist, i);
12595       // Get a possible new degenerated subface.
12596       spivot(*parysh, cavesh);
12597       if (sapex(cavesh) == insertpt) {
12598         // Found a degenerated new subface, i.e., case (2).
12599         if (cavesegshlist->objects > 1) {
12600           // There are more than one subface share at this edge.
12601           j = (i + 1) % (int) cavesegshlist->objects;
12602           parysh = (face *) fastlookup(cavesegshlist, j);
12603           spivot(*parysh, neighsh);
12604           // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
12605           if (sorg(neighsh) != sorg(cavesh)) {
12606             sesymself(neighsh);
12607             assert(sorg(neighsh) == sorg(cavesh)); // SELF_CHECK
12608           }
12609           assert(sapex(neighsh) == insertpt); // SELF_CHECK
12610           // Connect adjacent faces at two other edges of cavesh and neighsh.
12611           //   As a result, the two degenrated new faces are squessed from the
12612           //   new triangulation of the cavity. Note that the squeezed faces
12613           //   still hold the adjacent informations which will be used in
12614           //   re-connecting subsegments (if they exist).
12615           for (j = 0; j < 2; j++) {
12616             senextself(cavesh);
12617             senextself(neighsh);
12618             spivot(cavesh, newsh);
12619             spivot(neighsh, casout);
12620             sbond1(newsh, casout); // newsh <- casout.
12621           }
12622         } else {
12623           // There is only one subface containing this edge [a,b]. Squeese the
12624           //   degenerated new face [a,b,c] by disconnecting it from its two
12625           //   adjacent subfaces at edges [b,c] and [c,a]. Note that the face
12626           //   [a,b,c] still hold the connection to them.
12627           for (j = 0; j < 2; j++) {
12628             senextself(cavesh);
12629             spivot(cavesh, newsh);
12630             sdissolve(newsh);
12631           }
12632         }
12633         //recentsh = newsh;
12634         // Update the point-to-subface map.
12635         if (pointtype(insertpt) == FREEFACETVERTEX) {
12636           setpoint2sh(insertpt, sencode(newsh));
12637         }
12638       }
12639     }
12640 
12641     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
12642       if (loc != INSTAR) { // if (bowywat < 3) {
12643         smarktest(*splitseg); // Mark it as being processed.
12644       }
12645 
12646       aseg = *splitseg;
12647       pa = sorg(*splitseg);
12648       pb = sdest(*splitseg);
12649 
12650       // Insert the new point p.
12651       makeshellface(subsegs, &aseg);
12652       makeshellface(subsegs, &bseg);
12653 
12654       setshvertices(aseg, pa, insertpt, nullptr);
12655       setshvertices(bseg, insertpt, pb, nullptr);
12656       setshellmark(aseg, shellmark(*splitseg));
12657       setshellmark(bseg, shellmark(*splitseg));
12658       setshelltype(aseg, shelltype(*splitseg));
12659       setshelltype(bseg, shelltype(*splitseg));
12660       if (checkconstraints) {
12661         setareabound(aseg, areabound(*splitseg));
12662         setareabound(bseg, areabound(*splitseg));
12663       }
12664 
12665       // Connect [#, a]<->[a, p].
12666       senext2(*splitseg, boutseg); // Temporarily use boutseg.
12667       spivotself(boutseg);
12668       if (boutseg.sh != nullptr) {
12669         senext2(aseg, aoutseg);
12670         sbond(boutseg, aoutseg);
12671       }
12672       // Connect [p, b]<->[b, #].
12673       senext(*splitseg, aoutseg);
12674       spivotself(aoutseg);
12675       if (aoutseg.sh != nullptr) {
12676         senext(bseg, boutseg);
12677         sbond(boutseg, aoutseg);
12678       }
12679       // Connect [a, p] <-> [p, b].
12680       senext(aseg, aoutseg);
12681       senext2(bseg, boutseg);
12682       sbond(aoutseg, boutseg);
12683 
12684       // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
12685       // Although the degenerated new faces have been squeesed. They still
12686       //   hold the connections to the actual new faces.
12687       for (i = 0; i < cavesegshlist->objects; i++) {
12688         parysh = (face *) fastlookup(cavesegshlist, i);
12689         spivot(*parysh, neighsh);
12690         // neighsh is a degenerated new face.
12691         if (sorg(neighsh) != pa) {
12692           sesymself(neighsh);
12693         }
12694         senext2(neighsh, newsh);
12695         spivotself(newsh); // The edge [p, a] in newsh
12696         ssbond(newsh, aseg);
12697         senext(neighsh, newsh);
12698         spivotself(newsh); // The edge [b, p] in newsh
12699         ssbond(newsh, bseg);
12700       }
12701 
12702 
12703       // Let the point remember the segment it lies on.
12704       if (pointtype(insertpt) == FREESEGVERTEX) {
12705         setpoint2sh(insertpt, sencode(aseg));
12706       }
12707       // Update the point-to-seg map.
12708       if (pointtype(pa) == FREESEGVERTEX) {
12709         setpoint2sh(pa, sencode(aseg));
12710       }
12711       if (pointtype(pb) == FREESEGVERTEX) {
12712         setpoint2sh(pb, sencode(bseg));
12713       }
12714     } // if ((splitseg != nullptr) && (splitseg->sh != nullptr))
12715 
12716     // Delete all degenerated new faces.
12717     for (i = 0; i < cavesegshlist->objects; i++) {
12718       parysh = (face *) fastlookup(cavesegshlist, i);
12719       spivotself(*parysh);
12720       if (sapex(*parysh) == insertpt) {
12721         shellfacedealloc(subfaces, parysh->sh);
12722       }
12723     }
12724     cavesegshlist->restart();
12725 
12726     if ((splitseg != nullptr) && (splitseg->sh != nullptr)) {
12727       // Return the two new subsegments (for further process).
12728       //   Re-use 'cavesegshlist'.
12729       cavesegshlist->newindex((void **) &parysh);
12730       *parysh = aseg;
12731       cavesegshlist->newindex((void **) &parysh);
12732       *parysh = bseg;
12733     }
12734   } // if (loc == ONEDGE)
12735 
12736 
12737   return (int) loc;
12738 }
12739 
12740 ///////////////////////////////////////////////////////////////////////////////
12741 //                                                                           //
12742 // sremovevertex()    Remove a vertex from the surface mesh.                 //
12743 //                                                                           //
12744 // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not nullptr, p is //
12745 // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a   //
12746 // facet vertex, and the origin of 'parentsh' is p.                          //
12747 //                                                                           //
12748 // Within each facet, we first use a sequence of 2-to-2 flips to flip any    //
12749 // edge at p, finally use a 3-to-1 flip to remove p.                         //
12750 //                                                                           //
12751 // All new created subfaces are returned in the global array 'caveshbdlist'. //
12752 // The new segment (when p is on segment) is returned in 'parentseg'.        //
12753 //                                                                           //
12754 // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay-   //
12755 // ness after p is removed.                                                  //
12756 //                                                                           //
12757 ///////////////////////////////////////////////////////////////////////////////
12758 
sremovevertex(point delpt,face * parentsh,face * parentseg,int lawson)12759 int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
12760                               int lawson)
12761 {
12762   face flipfaces[4], spinsh, *parysh;
12763   point pa, pb, pc, pd;
12764   REAL ori1, ori2;
12765   int it, i, j;
12766 
12767   if (parentseg != nullptr) {
12768     // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
12769     //   where 'parentseg' should be [p,b]. Find the segment [a,p].
12770     face startsh, neighsh, nextsh;
12771     face abseg, prevseg, checkseg;
12772     face adjseg1, adjseg2;
12773     face fakesh;
12774     senext2(*parentseg, prevseg);
12775     spivotself(prevseg);
12776     prevseg.shver = 0;
12777     assert(sdest(prevseg) == delpt);
12778     // Restore the original segment [a,b].
12779     pa = sorg(prevseg);
12780     pb = sdest(*parentseg);
12781     if (b->verbose > 2) {
12782       printf("      Remove vertex %d from segment [%d, %d].\n",
12783              pointmark(delpt), pointmark(pa), pointmark(pb));
12784     }
12785     makeshellface(subsegs, &abseg);
12786     setshvertices(abseg, pa, pb, nullptr);
12787     setshellmark(abseg, shellmark(*parentseg));
12788     setshelltype(abseg, shelltype(*parentseg));
12789     if (checkconstraints) {
12790       setareabound(abseg, areabound(*parentseg));
12791     }
12792     // Connect [#, a]<->[a, b].
12793     senext2(prevseg, adjseg1);
12794     spivotself(adjseg1);
12795     if (adjseg1.sh != nullptr) {
12796       adjseg1.shver = 0;
12797       assert(sdest(adjseg1) == pa);
12798       senextself(adjseg1);
12799       senext2(abseg, adjseg2);
12800       sbond(adjseg1, adjseg2);
12801     }
12802     // Connect [a, b]<->[b, #].
12803     senext(*parentseg, adjseg1);
12804     spivotself(adjseg1);
12805     if (adjseg1.sh != nullptr) {
12806       adjseg1.shver = 0;
12807       assert(sorg(adjseg1) == pb);
12808       senext2self(adjseg1);
12809       senext(abseg, adjseg2);
12810       sbond(adjseg1, adjseg2);
12811     }
12812     // Update the point-to-segment map.
12813     setpoint2sh(pa, sencode(abseg));
12814     setpoint2sh(pb, sencode(abseg));
12815 
12816     // Get the faces in face ring at segment [p, b].
12817     //   Re-use array 'caveshlist'.
12818     spivot(*parentseg, *parentsh);
12819     spinsh = *parentsh;
12820     while (1) {
12821       // Save this face in list.
12822       caveshlist->newindex((void **) &parysh);
12823       *parysh = spinsh;
12824       // Go to the next face in the ring.
12825       spivotself(spinsh);
12826       if (spinsh.sh == nullptr) break;
12827       if (spinsh.sh == parentsh->sh) break;
12828     }
12829 
12830     // Create the face ring of the new segment [a,b]. Each face in the ring
12831     //   is [a,b,p] (degenerated!). It will be removed (automatically).
12832     for (i = 0; i < caveshlist->objects; i++) {
12833       parysh = (face *) fastlookup(caveshlist, i);
12834       startsh = *parysh;
12835       if (sorg(startsh) != delpt) {
12836         sesymself(startsh);
12837         assert(sorg(startsh) == delpt);
12838       }
12839       // startsh is [p, b, #1], find the subface [a, p, #2].
12840       neighsh = startsh;
12841       while (1) {
12842         senext2self(neighsh);
12843         sspivot(neighsh, checkseg);
12844         if (checkseg.sh != nullptr) {
12845           // It must be the segment [a, p].
12846           assert(checkseg.sh == prevseg.sh);
12847           break;
12848         }
12849         spivotself(neighsh);
12850         assert(neighsh.sh != nullptr);
12851         if (sorg(neighsh) != delpt) sesymself(neighsh);
12852       }
12853       // Now neighsh is [a, p, #2].
12854       if (neighsh.sh != startsh.sh) {
12855         // Detach the two subsegments [a,p] and [p,b] from subfaces.
12856         ssdissolve(startsh);
12857         ssdissolve(neighsh);
12858         // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
12859         //   new segment [a,b]; (2) connect to the two adjacent subfaces
12860         //   [p,b,#] and [a,p,#].
12861         makeshellface(subfaces, &fakesh);
12862         setshvertices(fakesh, pa, pb, delpt);
12863         setshellmark(fakesh, shellmark(startsh));
12864         // Connect fakesh to the segment [a,b].
12865         ssbond(fakesh, abseg);
12866         // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
12867         senext(fakesh, nextsh);
12868         sbond(nextsh, startsh);
12869         senext2(fakesh, nextsh);
12870         sbond(nextsh, neighsh);
12871         smarktest(fakesh); // Mark it as faked.
12872       } else {
12873         // Special case. There exists already a degenerated face [a,b,p]!
12874         //   There is no need to create a faked subface here.
12875         senext2self(neighsh); // [a,b,p]
12876         assert(sapex(neighsh) == delpt);
12877         // Since we will re-connect the face ring using the faked subfaces.
12878         //   We put the adjacent face of [a,b,p] to the list.
12879         spivot(neighsh, startsh); // The original adjacent subface.
12880         if (sorg(startsh) != pa) sesymself(startsh);
12881         sdissolve(startsh);
12882         // Connect fakesh to the segment [a,b].
12883         ssbond(startsh, abseg);
12884         fakesh = startsh; // Do not mark it!
12885         // Delete the degenerated subface.
12886         shellfacedealloc(subfaces, neighsh.sh);
12887       }
12888       // Save the fakesh in list (for re-creating the face ring).
12889       cavesegshlist->newindex((void **) &parysh);
12890       *parysh = fakesh;
12891     } // i
12892     caveshlist->restart();
12893 
12894     // Re-create the face ring.
12895     if (cavesegshlist->objects > 1) {
12896       for (i = 0; i < cavesegshlist->objects; i++) {
12897         parysh = (face *) fastlookup(cavesegshlist, i);
12898         fakesh = *parysh;
12899         // Get the next face in the ring.
12900         j = (i + 1) % cavesegshlist->objects;
12901         parysh = (face *) fastlookup(cavesegshlist, j);
12902         nextsh = *parysh;
12903         sbond1(fakesh, nextsh);
12904       }
12905     }
12906 
12907     // Delete the two subsegments containing p.
12908     shellfacedealloc(subsegs, parentseg->sh);
12909     shellfacedealloc(subsegs, prevseg.sh);
12910     // Return the new segment.
12911     *parentseg = abseg;
12912   } else {
12913     // p is inside the surface.
12914     if (b->verbose > 2) {
12915       printf("      Remove vertex %d from surface.\n", pointmark(delpt));
12916     }
12917     assert(sorg(*parentsh) == delpt);
12918     // Let 'delpt' be its apex.
12919     senextself(*parentsh);
12920     // For unifying the code, we add parentsh to list.
12921     cavesegshlist->newindex((void **) &parysh);
12922     *parysh = *parentsh;
12923   }
12924 
12925   // Remove the point (p).
12926 
12927   for (it = 0; it < cavesegshlist->objects; it++) {
12928     parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
12929     senextself(*parentsh); // [b,p,a].
12930     spivotself(*parentsh);
12931     if (sorg(*parentsh) != delpt) sesymself(*parentsh);
12932     // now parentsh is [p,b,#].
12933     if (sorg(*parentsh) != delpt) {
12934       // The vertex has already been removed in above special case.
12935       assert(!smarktested(*parentsh));
12936       continue;
12937     }
12938 
12939     while (1) {
12940       // Initialize the flip edge list. Re-use 'caveshlist'.
12941       spinsh = *parentsh; // [p, b, #]
12942       while (1) {
12943         caveshlist->newindex((void **) &parysh);
12944         *parysh = spinsh;
12945         senext2self(spinsh);
12946         spivotself(spinsh);
12947         assert(spinsh.sh != nullptr);
12948         if (spinsh.sh == parentsh->sh) break;
12949         if (sorg(spinsh) != delpt) sesymself(spinsh);
12950         assert(sorg(spinsh) == delpt);
12951       } // while (1)
12952 
12953       if (caveshlist->objects == 3) {
12954         // Delete the point by a 3-to-1 flip.
12955         for (i = 0; i < 3; i++) {
12956           parysh = (face *) fastlookup(caveshlist, i);
12957           flipfaces[i] = *parysh;
12958         }
12959         flip31(flipfaces, lawson);
12960         for (i = 0; i < 3; i++) {
12961           shellfacedealloc(subfaces, flipfaces[i].sh);
12962         }
12963         caveshlist->restart();
12964         // Save the new subface.
12965         caveshbdlist->newindex((void **) &parysh);
12966         *parysh = flipfaces[3];
12967         // The vertex is removed.
12968         break;
12969       }
12970 
12971       // Search an edge to flip.
12972       for (i = 0; i < caveshlist->objects; i++) {
12973         parysh = (face *) fastlookup(caveshlist, i);
12974         flipfaces[0] = *parysh;
12975         spivot(flipfaces[0], flipfaces[1]);
12976         if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
12977           sesymself(flipfaces[1]);
12978         // Skip this edge if it belongs to a faked subface.
12979         if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
12980           pa = sorg(flipfaces[0]);
12981           pb = sdest(flipfaces[0]);
12982           pc = sapex(flipfaces[0]);
12983           pd = sapex(flipfaces[1]);
12984           calculateabovepoint4(pa, pb, pc, pd);
12985           // Check if a 2-to-2 flip is possible.
12986           ori1 = orient3d(pc, pd, dummypoint, pa);
12987           ori2 = orient3d(pc, pd, dummypoint, pb);
12988           if (ori1 * ori2 < 0) {
12989             // A 2-to-2 flip is found.
12990             flip22(flipfaces, lawson, 0);
12991             // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
12992             //   changed. The 'flipfaces[1]' contains p as its apex.
12993             senext2(flipfaces[1], *parentsh);
12994             // Save the new subface.
12995             caveshbdlist->newindex((void **) &parysh);
12996             *parysh = flipfaces[0];
12997             break;
12998           }
12999         } //
13000       } // i
13001 
13002       if (i == caveshlist->objects) {
13003         // This can happen only if there are 4 edges at p, and they are
13004         //   orthogonal to each other, see Fig. 2010-11-01.
13005         assert(caveshlist->objects == 4);
13006         // Do a flip22 and a flip31 to remove p.
13007         parysh = (face *) fastlookup(caveshlist, 0);
13008         flipfaces[0] = *parysh;
13009         spivot(flipfaces[0], flipfaces[1]);
13010         if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
13011           sesymself(flipfaces[1]);
13012         }
13013         flip22(flipfaces, lawson, 0);
13014         senext2(flipfaces[1], *parentsh);
13015         // Save the new subface.
13016         caveshbdlist->newindex((void **) &parysh);
13017         *parysh = flipfaces[0];
13018       }
13019 
13020       // The edge list at p are changed.
13021       caveshlist->restart();
13022     } // while (1)
13023 
13024   } // it
13025 
13026   cavesegshlist->restart();
13027 
13028   if (b->verbose > 2) {
13029     printf("      Created %ld new subfaces.\n", caveshbdlist->objects);
13030   }
13031 
13032 
13033   if (lawson) {
13034     lawsonflip();
13035   }
13036 
13037   return 0;
13038 }
13039 
13040 ///////////////////////////////////////////////////////////////////////////////
13041 //                                                                           //
13042 // slocate()    Locate a point in a surface triangulation.                   //
13043 //                                                                           //
13044 // Staring the search from 'searchsh'(it should not be nullptr). Perform a line //
13045 // walk search for a subface containing the point (p).                       //
13046 //                                                                           //
13047 // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies     //
13048 // above the 'searchsh' in its current orientation. The test if c is CCW to  //
13049 // the line a->b can be done by the test if c is below the oriented plane    //
13050 // a->b->dummypoint.                                                         //
13051 //                                                                           //
13052 // If 'cflag' is not TRUE, the triangulation may not be convex.  Stop search //
13053 // when a segment is met and return OUTSIDE.                                 //
13054 //                                                                           //
13055 // If 'rflag' (rounding) is set, after the location of the point is found,   //
13056 // either ONEDGE or ONFACE, round the result using an epsilon.               //
13057 //                                                                           //
13058 // The returned value inducates the following cases:                         //
13059 //   - ONVERTEX, p is the origin of 'searchsh'.                              //
13060 //   - ONEDGE, p lies on the edge of 'searchsh'.                             //
13061 //   - ONFACE, p lies in the interior of 'searchsh'.                         //
13062 //   - OUTSIDE, p lies outside of the triangulation, p is on the left-hand   //
13063 //     side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW.      //
13064 //                                                                           //
13065 ///////////////////////////////////////////////////////////////////////////////
13066 
slocate(point searchpt,face * searchsh,int aflag,int cflag,int rflag)13067 enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
13068   face* searchsh, int aflag, int cflag, int rflag)
13069 {
13070   face neighsh;
13071   point pa, pb, pc;
13072   enum locateresult loc;
13073   enum {MOVE_BC, MOVE_CA} nextmove;
13074   REAL ori, ori_bc, ori_ca;
13075   int i;
13076 
13077   pa = sorg(*searchsh);
13078   pb = sdest(*searchsh);
13079   pc = sapex(*searchsh);
13080 
13081   if (!aflag) {
13082     // No above point is given. Calculate an above point for this facet.
13083     calculateabovepoint4(pa, pb, pc, searchpt);
13084   }
13085 
13086   // 'dummypoint' is given. Make sure it is above [a,b,c]
13087   ori = orient3d(pa, pb, pc, dummypoint);
13088   assert(ori != 0); // SELF_CHECK
13089   if (ori > 0) {
13090     sesymself(*searchsh); // Reverse the face orientation.
13091   }
13092 
13093   // Find an edge of the face s.t. p lies on its right-hand side (CCW).
13094   for (i = 0; i < 3; i++) {
13095     pa = sorg(*searchsh);
13096     pb = sdest(*searchsh);
13097     ori = orient3d(pa, pb, dummypoint, searchpt);
13098     if (ori > 0) break;
13099     senextself(*searchsh);
13100   }
13101   assert(i < 3); // SELF_CHECK
13102 
13103   pc = sapex(*searchsh);
13104 
13105   if (pc == searchpt) {
13106     senext2self(*searchsh);
13107     return ONVERTEX;
13108   }
13109 
13110   while (1) {
13111 
13112     ori_bc = orient3d(pb, pc, dummypoint, searchpt);
13113     ori_ca = orient3d(pc, pa, dummypoint, searchpt);
13114 
13115     if (ori_bc < 0) {
13116       if (ori_ca < 0) { // (--)
13117         // Any of the edges is a viable move.
13118         if (randomnation(2)) {
13119           nextmove = MOVE_CA;
13120         } else {
13121           nextmove = MOVE_BC;
13122         }
13123       } else { // (-#)
13124         // Edge [b, c] is viable.
13125         nextmove = MOVE_BC;
13126       }
13127     } else {
13128       if (ori_ca < 0) { // (#-)
13129         // Edge [c, a] is viable.
13130         nextmove = MOVE_CA;
13131       } else {
13132         if (ori_bc > 0) {
13133           if (ori_ca > 0) { // (++)
13134             loc = ONFACE;  // Inside [a, b, c].
13135             break;
13136           } else { // (+0)
13137             senext2self(*searchsh); // On edge [c, a].
13138             loc = ONEDGE;
13139             break;
13140           }
13141         } else { // ori_bc == 0
13142           if (ori_ca > 0) { // (0+)
13143             senextself(*searchsh); // On edge [b, c].
13144             loc = ONEDGE;
13145             break;
13146           } else { // (00)
13147             // p is coincident with vertex c.
13148             senext2self(*searchsh);
13149             return ONVERTEX;
13150           }
13151         }
13152       }
13153     }
13154 
13155     // Move to the next face.
13156     if (nextmove == MOVE_BC) {
13157       senextself(*searchsh);
13158     } else {
13159       senext2self(*searchsh);
13160     }
13161     if (!cflag) {
13162       // NON-convex case. Check if we will cross a boundary.
13163       if (isshsubseg(*searchsh)) {
13164         return ENCSEGMENT;
13165       }
13166     }
13167     spivot(*searchsh, neighsh);
13168     if (neighsh.sh == nullptr) {
13169       return OUTSIDE; // A hull edge.
13170     }
13171     // Adjust the edge orientation.
13172     if (sorg(neighsh) != sdest(*searchsh)) {
13173       sesymself(neighsh);
13174     }
13175     assert(sorg(neighsh) == sdest(*searchsh)); // SELF_CHECK
13176 
13177     // Update the newly discovered face and its endpoints.
13178     *searchsh = neighsh;
13179     pa = sorg(*searchsh);
13180     pb = sdest(*searchsh);
13181     pc = sapex(*searchsh);
13182 
13183     if (pc == searchpt) {
13184       senext2self(*searchsh);
13185       return ONVERTEX;
13186     }
13187 
13188   } // while (1)
13189 
13190   // assert(loc == ONFACE || loc == ONEDGE);
13191 
13192 
13193   if (rflag) {
13194     // Round the locate result before return.
13195     REAL n[3], area_abc, area_abp, area_bcp, area_cap;
13196 
13197     pa = sorg(*searchsh);
13198     pb = sdest(*searchsh);
13199     pc = sapex(*searchsh);
13200 
13201     facenormal(pa, pb, pc, n, 1, nullptr);
13202     area_abc = sqrt(dot(n, n));
13203 
13204     facenormal(pb, pc, searchpt, n, 1, nullptr);
13205     area_bcp = sqrt(dot(n, n));
13206     if ((area_bcp / area_abc) < b->epsilon) {
13207       area_bcp = 0; // Rounding.
13208     }
13209 
13210     facenormal(pc, pa, searchpt, n, 1, nullptr);
13211     area_cap = sqrt(dot(n, n));
13212     if ((area_cap / area_abc) < b->epsilon) {
13213       area_cap = 0; // Rounding
13214     }
13215 
13216     if ((loc == ONFACE) || (loc == OUTSIDE)) {
13217       facenormal(pa, pb, searchpt, n, 1, nullptr);
13218       area_abp = sqrt(dot(n, n));
13219       if ((area_abp / area_abc) < b->epsilon) {
13220         area_abp = 0; // Rounding
13221       }
13222     } else { // loc == ONEDGE
13223       area_abp = 0;
13224     }
13225 
13226     if (area_abp == 0) {
13227       if (area_bcp == 0) {
13228         assert(area_cap != 0);
13229         senextself(*searchsh);
13230         loc = ONVERTEX; // p is close to b.
13231       } else {
13232         if (area_cap == 0) {
13233           loc = ONVERTEX; // p is close to a.
13234         } else {
13235           loc = ONEDGE; // p is on edge [a,b].
13236         }
13237       }
13238     } else if (area_bcp == 0) {
13239       if (area_cap == 0) {
13240         senext2self(*searchsh);
13241         loc = ONVERTEX; // p is close to c.
13242       } else {
13243         senextself(*searchsh);
13244         loc = ONEDGE; // p is on edge [b,c].
13245       }
13246     } else if (area_cap == 0) {
13247       senext2self(*searchsh);
13248       loc = ONEDGE; // p is on edge [c,a].
13249     } else {
13250       loc = ONFACE; // p is on face [a,b,c].
13251     }
13252   } // if (rflag)
13253 
13254   return loc;
13255 }
13256 
13257 ///////////////////////////////////////////////////////////////////////////////
13258 //                                                                           //
13259 // sscoutsegment()    Look for a segment in surface triangulation.           //
13260 //                                                                           //
13261 // The segment is given by the origin of 'searchsh' and 'endpt'.  Assume the //
13262 // orientation of 'searchsh' is CCW w.r.t. the above point.                  //
13263 //                                                                           //
13264 // If an edge in T is found matching this segment, the segment is "locaked"  //
13265 // in T at the edge.  Otherwise, flip the first edge in T that the segment   //
13266 // crosses. Continue the search from the flipped face.                       //
13267 //                                                                           //
13268 ///////////////////////////////////////////////////////////////////////////////
13269 
sscoutsegment(face * searchsh,point endpt)13270 enum tetgenmesh::interresult tetgenmesh::sscoutsegment(face *searchsh,
13271   point endpt)
13272 {
13273   face flipshs[2], neighsh;
13274   face newseg;
13275   point startpt, pa, pb, pc, pd;
13276   enum interresult dir;
13277   enum {MOVE_AB, MOVE_CA} nextmove;
13278   REAL ori_ab, ori_ca;
13279 
13280   // The origin of 'searchsh' is fixed.
13281   startpt = sorg(*searchsh); // pa = startpt;
13282   nextmove = MOVE_AB; // Avoid compiler warning.
13283 
13284   if (b->verbose > 2) {
13285     printf("      Scout segment (%d, %d).\n", pointmark(startpt),
13286            pointmark(endpt));
13287   }
13288 
13289   // Search an edge in 'searchsh' on the path of this segment.
13290   while (1) {
13291 
13292     pb = sdest(*searchsh);
13293     if (pb == endpt) {
13294       dir = SHAREEDGE; // Found!
13295       break;
13296     }
13297 
13298     pc = sapex(*searchsh);
13299     if (pc == endpt) {
13300       senext2self(*searchsh);
13301       sesymself(*searchsh);
13302       dir = SHAREEDGE; // Found!
13303       break;
13304     }
13305 
13306     ori_ab = orient3d(startpt, pb, dummypoint, endpt);
13307     ori_ca = orient3d(pc, startpt, dummypoint, endpt);
13308 
13309     if (ori_ab < 0) {
13310       if (ori_ca < 0) { // (--)
13311         // Both sides are viable moves.
13312         if (randomnation(2)) {
13313           nextmove = MOVE_CA;
13314         } else {
13315           nextmove = MOVE_AB;
13316         }
13317       } else { // (-#)
13318         nextmove = MOVE_AB;
13319       }
13320     } else {
13321       if (ori_ca < 0) { // (#-)
13322         nextmove = MOVE_CA;
13323       } else {
13324         if (ori_ab > 0) {
13325           if (ori_ca > 0) { // (++)
13326             // The segment intersects with edge [b, c].
13327             dir = ACROSSEDGE;
13328             break;
13329           } else { // (+0)
13330             // The segment collinear with edge [c, a].
13331             senext2self(*searchsh);
13332             sesymself(*searchsh);
13333             dir = ACROSSVERT;
13334             break;
13335           }
13336         } else {
13337           if (ori_ca > 0) { // (0+)
13338             // The segment collinear with edge [a, b].
13339             dir = ACROSSVERT;
13340             break;
13341           } else { // (00)
13342             // startpt == endpt. Not possible.
13343             assert(0); // SELF_CHECK
13344           }
13345         }
13346       }
13347     }
13348 
13349     // Move 'searchsh' to the next face, keep the origin unchanged.
13350     if (nextmove == MOVE_AB) {
13351       spivot(*searchsh, neighsh);
13352       if (sorg(neighsh) != pb) sesymself(neighsh);
13353       senext(neighsh, *searchsh);
13354     } else {
13355       senext2(*searchsh, neighsh);
13356       spivotself(neighsh);
13357       if (sdest(neighsh) != pc) sesymself(neighsh);
13358       *searchsh = neighsh;
13359     }
13360     assert(sorg(*searchsh) == startpt); // SELF_CHECK
13361 
13362   } // while
13363 
13364   if (dir == SHAREEDGE) {
13365     // Insert the segment into the triangulation.
13366     makeshellface(subsegs, &newseg);
13367     setshvertices(newseg, startpt, endpt, nullptr);
13368     // Set the default segment marker.
13369     setshellmark(newseg, 1);
13370     ssbond(*searchsh, newseg);
13371     spivot(*searchsh, neighsh);
13372     if (neighsh.sh != nullptr) {
13373       ssbond(neighsh, newseg);
13374     }
13375     return dir;
13376   }
13377 
13378   if (dir == ACROSSVERT) {
13379     // A point is found collinear with this segment.
13380     return dir;
13381   }
13382 
13383   if (dir == ACROSSEDGE) {
13384     // Edge [b, c] intersects with the segment.
13385     senext(*searchsh, flipshs[0]);
13386     if (isshsubseg(flipshs[0])) {
13387       printf("Error:  Invalid PLC.\n");
13388       pb = sorg(flipshs[0]);
13389       pc = sdest(flipshs[0]);
13390       printf("  Two segments (%d, %d) and (%d, %d) intersect.\n",
13391         pointmark(startpt), pointmark(endpt), pointmark(pb), pointmark(pc));
13392       terminatetetgen(3);
13393     }
13394     // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
13395     spivot(flipshs[0], flipshs[1]);
13396     assert(flipshs[1].sh != nullptr); // SELF_CHECK
13397     if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
13398     flip22(flipshs, 1, 0);
13399     // The flip may create an invered triangle, check it.
13400     pa = sapex(flipshs[1]);
13401     pb = sapex(flipshs[0]);
13402     pc = sorg(flipshs[0]);
13403     pd = sdest(flipshs[0]);
13404     // Check if pa and pb are on the different sides of [pc, pd].
13405     // Re-use ori_ab, ori_ca for the tests.
13406     ori_ab = orient3d(pc, pd, dummypoint, pb);
13407     ori_ca = orient3d(pd, pc, dummypoint, pa);
13408     //assert(ori_ab * ori_ca != 0); // SELF_CHECK
13409     if (ori_ab < 0) {
13410       flipshpush(&(flipshs[0]));  // push it to 'flipstack'
13411     } else if (ori_ca < 0) {
13412       flipshpush(&(flipshs[1])); // // push it to 'flipstack'
13413     }
13414     // Set 'searchsh' s.t. its origin is 'startpt'.
13415     *searchsh = flipshs[0];
13416     assert(sorg(*searchsh) == startpt);
13417   }
13418 
13419   return sscoutsegment(searchsh, endpt);
13420 }
13421 
13422 ///////////////////////////////////////////////////////////////////////////////
13423 //                                                                           //
13424 // scarveholes()    Remove triangles not in the facet.                       //
13425 //                                                                           //
13426 // This routine re-uses the two global arrays: caveshlist and caveshbdlist.  //
13427 //                                                                           //
13428 ///////////////////////////////////////////////////////////////////////////////
13429 
scarveholes(int holes,REAL * holelist)13430 void tetgenmesh::scarveholes(int holes, REAL* holelist)
13431 {
13432   face *parysh, searchsh, neighsh;
13433   enum locateresult loc;
13434   int i, j;
13435 
13436   // Get all triangles. Infect unprotected convex hull triangles.
13437   smarktest(recentsh);
13438   caveshlist->newindex((void **) &parysh);
13439   *parysh = recentsh;
13440   for (i = 0; i < caveshlist->objects; i++) {
13441     parysh = (face *) fastlookup(caveshlist, i);
13442     searchsh = *parysh;
13443     searchsh.shver = 0;
13444     for (j = 0; j < 3; j++) {
13445       spivot(searchsh, neighsh);
13446       // Is this side on the convex hull?
13447       if (neighsh.sh != nullptr) {
13448         if (!smarktested(neighsh)) {
13449           smarktest(neighsh);
13450           caveshlist->newindex((void **) &parysh);
13451           *parysh = neighsh;
13452         }
13453       } else {
13454         // A hull side. Check if it is protected by a segment.
13455         if (!isshsubseg(searchsh)) {
13456           // Not protected. Save this face.
13457           if (!sinfected(searchsh)) {
13458             sinfect(searchsh);
13459             caveshbdlist->newindex((void **) &parysh);
13460             *parysh = searchsh;
13461           }
13462         }
13463       }
13464       senextself(searchsh);
13465     }
13466   }
13467 
13468   // Infect the triangles in the holes.
13469   for (i = 0; i < 3 * holes; i += 3) {
13470     searchsh = recentsh;
13471     loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
13472     if (loc != OUTSIDE) {
13473       sinfect(searchsh);
13474       caveshbdlist->newindex((void **) &parysh);
13475       *parysh = searchsh;
13476     }
13477   }
13478 
13479   // Find and infect all exterior triangles.
13480   for (i = 0; i < caveshbdlist->objects; i++) {
13481     parysh = (face *) fastlookup(caveshbdlist, i);
13482     searchsh = *parysh;
13483     searchsh.shver = 0;
13484     for (j = 0; j < 3; j++) {
13485       spivot(searchsh, neighsh);
13486       if (neighsh.sh != nullptr) {
13487         if (!isshsubseg(searchsh)) {
13488           if (!sinfected(neighsh)) {
13489             sinfect(neighsh);
13490             caveshbdlist->newindex((void **) &parysh);
13491             *parysh = neighsh;
13492           }
13493         } else {
13494           sdissolve(neighsh); // Disconnect a protected face.
13495         }
13496       }
13497       senextself(searchsh);
13498     }
13499   }
13500 
13501   // Delete exterior triangles, unmark interior triangles.
13502   for (i = 0; i < caveshlist->objects; i++) {
13503     parysh = (face *) fastlookup(caveshlist, i);
13504     if (sinfected(*parysh)) {
13505       shellfacedealloc(subfaces, parysh->sh);
13506     } else {
13507       sunmarktest(*parysh);
13508     }
13509   }
13510 
13511   caveshlist->restart();
13512   caveshbdlist->restart();
13513 }
13514 
13515 ///////////////////////////////////////////////////////////////////////////////
13516 //                                                                           //
13517 // triangulate()    Create a CDT for the facet.                              //
13518 //                                                                           //
13519 // All vertices of the triangulation have type FACETVERTEX.  The actual type //
13520 // of boundary vertices are set by the routine unifysements().               //
13521 //                                                                           //
13522 ///////////////////////////////////////////////////////////////////////////////
13523 
triangulate(int shmark,arraypool * ptlist,arraypool * conlist,int holes,REAL * holelist)13524 void tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
13525                              int holes, REAL* holelist)
13526 {
13527   face searchsh, newsh, *parysh;
13528   face newseg;
13529   point pa, pb, pc, *ppt, *cons;
13530   int iloc;
13531   int i, j;
13532 
13533   if (b->verbose > 2) {
13534     printf("      f%d:  %ld vertices, %ld segments", shmark, ptlist->objects,
13535            conlist->objects);
13536     if (holes > 0) {
13537       printf(", %d holes", holes);
13538     }
13539     printf(".\n");
13540   }
13541 
13542   if (ptlist->objects < 2l) {
13543     // Not a segment or a facet.
13544     return;
13545   }
13546 
13547   if (ptlist->objects == 2l) {
13548     pa = * (point *) fastlookup(ptlist, 0);
13549     pb = * (point *) fastlookup(ptlist, 1);
13550     if (distance(pa, pb) > 0) {
13551       // It is a single segment.
13552       makeshellface(subsegs, &newseg);
13553       setshvertices(newseg, pa, pb, nullptr);
13554       // Set the default segment marker '1'.
13555       setshellmark(newseg, 1);
13556     }
13557     if (pointtype(pa) == VOLVERTEX) {
13558       setpointtype(pa, FACETVERTEX);
13559     }
13560     if (pointtype(pb) == VOLVERTEX) {
13561       setpointtype(pb, FACETVERTEX);
13562     }
13563     return;
13564   }
13565 
13566 
13567   // Calulcate an above point of this facet.
13568   if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
13569     return; // The point set is degenerate.
13570   }
13571 
13572   // Create an initial triangulation.
13573   makeshellface(subfaces, &newsh);
13574   setshvertices(newsh, pa, pb, pc);
13575   setshellmark(newsh, shmark);
13576   recentsh = newsh;
13577 
13578   if (pointtype(pa) == VOLVERTEX) {
13579     setpointtype(pa, FACETVERTEX);
13580   }
13581   if (pointtype(pb) == VOLVERTEX) {
13582     setpointtype(pb, FACETVERTEX);
13583   }
13584   if (pointtype(pc) == VOLVERTEX) {
13585     setpointtype(pc, FACETVERTEX);
13586   }
13587 
13588   // Are there area constraints?
13589   if (b->quality && (in->facetconstraintlist != (REAL *) nullptr)) {
13590     int idx, fmarker;
13591     REAL area;
13592     idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker.
13593     for (i = 0; i < in->numberoffacetconstraints; i++) {
13594       fmarker = (int) in->facetconstraintlist[i * 2];
13595       if (fmarker == idx) {
13596         area = in->facetconstraintlist[i * 2 + 1];
13597         setareabound(newsh, area);
13598         break;
13599       }
13600     }
13601   }
13602 
13603   if (ptlist->objects == 3) {
13604     // The triangulation only has one element.
13605     for (i = 0; i < 3; i++) {
13606       makeshellface(subsegs, &newseg);
13607       setshvertices(newseg, sorg(newsh), sdest(newsh), nullptr);
13608       // Set the default segment marker '1'.
13609       setshellmark(newseg, 1);
13610       ssbond(newsh, newseg);
13611       senextself(newsh);
13612     }
13613     return;
13614   }
13615 
13616   // Incrementally build the triangulation.
13617   pinfect(pa);
13618   pinfect(pb);
13619   pinfect(pc);
13620   for (i = 0; i < ptlist->objects; i++) {
13621     ppt = (point *) fastlookup(ptlist, i);
13622     if (!pinfected(*ppt)) {
13623       searchsh = recentsh; // Start from 'recentsh'.
13624       iloc = (int) OUTSIDE;
13625       // Insert the vertex. Use Bowyer-Watson algo. Round the location.
13626       iloc = sinsertvertex(*ppt, &searchsh, nullptr, iloc, 1, 1);
13627       if (pointtype(*ppt) == VOLVERTEX) {
13628         setpointtype(*ppt, FACETVERTEX);
13629       }
13630       // Delete all removed subfaces.
13631       for (j = 0; j < caveshlist->objects; j++) {
13632         parysh = (face *) fastlookup(caveshlist, j);
13633         shellfacedealloc(subfaces, parysh->sh);
13634       }
13635       // Clear the global lists.
13636       caveshbdlist->restart();
13637       caveshlist->restart();
13638       cavesegshlist->restart();
13639     } else {
13640       puninfect(*ppt); // This point has inserted.
13641     }
13642   }
13643 
13644   // Insert the segments.
13645   for (i = 0; i < conlist->objects; i++) {
13646     cons = (point *) fastlookup(conlist, i);
13647     searchsh = recentsh;
13648     iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
13649     if (iloc != (enum locateresult) ONVERTEX) {
13650       // Not found due to roundoff errors. Do a brute-force search.
13651       subfaces->traversalinit();
13652       searchsh.sh = shellfacetraverse(subfaces);
13653       while (searchsh.sh != nullptr) {
13654         // Only search the subface in the same facet.
13655         if (shellmark(searchsh) == shmark) {
13656           if ((point) searchsh.sh[3] == cons[0]) {
13657             searchsh.shver = 0; break;
13658           } else if ((point) searchsh.sh[4] == cons[0]) {
13659             searchsh.shver = 2; break;
13660           } else if ((point) searchsh.sh[5] == cons[0]) {
13661             searchsh.shver = 4; break;
13662           }
13663         }
13664         searchsh.sh = shellfacetraverse(subfaces);
13665           }
13666       assert(searchsh.sh != nullptr);
13667     }
13668     // Recover the segment. Some edges may be flipped.
13669     sscoutsegment(&searchsh, cons[1]);
13670     if (flipstack != nullptr) {
13671       // Recover locally Delaunay edges.
13672       lawsonflip();
13673     }
13674   }
13675 
13676   // Remove exterior and hole triangles.
13677   scarveholes(holes, holelist);
13678 }
13679 
13680 ///////////////////////////////////////////////////////////////////////////////
13681 //                                                                           //
13682 // unifysubfaces()    Unify two identical subfaces.                          //
13683 //                                                                           //
13684 // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b].  //
13685 // If c = d, then f1 and f2 are identical. Otherwise, these two subfaces     //
13686 // intersect, and the mesher is stopped.                                     //
13687 //                                                                           //
13688 // If the two subfaces are indentical, we try to replace f2 by f1, i.e, all  //
13689 // neighbors of f2 are re-connected to f1.                                   //
13690 //                                                                           //
13691 ///////////////////////////////////////////////////////////////////////////////
13692 
unifysubfaces(face * f1,face * f2)13693 void tetgenmesh::unifysubfaces(face *f1, face *f2)
13694 {
13695   if (b->psc) {
13696     // In this case, it is possible that two subfaces are identical.
13697     // While they must belong to two differnet surfaces.
13698     return;
13699   }
13700 
13701   point pa, pb, pc, pd;
13702 
13703   pa = sorg(*f1);
13704   pb = sdest(*f1);
13705   pc = sapex(*f1);
13706   pd = sapex(*f2);
13707 
13708   if (pc != pd) {
13709     printf("Found two facets intersect each other.\n");
13710     printf("  1st: [%d, %d, %d] #%d\n",
13711                pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13712     printf("  2nd: [%d, %d, %d] #%d\n",
13713                pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13714     // [Bruno]
13715     // Keep track of the facets that intersect.
13716     in->isectfaces.insert(shellmark(*f1));
13717     in->isectfaces.insert(shellmark(*f2));
13718     terminatetetgen(3);
13719   } else {
13720     printf("Found two duplicated facets.\n");
13721     printf("  1st: [%d, %d, %d] #%d\n",
13722                pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
13723     printf("  2nd: [%d, %d, %d] #%d\n",
13724                pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
13725     // [Bruno]
13726     // Keep track of the facets that intersect.
13727     in->isectfaces.insert(shellmark(*f1));
13728     in->isectfaces.insert(shellmark(*f2));
13729     terminatetetgen(3);
13730   }
13731 
13732 }
13733 
13734 ///////////////////////////////////////////////////////////////////////////////
13735 //                                                                           //
13736 // unifysegments()    Remove redundant segments and create face links.       //
13737 //                                                                           //
13738 // After this routine, although segments are unique, but some of them may be //
13739 // removed later by mergefacet().  All vertices still have type FACETVERTEX. //
13740 //                                                                           //
13741 ///////////////////////////////////////////////////////////////////////////////
13742 
unifysegments()13743 void tetgenmesh::unifysegments()
13744 {
13745   badface *facelink = nullptr, *newlinkitem, *f1, *f2;
13746   face *facperverlist, sface;
13747   face subsegloop, testseg;
13748   point torg, tdest;
13749   REAL ori1, ori2, ori3;
13750   REAL n1[3], n2[3];
13751   int *idx2faclist;
13752   int idx, k, m;
13753 
13754   if (b->verbose > 1) {
13755     printf("  Unifying segments.\n");
13756   }
13757 
13758   // Create a mapping from vertices to subfaces.
13759   makepoint2submap(subfaces, idx2faclist, facperverlist);
13760 
13761   if (b->psc) {
13762     face sface1;
13763     face seg, seg1;
13764     int fmarker, fmarker1;
13765     // First only connect subfaces which belong to the same surfaces.
13766     subsegloop.shver = 0;
13767     subsegs->traversalinit();
13768     subsegloop.sh = shellfacetraverse(subsegs);
13769     while (subsegloop.sh != (shellface *) nullptr) {
13770       torg = sorg(subsegloop);
13771       tdest = sdest(subsegloop);
13772 
13773       idx = pointmark(torg) - in->firstnumber;
13774       for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13775         sface = facperverlist[k];
13776         // The face may be deleted if it is a duplicated face.
13777         if (sface.sh[3] == nullptr) continue;
13778         // Search the edge torg->tdest.
13779         assert(sorg(sface) == torg); // SELF_CHECK
13780         if (sdest(sface) != tdest) {
13781           senext2self(sface);
13782           sesymself(sface);
13783         }
13784         if (sdest(sface) != tdest) continue;
13785 
13786         sspivot(sface, seg);
13787         if (seg.sh == nullptr) continue;
13788         // assert(seg.sh != nullptr); It may or may not be subsegloop.
13789 
13790         // Find the adjacent subface on the same facet.
13791         fmarker = in->facetmarkerlist[shellmark(sface) - 1];
13792         sface1.sh = nullptr;
13793         k++;
13794         for (; k < idx2faclist[idx + 1]; k++) {
13795           sface1 = facperverlist[k];
13796           // The face may be deleted if it is a duplicated face.
13797           if (sface1.sh[3] == nullptr) continue;
13798           // Search the edge torg->tdest.
13799           assert(sorg(sface1) == torg); // SELF_CHECK
13800           if (sdest(sface1) != tdest) {
13801             senext2self(sface1);
13802             sesymself(sface1);
13803           }
13804           if (sdest(sface1) != tdest) continue;
13805           // Found a subface sharing at the same edge.
13806           fmarker1 = in->facetmarkerlist[shellmark(sface1) - 1];
13807           if (fmarker1 == fmarker) {
13808             // Found a pair of adjacent subfaces. Connect them.
13809             // Delete a redundent segment.
13810             sspivot(sface1, seg1);
13811             assert(seg1.sh != nullptr); // SELF_CHECK
13812             shellfacedealloc(subsegs, seg.sh);
13813             shellfacedealloc(subsegs, seg1.sh);
13814             ssdissolve(sface);
13815             ssdissolve(sface1);
13816             // Connect them.
13817             sbond(sface, sface1);
13818             // Set Steiner point -to- subface map.
13819             if (pointtype(torg) == FREEFACETVERTEX) {
13820               setpoint2sh(torg, sencode(sface));
13821             }
13822             if (pointtype(tdest) == FREEFACETVERTEX) {
13823               setpoint2sh(tdest, sencode(sface));
13824             }
13825             break;
13826           }
13827         }
13828         break;
13829       }
13830       subsegloop.sh = shellfacetraverse(subsegs);
13831     }
13832   } // if (b->psc)
13833 
13834   subsegloop.shver = 0;
13835   subsegs->traversalinit();
13836   subsegloop.sh = shellfacetraverse(subsegs);
13837   while (subsegloop.sh != (shellface *) nullptr) {
13838     torg = sorg(subsegloop);
13839     tdest = sdest(subsegloop);
13840 
13841     idx = pointmark(torg) - in->firstnumber;
13842     // Loop through the set of subfaces containing 'torg'.  Get all the
13843     //   subfaces containing the edge (torg, tdest). Save and order them
13844     //   in 'sfacelist', the ordering is defined by the right-hand rule
13845     //   with thumb points from torg to tdest.
13846     for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
13847       sface = facperverlist[k];
13848       // The face may be deleted if it is a duplicated face.
13849       if (sface.sh[3] == nullptr) continue;
13850       // Search the edge torg->tdest.
13851       assert(sorg(sface) == torg); // SELF_CHECK
13852       if (sdest(sface) != tdest) {
13853         senext2self(sface);
13854         sesymself(sface);
13855       }
13856       if (sdest(sface) != tdest) continue;
13857 
13858       // Save the face f in facelink.
13859       if (flippool->items >= 2) {
13860         f1 = facelink;
13861         for (m = 0; m < flippool->items - 1; m++) {
13862           f2 = f1->nextitem;
13863           ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
13864           ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13865           if (ori1 > 0) {
13866             // apex(f2) is below f1.
13867             if (ori2 > 0) {
13868               // apex(f) is below f1 (see Fig.1).
13869               ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13870               if (ori3 > 0) {
13871                 // apex(f) is below f2, insert it.
13872                 break;
13873               } else if (ori3 < 0) {
13874                 // apex(f) is above f2, continue.
13875               } else { // ori3 == 0;
13876                 // f is coplanar and codirection with f2.
13877                 unifysubfaces(&(f2->ss), &sface);
13878                 break;
13879               }
13880             } else if (ori2 < 0) {
13881               // apex(f) is above f1 below f2, inset it (see Fig. 2).
13882               break;
13883             } else { // ori2 == 0;
13884               // apex(f) is coplanar with f1 (see Fig. 5).
13885               ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13886               if (ori3 > 0) {
13887                 // apex(f) is below f2, insert it.
13888                 break;
13889               } else {
13890                 // f is coplanar and codirection with f1.
13891                 unifysubfaces(&(f1->ss), &sface);
13892                 break;
13893               }
13894             }
13895           } else if (ori1 < 0) {
13896             // apex(f2) is above f1.
13897             if (ori2 > 0) {
13898               // apex(f) is below f1, continue (see Fig. 3).
13899             } else if (ori2 < 0) {
13900               // apex(f) is above f1 (see Fig.4).
13901               ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13902               if (ori3 > 0) {
13903                 // apex(f) is below f2, insert it.
13904                 break;
13905               } else if (ori3 < 0) {
13906                 // apex(f) is above f2, continue.
13907               } else { // ori3 == 0;
13908                 // f is coplanar and codirection with f2.
13909                 unifysubfaces(&(f2->ss), &sface);
13910                 break;
13911               }
13912             } else { // ori2 == 0;
13913               // f is coplanar and with f1 (see Fig. 6).
13914               ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
13915               if (ori3 > 0) {
13916                 // f is also codirection with f1.
13917                 unifysubfaces(&(f1->ss), &sface);
13918                 break;
13919               } else {
13920                 // f is above f2, continue.
13921               }
13922             }
13923           } else { // ori1 == 0;
13924             // apex(f2) is coplanar with f1. By assumption, f1 is not
13925             //   coplanar and codirection with f2.
13926             if (ori2 > 0) {
13927               // apex(f) is below f1, continue (see Fig. 7).
13928             } else if (ori2 < 0) {
13929               // apex(f) is above f1, insert it (see Fig. 7).
13930               break;
13931             } else { // ori2 == 0.
13932               // apex(f) is coplanar with f1 (see Fig. 8).
13933               // f is either codirection with f1 or is codirection with f2.
13934               facenormal(torg, tdest, sapex(f1->ss), n1, 1, nullptr);
13935               facenormal(torg, tdest, sapex(sface), n2, 1, nullptr);
13936               if (dot(n1, n2) > 0) {
13937                 unifysubfaces(&(f1->ss), &sface);
13938               } else {
13939                 unifysubfaces(&(f2->ss), &sface);
13940               }
13941               break;
13942             }
13943           }
13944           // Go to the next item;
13945           f1 = f2;
13946         } // for (m = 0; ...)
13947         if (sface.sh[3] != nullptr) {
13948           // Insert sface between f1 and f2.
13949           newlinkitem = (badface *) flippool->alloc();
13950           newlinkitem->ss = sface;
13951           newlinkitem->nextitem = f1->nextitem;
13952           f1->nextitem = newlinkitem;
13953         }
13954       } else if (flippool->items == 1) {
13955         f1 = facelink;
13956         // Make sure that f is not coplanar and codirection with f1.
13957         ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
13958         if (ori1 == 0) {
13959           // f is coplanar with f1 (see Fig. 8).
13960           facenormal(torg, tdest, sapex(f1->ss), n1, 1, nullptr);
13961           facenormal(torg, tdest, sapex(sface), n2, 1, nullptr);
13962           if (dot(n1, n2) > 0) {
13963             // The two faces are codirectional as well.
13964             unifysubfaces(&(f1->ss), &sface);
13965           }
13966         }
13967         // Add this face to link if it is not deleted.
13968         if (sface.sh[3] != nullptr) {
13969           // Add this face into link.
13970           newlinkitem = (badface *) flippool->alloc();
13971           newlinkitem->ss = sface;
13972           newlinkitem->nextitem = nullptr;
13973           f1->nextitem = newlinkitem;
13974         }
13975       } else {
13976         // The first face.
13977         newlinkitem = (badface *) flippool->alloc();
13978         newlinkitem->ss = sface;
13979         newlinkitem->nextitem = nullptr;
13980         facelink = newlinkitem;
13981       }
13982     } // for (k = idx2faclist[idx]; ...)
13983 
13984     if (b->psc) {
13985       // Set Steiner point -to- segment map.
13986       if (pointtype(torg) == FREESEGVERTEX) {
13987         setpoint2sh(torg, sencode(subsegloop));
13988       }
13989       if (pointtype(tdest) == FREESEGVERTEX) {
13990         setpoint2sh(tdest, sencode(subsegloop));
13991       }
13992     }
13993 
13994     // Set the connection between this segment and faces containing it,
13995     //   at the same time, remove redundant segments.
13996     f1 = facelink;
13997     for (k = 0; k < flippool->items; k++) {
13998       sspivot(f1->ss, testseg);
13999       // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
14000       if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != nullptr)) {
14001         shellfacedealloc(subsegs, testseg.sh);
14002       }
14003       // Bonds the subface and the segment together.
14004       ssbond(f1->ss, subsegloop);
14005       f1 = f1->nextitem;
14006     }
14007 
14008     // Create the face ring at the segment.
14009     if (flippool->items > 1) {
14010       f1 = facelink;
14011       for (k = 1; k <= flippool->items; k++) {
14012         k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
14013         sbond1(f1->ss, f2->ss);
14014         f1 = f2;
14015       }
14016     }
14017 
14018     // All identified segments has an init marker "0".
14019     flippool->restart();
14020 
14021     // Are there length constraints?
14022     if (b->quality && (in->segmentconstraintlist != (REAL *) nullptr)) {
14023       int e1, e2;
14024       REAL len;
14025       for (k = 0; k < in->numberofsegmentconstraints; k++) {
14026         e1 = (int) in->segmentconstraintlist[k * 3];
14027         e2 = (int) in->segmentconstraintlist[k * 3 + 1];
14028         if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
14029             ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
14030           len = in->segmentconstraintlist[k * 3 + 2];
14031           setareabound(subsegloop, len);
14032           break;
14033         }
14034       }
14035     }
14036 
14037     subsegloop.sh = shellfacetraverse(subsegs);
14038   }
14039 
14040   delete [] idx2faclist;
14041   delete [] facperverlist;
14042 }
14043 
14044 ///////////////////////////////////////////////////////////////////////////////
14045 //                                                                           //
14046 // mergefacets()    Merge adjacent facets.                                   //
14047 //                                                                           //
14048 ///////////////////////////////////////////////////////////////////////////////
14049 
mergefacets()14050 void tetgenmesh::mergefacets()
14051 {
14052   face parentsh, neighsh, neineish;
14053   face segloop;
14054   point pa, pb, pc, pd;
14055   REAL ang_tol, ang;
14056   int remsegcount;
14057   int fidx1, fidx2;
14058   int fmrk1, fmrk2;
14059 
14060   if (b->verbose > 1) {
14061     printf("    Merging adjacent facets.\n");
14062   }
14063 
14064   // The dihedral angle bound for two different facets.
14065   //   Set by -p option. Default is 179 degree.
14066   ang_tol = b->facet_ang_tol / 180.0 * PI;
14067   remsegcount = 0;
14068 
14069   // Loop all segments, merge adjacent coplanar facets.
14070   subsegs->traversalinit();
14071   segloop.sh = shellfacetraverse(subsegs);
14072   while (segloop.sh != (shellface *) nullptr) {
14073     spivot(segloop, parentsh);
14074     if (parentsh.sh != nullptr) {
14075       spivot(parentsh, neighsh);
14076       if (neighsh.sh != nullptr) {
14077         spivot(neighsh, neineish);
14078         if (neineish.sh == parentsh.sh) {
14079           // Exactly two subfaces at this segment.
14080           fidx1 = shellmark(parentsh) - 1;
14081           fidx2 = shellmark(neighsh) - 1;
14082           // Only merge them if they are in different facet.
14083           if (fidx1 != fidx2) {
14084             // The two subfaces are not in the same facet.
14085             if (in->facetmarkerlist != nullptr) {
14086               fmrk1 = in->facetmarkerlist[fidx1];
14087               fmrk2 = in->facetmarkerlist[fidx2];
14088             } else {
14089               fmrk1 = fmrk2 = 0;
14090             }
14091             // Only merge them if they have the same boundary marker.
14092             if (fmrk1 == fmrk2) {
14093               pa = sorg(segloop);
14094               pb = sdest(segloop);
14095               pc = sapex(parentsh);
14096               pd = sapex(neighsh);
14097               // Calculate the dihedral angle at the segment [a,b].
14098               ang = facedihedral(pa, pb, pc, pd);
14099               if (ang > PI) ang = (2 * PI - ang);
14100               if (ang > ang_tol) {
14101                 remsegcount++;
14102                 ssdissolve(parentsh);
14103                 ssdissolve(neighsh);
14104                 shellfacedealloc(subsegs, segloop.sh);
14105                 // Add the edge to flip stack.
14106                 flipshpush(&parentsh);
14107               } // if (ang > ang_tol)
14108             } // if (fmrk1 == fmrk2)
14109           } // if (fidx1 != fidx2)
14110         } // if (neineish.sh == parentsh.sh)
14111       }
14112     }
14113     segloop.sh = shellfacetraverse(subsegs);
14114   }
14115 
14116   if (flipstack != nullptr) {
14117     lawsonflip(); // Recover Delaunayness.
14118   }
14119 
14120   if (b->verbose > 1) {
14121     printf("    %d segments are removed.\n", remsegcount);
14122   }
14123 }
14124 
14125 ///////////////////////////////////////////////////////////////////////////////
14126 //                                                                           //
14127 // identifypscedges()    Identify PSC edges.                                 //
14128 //                                                                           //
14129 // The set of PSC edges are provided in the 'in->edgelist'. Each edge should //
14130 // also be an edge in the surface mesh.  We find the corresponding edges in  //
14131 // the surface mesh and make them segments of the mesh.                      //
14132 //                                                                           //
14133 // It is possible to give an edge which is not in any facet, i.e., it is a   //
14134 // dangling edge inside the volume.                                          //
14135 //                                                                           //
14136 ///////////////////////////////////////////////////////////////////////////////
14137 
identifypscedges(point * idx2verlist)14138 void tetgenmesh::identifypscedges(point *idx2verlist)
14139 {
14140   face* shperverlist;
14141   int* idx2shlist;
14142   face searchsh, neighsh;
14143   face segloop, checkseg, newseg;
14144   point checkpt, pa = nullptr, pb = nullptr;
14145   int *endpts;
14146   int edgemarker;
14147   int idx, i, j;
14148 
14149   int e1, e2;
14150   REAL len;
14151 
14152   if (!b->quiet) {
14153     printf("Inserting edges ...\n");
14154   }
14155 
14156   // All identified segments have the initial marker '1'.
14157   // All segments inserted here should have a marker 'k >= 0'.
14158 
14159   if (b->psc) {
14160     // First mark all segments of the mesh with a marker '-1'.
14161     subsegs->traversalinit();
14162     segloop.sh = shellfacetraverse(subsegs);
14163     while (segloop.sh != nullptr) {
14164       setshellmark(segloop, -1);
14165       segloop.sh = shellfacetraverse(subsegs);
14166     }
14167   }
14168 
14169   // Construct a map from points to subfaces.
14170   makepoint2submap(subfaces, idx2shlist, shperverlist);
14171 
14172   // Process the set of PSC edges.
14173   for (i = 0; i < in->numberofedges; i++) {
14174     endpts = &(in->edgelist[(i << 1)]);
14175     // Find a face contains the edge.
14176     newseg.sh = nullptr;
14177     searchsh.sh = nullptr;
14178     idx = endpts[0] - in->firstnumber;
14179     for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
14180       checkpt = sdest(shperverlist[j]);
14181       if (pointmark(checkpt) == endpts[1]) {
14182         searchsh = shperverlist[j];
14183         break; // Found.
14184       } else {
14185         checkpt = sapex(shperverlist[j]);
14186         if (pointmark(checkpt) == endpts[1]) {
14187           senext2(shperverlist[j], searchsh);
14188           sesymself(searchsh);
14189           break;
14190         }
14191       }
14192     } // j
14193     edgemarker = 0;
14194     if (in->edgemarkerlist) {
14195       edgemarker = in->edgemarkerlist[i];
14196     }
14197 
14198     if (searchsh.sh != nullptr) {
14199       // Check if this edge is already a segment of the mesh.
14200       sspivot(searchsh, checkseg);
14201       if (checkseg.sh != nullptr) {
14202         // There should be no duplicated edges.
14203         setshellmark(checkseg, edgemarker);
14204       } else {
14205         // Create a new segment at this edge.
14206         pa = sorg(searchsh);
14207         pb = sdest(searchsh);
14208         makeshellface(subsegs, &newseg);
14209         setshvertices(newseg, pa, pb, nullptr);
14210         setshellmark(newseg, edgemarker);
14211         ssbond(searchsh, newseg);
14212         spivot(searchsh, neighsh);
14213         if (neighsh.sh != nullptr) {
14214           ssbond(neighsh, newseg);
14215         }
14216         if (b->psc) {
14217           if (pointtype(pa) == FREESEGVERTEX) {
14218             setpoint2sh(pa, sencode(newseg));
14219           }
14220           if (pointtype(pb) == FREESEGVERTEX) {
14221             setpoint2sh(pb, sencode(newseg));
14222           }
14223         }
14224       }
14225     } else {
14226       // It is a dangling segment (not belong to any facets).
14227       // Get the two endpoints of this segment.
14228       pa = idx2verlist[endpts[0]];
14229       pb = idx2verlist[endpts[1]];
14230       makeshellface(subsegs, &newseg);
14231       setshvertices(newseg, pa, pb, nullptr);
14232       setshellmark(newseg, edgemarker);
14233       if (b->psc) {
14234         if (pointtype(pa) == FREESEGVERTEX) {
14235           setpoint2sh(pa, sencode(newseg));
14236         }
14237         if (pointtype(pb) == FREESEGVERTEX) {
14238           setpoint2sh(pb, sencode(newseg));
14239         }
14240       }
14241     }
14242 
14243     if (newseg.sh != nullptr) {
14244       if (b->quality && (in->segmentconstraintlist != (REAL *) nullptr)) {
14245         for (i = 0; i < in->numberofsegmentconstraints; i++) {
14246           e1 = (int) in->segmentconstraintlist[i * 3];
14247           e2 = (int) in->segmentconstraintlist[i * 3 + 1];
14248           if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
14249               ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
14250             len = in->segmentconstraintlist[i * 3 + 2];
14251             setareabound(newseg, len);
14252             break;
14253           }
14254         }
14255       }
14256     }
14257   } // i
14258 
14259 
14260   delete [] shperverlist;
14261   delete [] idx2shlist;
14262 
14263   if (b->psc) {
14264     // Connecting subsegments at Steiner points.
14265     face seg1, seg2;
14266     // Re-use 'idx2shlist' and 'shperverlist'.
14267     makepoint2submap(subsegs, idx2shlist, shperverlist);
14268 
14269     points->traversalinit();
14270     pa = pointtraverse();
14271     while (pa != nullptr) {
14272       if (pointtype(pa) == FREESEGVERTEX) {
14273         idx = pointmark(pa) - in->firstnumber;
14274         // There must be only two segments containing this vertex.
14275         assert((idx2shlist[idx + 1] - idx2shlist[idx]) == 2);
14276         i = idx2shlist[idx];
14277         seg1 = shperverlist[i];
14278         seg2 = shperverlist[i+1];
14279         senextself(seg1);
14280         senextself(seg2);
14281         sbond(seg1, seg2);
14282       }
14283       pa = pointtraverse();
14284     }
14285 
14286     delete [] shperverlist;
14287     delete [] idx2shlist;
14288   }
14289 }
14290 
14291 ///////////////////////////////////////////////////////////////////////////////
14292 //                                                                           //
14293 // meshsurface()    Create a surface mesh of the input PLC.                  //
14294 //                                                                           //
14295 ///////////////////////////////////////////////////////////////////////////////
14296 
meshsurface()14297 void tetgenmesh::meshsurface()
14298 {
14299   arraypool *ptlist, *conlist;
14300   point *idx2verlist;
14301   point tstart, tend, *pnewpt, *cons;
14302   tetgenio::facet *f;
14303   tetgenio::polygon *p;
14304   int end1, end2;
14305   int shmark, i, j;
14306 
14307   if (!b->quiet) {
14308     printf("Creating surface mesh ...\n");
14309   }
14310 
14311   // Create a map from indices to points.
14312   makeindex2pointmap(idx2verlist);
14313 
14314   // Initialize arrays (block size: 2^8 = 256).
14315   ptlist = new arraypool(sizeof(point *), 8);
14316   conlist = new arraypool(2 * sizeof(point *), 8);
14317 
14318   // Loop the facet list, triangulate each facet.
14319   for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
14320 
14321     // Get a facet F.
14322     f = &in->facetlist[shmark - 1];
14323 
14324     // Process the duplicated points first, they are marked with type
14325     //   DUPLICATEDVERTEX.  If p and q are duplicated, and p'index > q's,
14326     //   then p is substituted by q.
14327     if (dupverts > 0l) {
14328       // Loop all polygons of this facet.
14329       for (i = 0; i < f->numberofpolygons; i++) {
14330         p = &(f->polygonlist[i]);
14331         // Loop other vertices of this polygon.
14332         for (j = 0; j < p->numberofvertices; j++) {
14333           end1 = p->vertexlist[j];
14334           tstart = idx2verlist[end1];
14335           if (pointtype(tstart) == DUPLICATEDVERTEX) {
14336             // Reset the index of vertex-j.
14337             tend = point2ppt(tstart);
14338             end2 = pointmark(tend);
14339             p->vertexlist[j] = end2;
14340           }
14341         }
14342       }
14343     }
14344 
14345     // Loop polygons of F, get the set of vertices and segments.
14346     for (i = 0; i < f->numberofpolygons; i++) {
14347       // Get a polygon.
14348       p = &(f->polygonlist[i]);
14349       // Get the first vertex.
14350       end1 = p->vertexlist[0];
14351       if ((end1 < in->firstnumber) ||
14352           (end1 >= in->firstnumber + in->numberofpoints)) {
14353         if (!b->quiet) {
14354           printf("Warning:  Invalid the 1st vertex %d of polygon", end1);
14355           printf(" %d in facet %d.\n", i + 1, shmark);
14356         }
14357         continue; // Skip this polygon.
14358       }
14359       tstart = idx2verlist[end1];
14360       // Add tstart to V if it haven't been added yet.
14361       if (!pinfected(tstart)) {
14362         pinfect(tstart);
14363         ptlist->newindex((void **) &pnewpt);
14364         *pnewpt = tstart;
14365       }
14366       // Loop other vertices of this polygon.
14367       for (j = 1; j <= p->numberofvertices; j++) {
14368         // get a vertex.
14369         if (j < p->numberofvertices) {
14370           end2 = p->vertexlist[j];
14371         } else {
14372           end2 = p->vertexlist[0];  // Form a loop from last to first.
14373         }
14374         if ((end2 < in->firstnumber) ||
14375             (end2 >= in->firstnumber + in->numberofpoints)) {
14376           if (!b->quiet) {
14377             printf("Warning:  Invalid vertex %d in polygon %d", end2, i + 1);
14378             printf(" in facet %d.\n", shmark);
14379           }
14380         } else {
14381           if (end1 != end2) {
14382             // 'end1' and 'end2' form a segment.
14383             tend = idx2verlist[end2];
14384             // Add tstart to V if it haven't been added yet.
14385             if (!pinfected(tend)) {
14386               pinfect(tend);
14387               ptlist->newindex((void **) &pnewpt);
14388               *pnewpt = tend;
14389             }
14390             // Save the segment in S (conlist).
14391             conlist->newindex((void **) &cons);
14392             cons[0] = tstart;
14393             cons[1] = tend;
14394             // Set the start for next continuous segment.
14395             end1 = end2;
14396             tstart = tend;
14397           } else {
14398             // Two identical vertices mean an isolated vertex of F.
14399             if (p->numberofvertices > 2) {
14400               // This may be an error in the input, anyway, we can continue
14401               //   by simply skipping this segment.
14402               if (!b->quiet) {
14403                 printf("Warning:  Polygon %d has two identical verts", i + 1);
14404                 printf(" in facet %d.\n", shmark);
14405               }
14406             }
14407             // Ignore this vertex.
14408           }
14409         }
14410         // Is the polygon degenerate (a segment or a vertex)?
14411         if (p->numberofvertices == 2) break;
14412       }
14413     }
14414     // Unmark vertices.
14415     for (i = 0; i < ptlist->objects; i++) {
14416       pnewpt = (point *) fastlookup(ptlist, i);
14417       puninfect(*pnewpt);
14418     }
14419 
14420     // Triangulate F into a CDT.
14421     triangulate(shmark, ptlist, conlist, f->numberofholes, f->holelist);
14422 
14423     // Clear working lists.
14424     ptlist->restart();
14425     conlist->restart();
14426   }
14427 
14428   if (!b->diagnose) {
14429     // Remove redundant segments and build the face links.
14430     unifysegments();
14431   }
14432 
14433   if (!b->psc && !b->nomergefacet && !b->nobisect && !b->diagnose) {
14434     // Merge adjacent coplanar facets.
14435     mergefacets();
14436   }
14437 
14438   if (in->numberofedges > 0) { // if (b->psc)
14439     // There are segments specified by the user. Read and create them.
14440     identifypscedges(idx2verlist);
14441   }
14442 
14443   if (b->object == tetgenbehavior::STL) {
14444     // Remove redundant vertices (for .stl input mesh).
14445     jettisonnodes();
14446   }
14447 
14448   if (b->verbose) {
14449     printf("  %ld (%ld) subfaces (segments).\n", subfaces->items,
14450            subsegs->items);
14451   }
14452 
14453   // The total number of iunput segments.
14454   insegments = subsegs->items;
14455 
14456   delete [] idx2verlist;
14457   delete ptlist;
14458   delete conlist;
14459 }
14460 
14461 
14462 ///////////////////////////////////////////////////////////////////////////////
14463 //                                                                           //
14464 // interecursive()    Recursively do intersection test on a set of triangles.//
14465 //                                                                           //
14466 // Recursively split the set 'subfacearray' of subfaces into two sets using  //
14467 // a cut plane parallel to x-, or, y-, or z-axies.  The split criteria are   //
14468 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of  //
14469 // H, and H- denotes the right halfspace of H; and s be a subface:           //
14470 //                                                                           //
14471 //    (1) If all points of s lie at H+, put it into left array;              //
14472 //    (2) If all points of s lie at H-, put it into right array;             //
14473 //    (3) If some points of s lie at H+ and some of lie at H-, or some       //
14474 //        points lie on H, put it into both arraies.                         //
14475 //                                                                           //
14476 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis  //
14477 // if axis == '2'. If current cut plane is parallel to the x-axis, the next  //
14478 // one will be parallel to y-axis, and the next one after the next is z-axis,//
14479 // and then alternately return back to x-axis.                               //
14480 //                                                                           //
14481 // Stop splitting when the number of triangles of the input array is not     //
14482 // decreased anymore. Do tests on the current set.                           //
14483 //                                                                           //
14484 ///////////////////////////////////////////////////////////////////////////////
14485 
interecursive(shellface ** subfacearray,int arraysize,int axis,REAL bxmin,REAL bxmax,REAL bymin,REAL bymax,REAL bzmin,REAL bzmax,int * internum)14486 void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
14487                                int axis, REAL bxmin, REAL bxmax, REAL bymin,
14488                                REAL bymax, REAL bzmin, REAL bzmax,
14489                                int* internum)
14490 {
14491   shellface **leftarray, **rightarray;
14492   face sface1, sface2;
14493   point p1, p2, p3;
14494   point p4, p5, p6;
14495   enum interresult intersect;
14496   REAL split;
14497   bool toleft, toright;
14498   int leftsize, rightsize;
14499   int i, j;
14500 
14501   if (b->verbose > 2) {
14502     printf("      Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
14503            arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
14504            axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
14505   }
14506 
14507   leftarray = new shellface*[arraysize];
14508   if (leftarray == nullptr) {
14509     terminatetetgen(1);
14510   }
14511   rightarray = new shellface*[arraysize];
14512   if (rightarray == nullptr) {
14513     terminatetetgen(1);
14514   }
14515   leftsize = rightsize = 0;
14516 
14517   if (axis == 0) {
14518     // Split along x-axis.
14519     split = 0.5 * (bxmin + bxmax);
14520   } else if (axis == 1) {
14521     // Split along y-axis.
14522     split = 0.5 * (bymin + bymax);
14523   } else {
14524     // Split along z-axis.
14525     split = 0.5 * (bzmin + bzmax);
14526   }
14527 
14528   for (i = 0; i < arraysize; i++) {
14529     sface1.sh = subfacearray[i];
14530     p1 = (point) sface1.sh[3];
14531     p2 = (point) sface1.sh[4];
14532     p3 = (point) sface1.sh[5];
14533     toleft = toright = false;
14534     if (p1[axis] < split) {
14535       toleft = true;
14536       if (p2[axis] >= split || p3[axis] >= split) {
14537         toright = true;
14538       }
14539     } else if (p1[axis] > split) {
14540       toright = true;
14541       if (p2[axis] <= split || p3[axis] <= split) {
14542         toleft = true;
14543       }
14544     } else {
14545       // p1[axis] == split;
14546       toleft = true;
14547       toright = true;
14548     }
14549     // At least one is true;
14550     assert(!(toleft == false && toright == false));
14551     if (toleft) {
14552       leftarray[leftsize] = sface1.sh;
14553       leftsize++;
14554     }
14555     if (toright) {
14556       rightarray[rightsize] = sface1.sh;
14557       rightsize++;
14558     }
14559   }
14560 
14561   if (leftsize < arraysize && rightsize < arraysize) {
14562     // Continue to partition the input set. Now 'subfacearray' has been
14563     //   split into two sets, it's memory can be freed. 'leftarray' and
14564     //   'rightarray' will be freed in the next recursive (after they're
14565     //   partitioned again or performing tests).
14566     delete [] subfacearray;
14567     // Continue to split these two sets.
14568     if (axis == 0) {
14569       interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
14570                     bzmin, bzmax, internum);
14571       interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
14572                     bzmin, bzmax, internum);
14573     } else if (axis == 1) {
14574       interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
14575                     bzmin, bzmax, internum);
14576       interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
14577                     bzmin, bzmax, internum);
14578     } else {
14579       interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
14580                     bzmin, split, internum);
14581       interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
14582                     split, bzmax, internum);
14583     }
14584   } else {
14585     if (b->verbose > 1) {
14586       printf("  Checking intersecting faces.\n");
14587     }
14588     // Perform a brute-force compare on the set.
14589     for (i = 0; i < arraysize; i++) {
14590       sface1.sh = subfacearray[i];
14591       p1 = (point) sface1.sh[3];
14592       p2 = (point) sface1.sh[4];
14593       p3 = (point) sface1.sh[5];
14594       for (j = i + 1; j < arraysize; j++) {
14595         sface2.sh = subfacearray[j];
14596         p4 = (point) sface2.sh[3];
14597         p5 = (point) sface2.sh[4];
14598         p6 = (point) sface2.sh[5];
14599         intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
14600         if (intersect == INTERSECT || intersect == SHAREFACE) {
14601             // [Bruno]
14602             // Keep track of the facets that intersect.
14603             in->isectfaces.insert(shellmark(sface1));
14604             in->isectfaces.insert(shellmark(sface2));
14605           if (!b->quiet) {
14606             if (intersect == INTERSECT) {
14607               printf("  Facet #%d intersects facet #%d at triangles:\n",
14608                      shellmark(sface1), shellmark(sface2));
14609               printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14610                      pointmark(p1), pointmark(p2), pointmark(p3),
14611                      pointmark(p4), pointmark(p5), pointmark(p6));
14612             } else {
14613               printf("  Facet #%d duplicates facet #%d at triangle:\n",
14614                      shellmark(sface1), shellmark(sface2));
14615               printf("    (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
14616                      pointmark(p1), pointmark(p2), pointmark(p3),
14617                      pointmark(p4), pointmark(p5), pointmark(p6));
14618             }
14619           }
14620           // Increase the number of intersecting pairs.
14621           (*internum)++;
14622           // Infect these two faces (although they may already be infected).
14623           sinfect(sface1);
14624           sinfect(sface2);
14625         }
14626       }
14627     }
14628     // Don't forget to free all three arrays. No further partition.
14629     delete [] leftarray;
14630     delete [] rightarray;
14631     delete [] subfacearray;
14632   }
14633 }
14634 
14635 ///////////////////////////////////////////////////////////////////////////////
14636 //                                                                           //
14637 // detectinterfaces()    Detect intersecting triangles.                      //
14638 //                                                                           //
14639 // Given a set of triangles,  find the pairs of intersecting triangles from  //
14640 // them.  Here the set of triangles is in 'subfaces' which is a surface mesh //
14641 // of a PLC (.poly or .smesh).                                               //
14642 //                                                                           //
14643 // To detect whether two triangles are intersecting is done by the routine   //
14644 // 'tri_tri_inter()'.  The algorithm for the test is very simple and stable. //
14645 // It is based on geometric orientation test which uses exact arithmetics.   //
14646 //                                                                           //
14647 // Use divide-and-conquer algorithm for reducing the number of intersection  //
14648 // tests.  Start from the bounding box of the input point set, recursively   //
14649 // partition the box into smaller boxes, until the number of triangles in a  //
14650 // box is not decreased anymore. Then perform triangle-triangle tests on the //
14651 // remaining set of triangles.  The memory allocated in the input set is     //
14652 // freed immediately after it has been partitioned into two arrays.  So it   //
14653 // can be re-used for the consequent partitions.                             //
14654 //                                                                           //
14655 // On return, the pool 'subfaces' will be cleared, and only the intersecting //
14656 // triangles remain for output (to a .face file).                            //
14657 //                                                                           //
14658 ///////////////////////////////////////////////////////////////////////////////
14659 
detectinterfaces()14660 void tetgenmesh::detectinterfaces()
14661 {
14662   shellface **subfacearray;
14663   face shloop;
14664   int internum;
14665   int i;
14666 
14667   if (!b->quiet) {
14668     printf("Detecting self-intersecting facets...\n");
14669   }
14670 
14671   // Construct a map from indices to subfaces;
14672   subfacearray = new shellface*[subfaces->items];
14673   subfaces->traversalinit();
14674   shloop.sh = shellfacetraverse(subfaces);
14675   i = 0;
14676   while (shloop.sh != (shellface *) nullptr) {
14677     subfacearray[i] = shloop.sh;
14678     shloop.sh = shellfacetraverse(subfaces);
14679     i++;
14680   }
14681 
14682   internum = 0;
14683   // Recursively split the set of triangles into two sets using a cut plane
14684   //   parallel to x-, or, y-, or z-axies.  Stop splitting when the number
14685   //   of subfaces is not decreasing anymore. Do tests on the current set.
14686   interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
14687                 zmin, zmax, &internum);
14688 
14689   if (!b->quiet) {
14690     if (internum > 0) {
14691       printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
14692     } else {
14693       printf("\nNo faces are intersecting.\n\n");
14694     }
14695   }
14696 
14697   if (internum > 0) {
14698     // Traverse all subfaces, deallocate those have not been infected (they
14699     //   are not intersecting faces). Uninfect those have been infected.
14700     //   After this loop, only intersecting faces remain.
14701     subfaces->traversalinit();
14702     shloop.sh = shellfacetraverse(subfaces);
14703     while (shloop.sh != (shellface *) nullptr) {
14704       if (sinfected(shloop)) {
14705         suninfect(shloop);
14706       } else {
14707         shellfacedealloc(subfaces, shloop.sh);
14708       }
14709       shloop.sh = shellfacetraverse(subfaces);
14710     }
14711   } else {
14712     // Deallocate all subfaces.
14713     subfaces->restart();
14714   }
14715 }
14716 
14717 ////                                                                       ////
14718 ////                                                                       ////
14719 //// surface_cxx //////////////////////////////////////////////////////////////
14720 
14721 //// constrained_cxx //////////////////////////////////////////////////////////
14722 ////                                                                       ////
14723 ////                                                                       ////
14724 
14725 ///////////////////////////////////////////////////////////////////////////////
14726 //                                                                           //
14727 // markacutevertices()    Classify vertices as ACUTEVERTEXs or RIDGEVERTEXs. //
14728 //                                                                           //
14729 // Initialize all segment vertices's type be RIDGEVERTEX. A segment is acute //
14730 // if there are at least two segments incident at it form an angle less than //
14731 // theta (= 60 degree).                                                      //
14732 //                                                                           //
14733 // The minimum segment-segment angle (minfaceang) is calculated.             //
14734 //                                                                           //
14735 ///////////////////////////////////////////////////////////////////////////////
14736 
markacutevertices()14737 void tetgenmesh::markacutevertices()
14738 {
14739   face* segperverlist;
14740   int* idx2seglist;
14741   point pa, pb, pc;
14742   REAL anglimit, sharpanglimit, ang;
14743   bool acuteflag;
14744   int acutecount, sharpsegcount;
14745   int idx, i, j;
14746 
14747   if (b->verbose) {
14748     printf("  Marking acute vertices.\n");
14749   }
14750   anglimit = PI / 3.0;  // 60 degree.
14751   sharpanglimit = 5.0 / 180.0 * PI; // 5 degree.
14752   minfaceang = PI; // 180 degree.
14753   acutecount = sharpsegcount = 0;
14754 
14755   // Construct a map from points to segments.
14756   makepoint2submap(subsegs, idx2seglist, segperverlist);
14757 
14758   // Loop over the set of vertices.
14759   points->traversalinit();
14760   pa = pointtraverse();
14761   while (pa != nullptr) {
14762     idx = pointmark(pa) - in->firstnumber;
14763     // Mark it if it is an endpoint of some segments.
14764     if (idx2seglist[idx + 1] > idx2seglist[idx]) {
14765       // It is an endpoint of some segments.
14766       setpointtype(pa, RIDGEVERTEX);
14767       acuteflag = false;
14768       // Do a brute-force pair-pair check.
14769       for (i=idx2seglist[idx]; i<idx2seglist[idx + 1]; i++) {
14770         pb = sdest(segperverlist[i]);
14771         for (j = i + 1; j < idx2seglist[idx + 1]; j++) {
14772           pc = sdest(segperverlist[j]);
14773           ang = interiorangle(pa, pb, pc, nullptr);
14774           if (!acuteflag) {
14775             acuteflag = ang < anglimit;
14776           }
14777           // Remember the smallest angle.
14778           if (ang < minfaceang) minfaceang = ang;
14779           // Mark segments at extremely small angle.
14780           if (ang < sharpanglimit) {
14781             if (shelltype(segperverlist[i]) != SHARP) {
14782               setshelltype(segperverlist[i], SHARP);
14783               sharpsegcount++;
14784             }
14785             if (shelltype(segperverlist[j]) != SHARP) {
14786               setshelltype(segperverlist[j], SHARP);
14787               sharpsegcount++;
14788             }
14789           }
14790         } // j
14791       } // i
14792       if (acuteflag) {
14793         setpointtype(pa, ACUTEVERTEX);
14794         acutecount++;
14795       }
14796     }
14797     pa = pointtraverse();
14798   }
14799 
14800   if (b->verbose) {
14801     if (acutecount > 0) {
14802       printf("  Found %d acute vertices.\n", acutecount);
14803     }
14804     if (sharpsegcount > 0) {
14805       printf("  Found %d sharp segments.\n", sharpsegcount);
14806     }
14807     printf("  Minimum seg-seg angle = %g.\n", minfaceang / PI * 180.0);
14808   }
14809 
14810   delete [] idx2seglist;
14811   delete [] segperverlist;
14812 }
14813 
14814 
14815 ///////////////////////////////////////////////////////////////////////////////
14816 //                                                                           //
14817 // finddirection()    Find the tet on the path from one point to another.    //
14818 //                                                                           //
14819 // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
14820 // 'searchtet' contains a tet on the path, its origin does not change.       //
14821 //                                                                           //
14822 // The return value indicates one of the following cases (let 'searchtet' be //
14823 // abcd, a is the origin of the path):                                       //
14824 //   - ACROSSVERT, edge ab is collinear with the path;                       //
14825 //   - ACROSSEDGE, edge bc intersects with the path;                         //
14826 //   - ACROSSFACE, face bcd intersects with the path.                        //
14827 //                                                                           //
14828 // WARNING: This routine is designed for convex triangulations, and will not //
14829 // generally work after the holes and concavities have been carved.          //
14830 //                                                                           //
14831 ///////////////////////////////////////////////////////////////////////////////
14832 
14833 enum tetgenmesh::interresult
finddirection(triface * searchtet,point endpt)14834   tetgenmesh::finddirection(triface* searchtet, point endpt)
14835 {
14836   triface neightet;
14837   point pa, pb, pc, pd;
14838   enum {HMOVE, RMOVE, LMOVE} nextmove;
14839   REAL hori, rori, lori;
14840   int t1ver;
14841   int s;
14842 
14843   // The origin is fixed.
14844   pa = org(*searchtet);
14845   if ((point) searchtet->tet[7] == dummypoint) {
14846     // A hull tet. Choose the neighbor of its base face.
14847     decode(searchtet->tet[3], *searchtet);
14848     // Reset the origin to be pa.
14849     if ((point) searchtet->tet[4] == pa) {
14850       searchtet->ver = 11;
14851     } else if ((point) searchtet->tet[5] == pa) {
14852       searchtet->ver = 3;
14853     } else if ((point) searchtet->tet[6] == pa) {
14854       searchtet->ver = 7;
14855     } else {
14856       assert((point) searchtet->tet[7] == pa);
14857       searchtet->ver = 0;
14858     }
14859   }
14860 
14861   pb = dest(*searchtet);
14862   // Check whether the destination or apex is 'endpt'.
14863   if (pb == endpt) {
14864     // pa->pb is the search edge.
14865     return ACROSSVERT;
14866   }
14867 
14868   pc = apex(*searchtet);
14869   if (pc == endpt) {
14870     // pa->pc is the search edge.
14871     eprevesymself(*searchtet);
14872     return ACROSSVERT;
14873   }
14874 
14875   // Walk through tets around pa until the right one is found.
14876   while (1) {
14877 
14878     pd = oppo(*searchtet);
14879     // Check whether the opposite vertex is 'endpt'.
14880     if (pd == endpt) {
14881       // pa->pd is the search edge.
14882       esymself(*searchtet);
14883       enextself(*searchtet);
14884       return ACROSSVERT;
14885     }
14886     // Check if we have entered outside of the domain.
14887     if (pd == dummypoint) {
14888       // This is possible when the mesh is non-convex.
14889       assert(nonconvex);
14890       return ACROSSSUB; // Hit a bounday.
14891     }
14892 
14893     // Now assume that the base face abc coincides with the horizon plane,
14894     //   and d lies above the horizon.  The search point 'endpt' may lie
14895     //   above or below the horizon.  We test the orientations of 'endpt'
14896     //   with respect to three planes: abc (horizon), bad (right plane),
14897     //   and acd (left plane).
14898     hori = orient3d(pa, pb, pc, endpt);
14899     rori = orient3d(pb, pa, pd, endpt);
14900     lori = orient3d(pa, pc, pd, endpt);
14901 
14902     // Now decide the tet to move.  It is possible there are more than one
14903     //   tets are viable moves. Is so, randomly choose one.
14904     if (hori > 0) {
14905       if (rori > 0) {
14906         if (lori > 0) {
14907           // Any of the three neighbors is a viable move.
14908           s = randomnation(3);
14909           if (s == 0) {
14910             nextmove = HMOVE;
14911           } else if (s == 1) {
14912             nextmove = RMOVE;
14913           } else {
14914             nextmove = LMOVE;
14915           }
14916         } else {
14917           // Two tets, below horizon and below right, are viable.
14918           //s = randomnation(2);
14919           if (randomnation(2)) {
14920             nextmove = HMOVE;
14921           } else {
14922             nextmove = RMOVE;
14923           }
14924         }
14925       } else {
14926         if (lori > 0) {
14927           // Two tets, below horizon and below left, are viable.
14928           //s = randomnation(2);
14929           if (randomnation(2)) {
14930             nextmove = HMOVE;
14931           } else {
14932             nextmove = LMOVE;
14933           }
14934         } else {
14935           // The tet below horizon is chosen.
14936           nextmove = HMOVE;
14937         }
14938       }
14939     } else {
14940       if (rori > 0) {
14941         if (lori > 0) {
14942           // Two tets, below right and below left, are viable.
14943           //s = randomnation(2);
14944           if (randomnation(2)) {
14945             nextmove = RMOVE;
14946           } else {
14947             nextmove = LMOVE;
14948           }
14949         } else {
14950           // The tet below right is chosen.
14951           nextmove = RMOVE;
14952         }
14953       } else {
14954         if (lori > 0) {
14955           // The tet below left is chosen.
14956           nextmove = LMOVE;
14957         } else {
14958           // 'endpt' lies either on the plane(s) or across face bcd.
14959           if (hori == 0) {
14960             if (rori == 0) {
14961               // pa->'endpt' is COLLINEAR with pa->pb.
14962               return ACROSSVERT;
14963             }
14964             if (lori == 0) {
14965               // pa->'endpt' is COLLINEAR with pa->pc.
14966               eprevesymself(*searchtet); // // [a,c,d]
14967               return ACROSSVERT;
14968             }
14969             // pa->'endpt' crosses the edge pb->pc.
14970             return ACROSSEDGE;
14971           }
14972           if (rori == 0) {
14973             if (lori == 0) {
14974               // pa->'endpt' is COLLINEAR with pa->pd.
14975               esymself(*searchtet); // face bad.
14976               enextself(*searchtet); // face [a,d,b]
14977               return ACROSSVERT;
14978             }
14979             // pa->'endpt' crosses the edge pb->pd.
14980             esymself(*searchtet); // face bad.
14981             enextself(*searchtet); // face adb
14982             return ACROSSEDGE;
14983           }
14984           if (lori == 0) {
14985             // pa->'endpt' crosses the edge pc->pd.
14986             eprevesymself(*searchtet); // [a,c,d]
14987             return ACROSSEDGE;
14988           }
14989           // pa->'endpt' crosses the face bcd.
14990           return ACROSSFACE;
14991         }
14992       }
14993     }
14994 
14995     // Move to the next tet, fix pa as its origin.
14996     if (nextmove == RMOVE) {
14997       fnextself(*searchtet);
14998     } else if (nextmove == LMOVE) {
14999       eprevself(*searchtet);
15000       fnextself(*searchtet);
15001       enextself(*searchtet);
15002     } else { // HMOVE
15003       fsymself(*searchtet);
15004       enextself(*searchtet);
15005     }
15006     assert(org(*searchtet) == pa);
15007     pb = dest(*searchtet);
15008     pc = apex(*searchtet);
15009 
15010   } // while (1)
15011 
15012 }
15013 
15014 ///////////////////////////////////////////////////////////////////////////////
15015 //                                                                           //
15016 // scoutsegment()    Search an edge in the tetrahedralization.               //
15017 //                                                                           //
15018 // If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the   //
15019 // edge from startpt to endpt.                                               //
15020 //                                                                           //
15021 // If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
15022 // indicates that the edge intersects an edge or a face.  If 'refpt' is nullptr,//
15023 // 'searchtet' returns the edge or face. If 'refpt' is not nullptr, it returns  //
15024 // a vertex which encroaches upon this edge, and 'searchtet' returns a tet   //
15025 // which containing 'refpt'.                                                 //
15026 //                                                                           //
15027 // The following cases can happen when the input PLC is not valid.           //
15028 //   - ACROSSVERT, the edge intersects a vertex return by the origin of      //
15029 //                 'searchtet'.                                              //
15030 //   - ACROSSSEG, the edge intersects a segment returned by 'searchtet'.     //
15031 //   - ACROSSSUB, the edge intersects a subface returned by 'searchtet'.     //
15032 //                                                                           //
15033 ///////////////////////////////////////////////////////////////////////////////
15034 
15035 enum tetgenmesh::interresult
scoutsegment(point startpt,point endpt,triface * searchtet,point * refpt,arraypool * intfacelist)15036   tetgenmesh::scoutsegment(point startpt, point endpt, triface* searchtet,
15037                            point* refpt, arraypool* intfacelist)
15038 {
15039   point pd;
15040   enum interresult dir;
15041   int t1ver;
15042 
15043   if (b->verbose > 2) {
15044     printf("      Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
15045   }
15046 
15047   point2tetorg(startpt, *searchtet);
15048   dir = finddirection(searchtet, endpt);
15049 
15050   if (dir == ACROSSVERT) {
15051     pd = dest(*searchtet);
15052     if (pd == endpt) {
15053       // The job is done.
15054       return SHAREEDGE;
15055     } else {
15056       // A point is on the path.
15057       // Let the origin of the searchtet be the vertex.
15058       enextself(*searchtet);
15059       if (refpt) *refpt = pd;
15060       return ACROSSVERT;
15061     }
15062   } // if (dir == ACROSSVERT)
15063 
15064   // dir is either ACROSSEDGE or ACROSSFACE.
15065 
15066   enextesymself(*searchtet); // Go to the opposite face.
15067   fsymself(*searchtet); // Enter the adjacent tet.
15068 
15069   if (dir == ACROSSEDGE) {
15070     // Check whether two segments are intersecting.
15071     if (issubseg(*searchtet)) {
15072       return ACROSSSEG;
15073     }
15074   } else if (dir == ACROSSFACE) {
15075     if (checksubfaceflag) {
15076       // Check whether a segment and a subface are intersecting.
15077       if (issubface(*searchtet)) {
15078         return ACROSSSUB;
15079       }
15080     }
15081   }
15082 
15083   if (refpt == nullptr) {
15084     // Do not need a reference point. Return.
15085     return dir;
15086   }
15087 
15088   triface neightet, reftet;
15089   point pa, pb, pc;
15090   REAL angmax, ang;
15091   int types[2], poss[4];
15092   int pos = 0, i, j;
15093 
15094   pa = org(*searchtet);
15095   angmax = interiorangle(pa, startpt, endpt, nullptr);
15096   *refpt = pa;
15097   pb = dest(*searchtet);
15098   ang = interiorangle(pb, startpt, endpt, nullptr);
15099   if (ang > angmax) {
15100     angmax = ang;
15101     *refpt = pb;
15102   }
15103   pc = apex(*searchtet);
15104   ang = interiorangle(pc, startpt, endpt, nullptr);
15105   if (ang > angmax) {
15106     angmax = ang;
15107     *refpt = pc;
15108   }
15109   reftet = *searchtet; // Save the tet containing the refpt.
15110 
15111   // Search intersecting faces along the segment.
15112   while (1) {
15113 
15114 
15115     pd = oppo(*searchtet);
15116     assert(pd != dummypoint);  // SELF_CHECK
15117 
15118 
15119     // Stop if we meet 'endpt'.
15120     if (pd == endpt) break;
15121 
15122     ang = interiorangle(pd, startpt, endpt, nullptr);
15123     if (ang > angmax) {
15124       angmax = ang;
15125       *refpt = pd;
15126       reftet = *searchtet;
15127     }
15128 
15129     // Find a face intersecting the segment.
15130     if (dir == ACROSSFACE) {
15131       // One of the three oppo faces in 'searchtet' intersects the segment.
15132       neightet = *searchtet;
15133       j = (neightet.ver & 3); // j is the current face number.
15134       for (i = j + 1; i < j + 4; i++) {
15135         neightet.ver = (i % 4);
15136         pa = org(neightet);
15137         pb = dest(neightet);
15138         pc = apex(neightet);
15139         pd = oppo(neightet); // The above point.
15140         if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15141           dir = (enum interresult) types[0];
15142           pos = poss[0];
15143           break;
15144         } else {
15145           dir = DISJOINT;
15146           pos = 0;
15147         }
15148       }
15149       assert(dir != DISJOINT);  // SELF_CHECK
15150     } else { // dir == ACROSSEDGE
15151       // Check the two opposite faces (of the edge) in 'searchtet'.
15152       for (i = 0; i < 2; i++) {
15153         if (i == 0) {
15154           enextesym(*searchtet, neightet);
15155         } else {
15156           eprevesym(*searchtet, neightet);
15157         }
15158         pa = org(neightet);
15159         pb = dest(neightet);
15160         pc = apex(neightet);
15161         pd = oppo(neightet); // The above point.
15162         if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15163           dir = (enum interresult) types[0];
15164           pos = poss[0];
15165           break;
15166         } else {
15167           dir = DISJOINT;
15168           pos = 0;
15169         }
15170       }
15171       if (dir == DISJOINT) {
15172         // No intersection. Rotate to the next tet at the edge.
15173         dir = ACROSSEDGE;
15174         fnextself(*searchtet);
15175         continue;
15176       }
15177     }
15178 
15179     if (dir == ACROSSVERT) {
15180       // This segment passing a vertex. Choose it and return.
15181       for (i = 0; i < pos; i++) {
15182         enextself(neightet);
15183       }
15184       pd = org(neightet);
15185       *refpt = pd;
15186       // break;
15187       return ACROSSVERT;
15188     } else if (dir == ACROSSEDGE) {
15189       // Get the edge intersects with the segment.
15190       for (i = 0; i < pos; i++) {
15191         enextself(neightet);
15192       }
15193     }
15194     // Go to the next tet.
15195     fsym(neightet, *searchtet);
15196 
15197     if (dir == ACROSSEDGE) {
15198       // Check whether two segments are intersecting.
15199       if (issubseg(*searchtet)) {
15200         return ACROSSSEG;
15201       }
15202     } else if (dir == ACROSSFACE) {
15203       if (checksubfaceflag) {
15204         // Check whether a segment and a subface are intersecting.
15205         if (issubface(*searchtet)) {
15206           return ACROSSSUB;
15207         }
15208       }
15209     }
15210 
15211   } // while (1)
15212 
15213   // A valid reference point should inside the diametrial circumsphere of
15214   //   the missing segment, i.e., it encroaches upon it.
15215   if (2.0 * angmax < PI) {
15216     *refpt = nullptr;
15217   }
15218 
15219 
15220   *searchtet = reftet;
15221   return dir;
15222 }
15223 
15224 ///////////////////////////////////////////////////////////////////////////////
15225 //                                                                           //
15226 // getsteinerpointonsegment()    Get a Steiner point on a segment.           //
15227 //                                                                           //
15228 ///////////////////////////////////////////////////////////////////////////////
15229 
getsteinerptonsegment(face * seg,point refpt,point steinpt)15230 void tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
15231 {
15232   point ei, ej;
15233   REAL Li, Lj, L;
15234   REAL t;
15235   int i;
15236 
15237   ei = sorg(*seg);
15238   ej = sdest(*seg);
15239 
15240 
15241   if (refpt != nullptr) {
15242     // Let ei be the closer one to refpt.
15243     Li = distance(ei, refpt);
15244     Lj = distance(ej, refpt);
15245     if (Li > Lj) {
15246       // Swap ei and ej;
15247       sesymself(*seg);
15248       ei = sorg(*seg);
15249       ej = sdest(*seg);
15250       L = Li;
15251       Li = Lj;
15252       Lj = L;
15253     }
15254     if (pointtype(ei) == ACUTEVERTEX) {
15255       // Cut the segment by a sphere centered at ei with radius Li.
15256       L = distance(ei, ej);
15257       t = Li / L; // t \in (0, 1).
15258       for (i = 0; i < 3; i++) {
15259         steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
15260       }
15261       // Re-use Li and Lj;
15262       Li = distance(steinpt, refpt);
15263       Lj = distance(steinpt, ej);
15264       if (Li > Lj) {
15265         // Avoid to create a very short edge at ej.
15266         t = 0.5;
15267         for (i = 0; i < 3; i++) {
15268           steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
15269         }
15270       }
15271     } else {
15272       // Cut the segment by the projection point of refpt.
15273       projpt2edge(refpt, ei, ej, steinpt);
15274       L = distance(steinpt, refpt);
15275       if ((L > distance(steinpt, ei)) || (L > distance(steinpt, ej))) {
15276         // Avoid creating a very short edge.
15277         t = 0.5;
15278         for (i = 0; i < 3; i++) {
15279           steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
15280         }
15281       }
15282     }
15283   } else {
15284     // Split the point at the middle.
15285     t = 0.5;
15286     for (i = 0; i < 3; i++) {
15287       steinpt[i] = ei[i] + t * (ej[i] - ei[i]);
15288     }
15289   } // if (refpt == nullptr)
15290 
15291   if (pointtype(steinpt) == UNUSEDVERTEX) {
15292     setpointtype(steinpt, FREESEGVERTEX);
15293   }
15294 }
15295 
15296 
15297 
15298 ///////////////////////////////////////////////////////////////////////////////
15299 //                                                                           //
15300 // delaunizesegments()    Recover segments in a DT.                          //
15301 //                                                                           //
15302 // All segments need to be recovered are in 'subsegstack' (Q).  They will be //
15303 // be recovered one by one (in a random order).                              //
15304 //                                                                           //
15305 // Given a segment s in the Q, this routine first queries s in the DT, if s  //
15306 // matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split  //
15307 // by inserting a new point p in both the DT and itself. The two new subseg- //
15308 // ments of s are queued in Q.  The process continues until Q is empty.      //
15309 //                                                                           //
15310 ///////////////////////////////////////////////////////////////////////////////
15311 
delaunizesegments()15312 void tetgenmesh::delaunizesegments()
15313 {
15314   triface searchtet, spintet;
15315   face searchsh;
15316   face sseg, *psseg;
15317   point refpt, newpt;
15318   enum interresult dir;
15319   insertvertexflags ivf;
15320   int t1ver;
15321 
15322 
15323   ivf.bowywat = 1; // Use Bowyer-Watson insertion.
15324   ivf.assignmeshsize = b->metric;
15325   ivf.sloc = (int) ONEDGE; // on 'sseg'.
15326   ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
15327 
15328   // Loop until 'subsegstack' is empty.
15329   while (subsegstack->objects > 0l) {
15330     // seglist is used as a stack.
15331     subsegstack->objects--;
15332     psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
15333     sseg = *psseg;
15334 
15335     // Check if this segment has been recovered.
15336     sstpivot1(sseg, searchtet);
15337     if (searchtet.tet != nullptr) {
15338       continue; // Not a missing segment.
15339     }
15340 
15341     // Search the segment.
15342     dir = scoutsegment(sorg(sseg), sdest(sseg), &searchtet, &refpt, nullptr);
15343 
15344     if (dir == SHAREEDGE) {
15345       // Found this segment, insert it.
15346       if (!issubseg(searchtet)) {
15347         // Let the segment remember an adjacent tet.
15348         sstbond1(sseg, searchtet);
15349         // Bond the segment to all tets containing it.
15350         spintet = searchtet;
15351         do {
15352           tssbond1(spintet, sseg);
15353           fnextself(spintet);
15354         } while (spintet.tet != searchtet.tet);
15355       } else {
15356         // Collision! Maybe a bug.
15357         assert(0);
15358       }
15359     } else {
15360       if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15361         // The segment is missing. Split it.
15362         // Create a new point.
15363         makepoint(&newpt, FREESEGVERTEX);
15364         //setpointtype(newpt, FREESEGVERTEX);
15365         getsteinerptonsegment(&sseg, refpt, newpt);
15366 
15367         // Start searching from 'searchtet'.
15368         ivf.iloc = (int) OUTSIDE;
15369         // Insert the new point into the tetrahedralization T.
15370         //   Missing segments and subfaces are queued for recovery.
15371         //   Note that T is convex (nonconvex = 0).
15372         if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
15373           // The new point has been inserted.
15374           st_segref_count++;
15375           if (steinerleft > 0) steinerleft--;
15376         } else {
15377           assert (ivf.iloc == (enum locateresult) NEARVERTEX);
15378           terminatetetgen(4);
15379         }
15380       } else {
15381         // Indicate it is an input problem.
15382         terminatetetgen(3);
15383       }
15384     }
15385   } // while
15386 }
15387 
15388 ///////////////////////////////////////////////////////////////////////////////
15389 //                                                                           //
15390 // scoutsubface()    Search subface in the tetrahedralization.               //
15391 //                                                                           //
15392 // 'searchsh' is searched in T. If it exists, it is 'locked' at the face in  //
15393 // T. 'searchtet' refers to the face. Otherwise, it is missing.              //
15394 //                                                                           //
15395 // The return value indicates one of the following cases:                    //
15396 //   - SHAREFACE, 'searchsh' exists and is inserted in T.                    //
15397 //   - COLLISIONFACE, 'searchsh' exists in T, but it conflicts with another  //
15398 //     subface which was inserted earlier. It is not inserted.               //
15399 //                                                                           //
15400 ///////////////////////////////////////////////////////////////////////////////
15401 
15402 enum tetgenmesh::interresult
scoutsubface(face * searchsh,triface * searchtet)15403   tetgenmesh::scoutsubface(face* searchsh, triface* searchtet)
15404 {
15405   triface spintet;
15406   point pa, pb, pc;
15407   enum interresult dir;
15408   int t1ver;
15409 
15410   pa = sorg(*searchsh);
15411   pb = sdest(*searchsh);
15412 
15413 
15414   // Get a tet whose origin is a.
15415   point2tetorg(pa, *searchtet);
15416   // Search the edge [a,b].
15417   dir = finddirection(searchtet, pb);
15418   if (dir == ACROSSVERT) {
15419     // Check validity of a PLC.
15420     if (dest(*searchtet) != pb) {
15421       // A vertex lies on the search edge.
15422       enextself(*searchtet);
15423       // It is possible a PLC self-intersection problem.
15424       terminatetetgen(3);
15425       return TOUCHEDGE;
15426     }
15427     // The edge exists. Check if the face exists.
15428     pc = sapex(*searchsh);
15429     // Searchtet holds edge [a,b]. Search a face with apex c.
15430     spintet = *searchtet;
15431     while (1) {
15432       if (apex(spintet) == pc) {
15433         // Found a face matching to 'searchsh'!
15434         if (!issubface(spintet)) {
15435           // Insert 'searchsh'.
15436           tsbond(spintet, *searchsh);
15437           fsymself(spintet);
15438           sesymself(*searchsh);
15439           tsbond(spintet, *searchsh);
15440           *searchtet = spintet;
15441           return SHAREFACE;
15442         } else {
15443           // Another subface is already inserted.
15444           face checksh;
15445           tspivot(spintet, checksh);
15446           assert(checksh.sh != searchsh->sh); // SELF_CHECK
15447           // This is possibly an input problem, i.e., two facets overlap.
15448           // Report this problem and exit.
15449           printf("Warning:  Found two facets nearly overlap.\n");
15450           terminatetetgen(5);
15451           // unifysubfaces(&checksh, searchsh);
15452           *searchtet = spintet;
15453           return COLLISIONFACE;
15454         }
15455       }
15456       fnextself(spintet);
15457       if (spintet.tet == searchtet->tet) break;
15458     }
15459   }
15460 
15461   // dir is either ACROSSEDGE or ACROSSFACE.
15462   return dir;
15463 }
15464 
15465 ///////////////////////////////////////////////////////////////////////////////
15466 //                                                                           //
15467 // formregion()    Form the missing region of a missing subface.             //
15468 //                                                                           //
15469 // 'missh' is a missing subface. From it we form a missing region R which is //
15470 // a connected region formed by a set of missing subfaces of a facet.        //
15471 // Comment: There should be no segment inside R.                             //
15472 //                                                                           //
15473 // 'missingshs' returns the list of subfaces in R. All subfaces in this list //
15474 // are oriented as the 'missh'.  'missingshbds' returns the list of boundary //
15475 // edges (tetrahedral handles) of R.  'missingshverts' returns all vertices  //
15476 // of R. They are all pmarktested.                                           //
15477 //                                                                           //
15478 // Except the first one (which is 'missh') in 'missingshs', each subface in  //
15479 // this list represents an internal edge of R, i.e., it is missing in the    //
15480 // tetrahedralization. Since R may contain interior vertices, not all miss-  //
15481 // ing edges can be found by this way.                                       //
15482 ///////////////////////////////////////////////////////////////////////////////
15483 
formregion(face * missh,arraypool * missingshs,arraypool * missingshbds,arraypool * missingshverts)15484 void tetgenmesh::formregion(face* missh, arraypool* missingshs,
15485                             arraypool* missingshbds, arraypool* missingshverts)
15486 {
15487   triface searchtet, spintet;
15488   face neighsh, *parysh;
15489   face neighseg, fakeseg;
15490   point pa, pb, *parypt;
15491   enum interresult dir;
15492   int t1ver;
15493   int i, j;
15494 
15495   smarktest(*missh);
15496   missingshs->newindex((void **) &parysh);
15497   *parysh = *missh;
15498 
15499   // Incrementally find other missing subfaces.
15500   for (i = 0; i < missingshs->objects; i++) {
15501     missh = (face *) fastlookup(missingshs, i);
15502     for (j = 0; j < 3; j++) {
15503       pa = sorg(*missh);
15504       pb = sdest(*missh);
15505       point2tetorg(pa, searchtet);
15506       dir = finddirection(&searchtet, pb);
15507       if (dir != ACROSSVERT) {
15508         // This edge is missing. Its neighbor is a missing subface.
15509         spivot(*missh, neighsh);
15510         if (!smarktested(neighsh)) {
15511           // Adjust the face orientation.
15512           if (sorg(neighsh) != pb) sesymself(neighsh);
15513           smarktest(neighsh);
15514           missingshs->newindex((void **) &parysh);
15515           *parysh = neighsh;
15516         }
15517       } else {
15518         if (dest(searchtet) != pb) {
15519           // This might be a self-intersection problem.
15520           terminatetetgen(3);
15521         }
15522       }
15523       // Collect the vertices of R.
15524       if (!pmarktested(pa)) {
15525         pmarktest(pa);
15526         missingshverts->newindex((void **) &parypt);
15527         *parypt = pa;
15528       }
15529       senextself(*missh);
15530     } // j
15531   } // i
15532 
15533   // Get the boundary edges of R.
15534   for (i = 0; i < missingshs->objects; i++) {
15535     missh = (face *) fastlookup(missingshs, i);
15536     for (j = 0; j < 3; j++) {
15537       spivot(*missh, neighsh);
15538       if ((neighsh.sh == nullptr) || !smarktested(neighsh)) {
15539         // A boundary edge of R.
15540         // Let the segment point to the adjacent tet.
15541         point2tetorg(sorg(*missh), searchtet);
15542         finddirection(&searchtet, sdest(*missh));
15543         missingshbds->newindex((void **) &parysh);
15544         *parysh = *missh;
15545         // Check if this edge is a segment.
15546         sspivot(*missh, neighseg);
15547         if (neighseg.sh == nullptr) {
15548           // Temporarily create a segment at this edge.
15549           makeshellface(subsegs, &fakeseg);
15550           setsorg(fakeseg, sorg(*missh));
15551           setsdest(fakeseg, sdest(*missh));
15552           sinfect(fakeseg); // Mark it as faked.
15553           // Connect it to all tets at this edge.
15554           spintet = searchtet;
15555           while (1) {
15556             tssbond1(spintet, fakeseg);
15557             fnextself(spintet);
15558             if (spintet.tet == searchtet.tet) break;
15559           }
15560           neighseg = fakeseg;
15561         }
15562         // Let the segment and the boundary edge point to each other.
15563         ssbond(*missh, neighseg);
15564         sstbond1(neighseg, searchtet);
15565       }
15566       senextself(*missh);
15567     } // j
15568   } // i
15569 
15570 
15571   // Unmarktest collected missing subfaces.
15572   for (i = 0; i < missingshs->objects; i++) {
15573     parysh = (face *) fastlookup(missingshs, i);
15574     sunmarktest(*parysh);
15575   }
15576 }
15577 
15578 ///////////////////////////////////////////////////////////////////////////////
15579 //                                                                           //
15580 // scoutcrossedge()    Search an edge that crosses the missing region.       //
15581 //                                                                           //
15582 // Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
15583 // over, the edge is oriented such that its origin lies below R.  Return 0   //
15584 // if no such edge is found.                                                 //
15585 //                                                                           //
15586 // Assumption: All vertices of the missing region are marktested.            //
15587 //                                                                           //
15588 ///////////////////////////////////////////////////////////////////////////////
15589 
scoutcrossedge(triface & crosstet,arraypool * missingshbds,arraypool * missingshs)15590 int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds,
15591                                arraypool* missingshs)
15592 {
15593   triface searchtet, spintet;
15594   face *parysh;
15595   face neighseg;
15596   point pa, pb, pc, pd, pe;
15597   enum interresult dir;
15598   REAL ori;
15599   int types[2], poss[4];
15600   int searchflag, interflag;
15601   int t1ver;
15602   int i, j;
15603 
15604   searchflag = 0;
15605 
15606   for (j = 0; j < missingshbds->objects && !searchflag; j++) {
15607     parysh = (face *) fastlookup(missingshbds, j);
15608     sspivot(*parysh, neighseg);
15609     sstpivot1(neighseg, searchtet);
15610     interflag = 0;
15611     // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
15612     spintet = searchtet;
15613     while (1) {
15614       pd = apex(spintet);
15615       pe = oppo(spintet);
15616       // Skip a hull edge.
15617       if ((pd != dummypoint) && (pe != dummypoint)) {
15618         // Skip an edge containing a vertex of R.
15619         if (!pmarktested(pd) && !pmarktested(pe)) {
15620           // Check if [d,e] intersects R.
15621           for (i = 0; i < missingshs->objects && !interflag; i++) {
15622             parysh = (face *) fastlookup(missingshs, i);
15623             pa = sorg(*parysh);
15624             pb = sdest(*parysh);
15625             pc = sapex(*parysh);
15626             interflag=tri_edge_test(pa, pb, pc, pd, pe, nullptr, 1, types, poss);
15627             if (interflag > 0) {
15628               if (interflag == 2) {
15629                 // They intersect at a single point.
15630                 dir = (enum interresult) types[0];
15631                 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15632                   //pos = poss[0];
15633                   // Go to the crossing edge [d,e,#,#].
15634                   edestoppo(spintet, crosstet); // // [d,e,#,#].
15635                   // Check if it is a segment.
15636                   if (issubseg(crosstet)) {
15637                     //face checkseg;
15638                     //tsspivot1(crosstet, checkseg);
15639                     //reportselfintersect(&checkseg, parysh);
15640                     terminatetetgen(3);
15641                   }
15642                   // Adjust the edge such that d lies below [a,b,c].
15643                   ori = orient3d(pa, pb, pc, pd);
15644                   assert(ori != 0);
15645                   if (ori < 0) {
15646                     esymself(crosstet);
15647                   }
15648                   searchflag = 1;
15649                 }
15650               }
15651               break;
15652             } // if (interflag > 0)
15653           }
15654         }
15655       }
15656       // Leave search at this bdry edge if an intersection is found.
15657       if (interflag > 0) break;
15658       // Go to the next tetrahedron.
15659       fnextself(spintet);
15660       if (spintet.tet == searchtet.tet) break;
15661     } // while (1)
15662   } // j
15663 
15664   return searchflag;
15665 }
15666 
15667 ///////////////////////////////////////////////////////////////////////////////
15668 //                                                                           //
15669 // formcavity()    Form the cavity of a missing region.                      //
15670 //                                                                           //
15671 // The missing region R is formed by a set of missing subfaces 'missingshs'. //
15672 // In the following, we assume R is horizontal and oriented. (All subfaces   //
15673 // of R are oriented in the same way.)  'searchtet' is a tetrahedron [d,e,#, //
15674 // #] which intersects R in its interior, where the edge [d,e] intersects R, //
15675 // and d lies below R.                                                       //
15676 //                                                                           //
15677 // 'crosstets' returns the set of crossing tets. Every tet in it has the     //
15678 // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R.  The   //
15679 // set of tets form the cavity C, which is divided into two parts by R, one  //
15680 // at top and one at bottom. 'topfaces' and 'botfaces' return the upper and  //
15681 // lower boundary faces of C. 'toppoints' contains vertices of 'crosstets'   //
15682 // in the top part of C, and so does 'botpoints'. Both 'toppoints' and       //
15683 // 'botpoints' contain vertices of R.                                        //
15684 //                                                                           //
15685 // Important: This routine assumes all vertices of the facet containing this //
15686 // subface are marked, i.e., pmarktested(p) returns true.                    //
15687 //                                                                           //
15688 ///////////////////////////////////////////////////////////////////////////////
15689 
formcavity(triface * searchtet,arraypool * missingshs,arraypool * crosstets,arraypool * topfaces,arraypool * botfaces,arraypool * toppoints,arraypool * botpoints)15690 bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
15691                             arraypool* crosstets, arraypool* topfaces,
15692                             arraypool* botfaces, arraypool* toppoints,
15693                             arraypool* botpoints)
15694 {
15695   arraypool *crossedges;
15696   triface spintet, neightet, *parytet;
15697   face *parysh = nullptr;
15698   point pa, pd, pe, *parypt;
15699   enum interresult dir;
15700   bool testflag, invalidflag;
15701   int types[2], poss[4];
15702   int t1ver;
15703   int i, j, k;
15704 
15705   // Temporarily re-use 'topfaces' for all crossing edges.
15706   crossedges = topfaces;
15707 
15708   if (b->verbose > 2) {
15709     printf("      Form the cavity of a missing region.\n");
15710   }
15711   // Mark this edge to avoid testing it later.
15712   markedge(*searchtet);
15713   crossedges->newindex((void **) &parytet);
15714   *parytet = *searchtet;
15715 
15716   invalidflag = 0;
15717 
15718   // Collect all crossing tets.  Each cross tet is saved in the standard
15719   //   form [d,e,#,#], where [d,e] is a corossing edge, d lies below R.
15720   //   NEITHER d NOR e is a vertex of R (!pmarktested).
15721   for (i = 0; i < crossedges->objects; i++) {
15722     // Get a crossing edge [d,e,#,#].
15723     searchtet = (triface *) fastlookup(crossedges, i);
15724 
15725     // Sort vertices into the bottom and top arrays.
15726     pd = org(*searchtet);
15727     if (!pinfected(pd)) {
15728       pinfect(pd);
15729       botpoints->newindex((void **) &parypt);
15730       *parypt = pd;
15731     }
15732     pe = dest(*searchtet);
15733     if (!pinfected(pe)) {
15734       pinfect(pe);
15735       toppoints->newindex((void **) &parypt);
15736       *parypt = pe;
15737     }
15738 
15739     // All tets sharing this edge are crossing tets.
15740     spintet = *searchtet;
15741     while (1) {
15742       if (!infected(spintet)) {
15743         infect(spintet);
15744         crosstets->newindex((void **) &parytet);
15745         *parytet = spintet;
15746       }
15747       // Go to the next crossing tet.
15748       fnextself(spintet);
15749       if (spintet.tet == searchtet->tet) break;
15750     } // while (1)
15751 
15752     // Detect new crossing edges.
15753     spintet = *searchtet;
15754     while (1) {
15755       // spintet is [d,e,a,#], where d lies below R, and e lies above R.
15756       pa = apex(spintet);
15757       if (pa != dummypoint) {
15758         if (!pmarktested(pa)) {
15759               // There exists a crossing edge, either [e,a] or [a,d]. First check
15760           //   if the crossing edge has already be added, i.e., check if a
15761           //   tetrahedron at this edge is marked.
15762           testflag = true;
15763           for (j = 0; j < 2 && testflag; j++) {
15764             if (j == 0) {
15765               enext(spintet, neightet);
15766             } else {
15767               eprev(spintet, neightet);
15768             }
15769             while (1) {
15770               if (edgemarked(neightet)) {
15771                 // This crossing edge has already been tested. Skip it.
15772                 testflag = false;
15773                 break;
15774               }
15775               fnextself(neightet);
15776               if (neightet.tet == spintet.tet) break;
15777             }
15778           } // j
15779           if (testflag) {
15780             // Test if [e,a] or [a,d] intersects R.
15781             // Do a brute-force search in the set of subfaces of R. Slow!
15782             //   Need to be improved!
15783             pd = org(spintet);
15784             pe = dest(spintet);
15785             for (k = 0; k < missingshs->objects; k++) {
15786               parysh = (face *) fastlookup(missingshs, k);
15787               if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15788                                 pe, pa, nullptr, 1, types, poss)) {
15789                 // Found intersection. 'a' lies below R.
15790                 enext(spintet, neightet);
15791                 dir = (enum interresult) types[0];
15792                 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15793                   // A valid intersection.
15794                 } else {
15795                   // A non-valid intersection. Maybe a PLC problem.
15796                   invalidflag = 1;
15797                 }
15798                 break;
15799               }
15800               if (tri_edge_test(sorg(*parysh), sdest(*parysh), sapex(*parysh),
15801                                 pa, pd, nullptr, 1, types, poss)) {
15802                 // Found intersection. 'a' lies above R.
15803                 eprev(spintet, neightet);
15804                 dir = (enum interresult) types[0];
15805                 if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15806                   // A valid intersection.
15807                 } else {
15808                   // A non-valid intersection. Maybe a PLC problem.
15809                   invalidflag = 1;
15810                 }
15811                 break;
15812               }
15813             } // k
15814             if (k < missingshs->objects) {
15815               // Found a pair of triangle - edge interseciton.
15816               if (invalidflag) {
15817                 if (!b->quiet) {
15818                   printf("Warning:  A non-valid facet - edge intersection\n");
15819                   printf("      subface: (%d, %d, %d) edge: (%d, %d)\n",
15820                          pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
15821                          pointmark(sapex(*parysh)), pointmark(org(neightet)),
15822                          pointmark(dest(neightet)));
15823                 }
15824                 // It may be a PLC problem.
15825                 terminatetetgen(3);
15826               }
15827               // Adjust the edge direction, so that its origin lies below R,
15828               //   and its destination lies above R.
15829               esymself(neightet);
15830               // Check if this edge is a segment.
15831               if (issubseg(neightet)) {
15832                 // Invalid PLC!
15833                 //face checkseg;
15834                 //tsspivot1(neightet, checkseg);
15835                 //reportselfintersect(&checkseg, parysh);
15836                 terminatetetgen(3);
15837               }
15838               // Mark this edge to avoid testing it again.
15839               markedge(neightet);
15840               crossedges->newindex((void **) &parytet);
15841               *parytet = neightet;
15842             } else {
15843               // No intersection is found. It may be a PLC problem.
15844               invalidflag = 1;
15845               // Split the subface intersecting [d,e].
15846               for (k = 0; k < missingshs->objects; k++) {
15847                 parysh = (face *) fastlookup(missingshs, k);
15848                 // Test if this face intersects [e,a].
15849                 if (tri_edge_test(sorg(*parysh),sdest(*parysh),sapex(*parysh),
15850                                   pd, pe, nullptr, 1, types, poss)) {
15851                   break;
15852                 }
15853               } // k
15854               if (k == missingshs->objects) {
15855                 // Not found such an edge.
15856                 // Arbitrarily choose an edge (except the first) to split.
15857                 k = randomnation(missingshs->objects - 1);
15858                 parysh = (face *) fastlookup(missingshs, k + 1);
15859               }
15860               recentsh = *parysh;
15861               recenttet = spintet; // For point location.
15862               break; // the while (1) loop
15863             } // if (k == missingshs->objects)
15864           } // if (testflag)
15865             } // if (!pmarktested(pa) || b->psc)
15866       } // if (pa != dummypoint)
15867       // Go to the next crossing tet.
15868       fnextself(spintet);
15869       if (spintet.tet == searchtet->tet) break;
15870     } // while (1)
15871 
15872     //if (b->psc) {
15873       if (invalidflag) break;
15874     //}
15875   } // i
15876 
15877   if (b->verbose > 2) {
15878     printf("      Formed cavity: %ld (%ld) cross tets (edges).\n",
15879            crosstets->objects, crossedges->objects);
15880   }
15881 
15882   // Unmark all marked edges.
15883   for (i = 0; i < crossedges->objects; i++) {
15884     searchtet = (triface *) fastlookup(crossedges, i);
15885     assert(edgemarked(*searchtet)); // SELF_CHECK
15886     unmarkedge(*searchtet);
15887   }
15888   crossedges->restart();
15889 
15890 
15891   if (invalidflag) {
15892     // Unmark all collected tets.
15893     for (i = 0; i < crosstets->objects; i++) {
15894       searchtet = (triface *) fastlookup(crosstets, i);
15895       uninfect(*searchtet);
15896     }
15897     // Unmark all collected vertices.
15898     for (i = 0; i < botpoints->objects; i++) {
15899       parypt = (point *) fastlookup(botpoints, i);
15900       puninfect(*parypt);
15901     }
15902     for (i = 0; i < toppoints->objects; i++) {
15903       parypt = (point *) fastlookup(toppoints, i);
15904       puninfect(*parypt);
15905     }
15906     crosstets->restart();
15907     botpoints->restart();
15908     toppoints->restart();
15909 
15910     // Randomly split an interior edge of R.
15911     i = randomnation(missingshs->objects - 1);
15912     recentsh = * (face *) fastlookup(missingshs, i);
15913     return false;
15914   }
15915 
15916 
15917   // Collect the top and bottom faces and the middle vertices. Since all top
15918   //   and bottom vertices have been infected. Uninfected vertices must be
15919   //   middle vertices (i.e., the vertices of R).
15920   // NOTE 1: Hull tets may be collected. Process them as a normal one.
15921   // NOTE 2: Some previously recovered subfaces may be completely inside the
15922   //   cavity. In such case, we remove these subfaces from the cavity and put     //   them into 'subfacstack'. They will be recovered later.
15923   // NOTE 3: Some segments may be completely inside the cavity, e.g., they
15924   //   attached to a subface which is inside the cavity. Such segments are
15925   //   put in 'subsegstack'. They will be recovered later.
15926   // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
15927   //   are identified in the routine "carvecavity()".
15928 
15929   for (i = 0; i < crosstets->objects; i++) {
15930     searchtet = (triface *) fastlookup(crosstets, i);
15931     // searchtet is [d,e,a,b].
15932     eorgoppo(*searchtet, spintet);
15933     fsym(spintet, neightet); // neightet is [a,b,e,#]
15934     if (!infected(neightet)) {
15935       // A top face.
15936       topfaces->newindex((void **) &parytet);
15937       *parytet = neightet;
15938     }
15939     edestoppo(*searchtet, spintet);
15940     fsym(spintet, neightet); // neightet is [b,a,d,#]
15941     if (!infected(neightet)) {
15942       // A bottom face.
15943       botfaces->newindex((void **) &parytet);
15944       *parytet = neightet;
15945     }
15946     // Add middle vertices if there are (skip dummypoint).
15947     pa = org(neightet);
15948     if (!pinfected(pa)) {
15949       if (pa != dummypoint) {
15950         pinfect(pa);
15951         botpoints->newindex((void **) &parypt);
15952         *parypt = pa;
15953         toppoints->newindex((void **) &parypt);
15954         *parypt = pa;
15955       }
15956     }
15957     pa = dest(neightet);
15958     if (!pinfected(pa)) {
15959       if (pa != dummypoint) {
15960         pinfect(pa);
15961         botpoints->newindex((void **) &parypt);
15962         *parypt = pa;
15963         toppoints->newindex((void **) &parypt);
15964         *parypt = pa;
15965       }
15966     }
15967   } // i
15968 
15969   // Uninfect all collected top, bottom, and middle vertices.
15970   for (i = 0; i < toppoints->objects; i++) {
15971     parypt = (point *) fastlookup(toppoints, i);
15972     puninfect(*parypt);
15973   }
15974   for (i = 0; i < botpoints->objects; i++) {
15975     parypt = (point *) fastlookup(botpoints, i);
15976     puninfect(*parypt);
15977   }
15978   cavitycount++;
15979 
15980   return true;
15981 }
15982 
15983 ///////////////////////////////////////////////////////////////////////////////
15984 //                                                                           //
15985 // delaunizecavity()    Fill a cavity by Delaunay tetrahedra.                //
15986 //                                                                           //
15987 // The cavity C to be tetrahedralized is the top or bottom part of a whole   //
15988 // cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
15989 // faces' do not form a closed polyhedron.  The "open" side are subfaces of  //
15990 // the missing facet. These faces will be recovered later in fillcavity().   //
15991 //                                                                           //
15992 // This routine first constructs the DT of the vertices. Then it identifies  //
15993 // the half boundary faces of the cavity in DT. Possiblely the cavity C will //
15994 // be enlarged.                                                              //
15995 //                                                                           //
15996 // The DT is returned in 'newtets'.                                          //
15997 //                                                                           //
15998 ///////////////////////////////////////////////////////////////////////////////
15999 
delaunizecavity(arraypool * cavpoints,arraypool * cavfaces,arraypool * cavshells,arraypool * newtets,arraypool * crosstets,arraypool * misfaces)16000 void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
16001                                  arraypool *cavshells, arraypool *newtets,
16002                                  arraypool *crosstets, arraypool *misfaces)
16003 {
16004   triface searchtet, neightet, *parytet, *parytet1;
16005   face tmpsh, *parysh;
16006   point pa, pb, pc, pd, pt[3], *parypt;
16007   enum interresult dir;
16008   insertvertexflags ivf;
16009   REAL ori;
16010   long baknum, bakhullsize;
16011   int bakchecksubsegflag, bakchecksubfaceflag;
16012   int t1ver;
16013   int i, j;
16014 
16015   if (b->verbose > 2) {
16016     printf("      Delaunizing cavity: %ld points, %ld faces.\n",
16017            cavpoints->objects, cavfaces->objects);
16018   }
16019   // Remember the current number of crossing tets. It may be enlarged later.
16020   baknum = crosstets->objects;
16021   bakhullsize = hullsize;
16022   bakchecksubsegflag = checksubsegflag;
16023   bakchecksubfaceflag = checksubfaceflag;
16024   hullsize = 0l;
16025   checksubsegflag = 0;
16026   checksubfaceflag = 0;
16027   b->verbose--;  // Suppress informations for creating Delaunay tetra.
16028   b->plc = 0; // Do not check near vertices.
16029 
16030   ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
16031 
16032   // Get four non-coplanar points (no dummypoint).
16033   pa = pb = pc = nullptr;
16034   for (i = 0; i < cavfaces->objects; i++) {
16035     parytet = (triface *) fastlookup(cavfaces, i);
16036     parytet->ver = epivot[parytet->ver];
16037     if (apex(*parytet) != dummypoint) {
16038       pa = org(*parytet);
16039       pb = dest(*parytet);
16040       pc = apex(*parytet);
16041       break;
16042     }
16043   }
16044   pd = nullptr;
16045   for (; i < cavfaces->objects; i++) {
16046     parytet = (triface *) fastlookup(cavfaces, i);
16047     pt[0] = org(*parytet);
16048     pt[1] = dest(*parytet);
16049     pt[2] = apex(*parytet);
16050     for (j = 0; j < 3; j++) {
16051       if (pt[j] != dummypoint) { // Do not include a hull point.
16052         ori = orient3d(pa, pb, pc, pt[j]);
16053         if (ori != 0) {
16054           pd = pt[j];
16055           if (ori > 0) {  // Swap pa and pb.
16056             pt[j] = pa; pa = pb; pb = pt[j];
16057           }
16058           break;
16059         }
16060       }
16061     }
16062     if (pd != nullptr) break;
16063   }
16064   assert(i < cavfaces->objects); // SELF_CHECK
16065 
16066   // Create an init DT.
16067   initialdelaunay(pa, pb, pc, pd);
16068 
16069   // Incrementally insert the vertices (duplicated vertices are ignored).
16070   for (i = 0; i < cavpoints->objects; i++) {
16071     pt[0] = * (point *) fastlookup(cavpoints, i);
16072     searchtet = recenttet;
16073     ivf.iloc = (int) OUTSIDE;
16074     insertpoint(pt[0], &searchtet, nullptr, nullptr, &ivf);
16075   }
16076 
16077   if (b->verbose > 2) {
16078     printf("      Identfying %ld boundary faces of the cavity.\n",
16079            cavfaces->objects);
16080   }
16081 
16082   while (1) {
16083 
16084     // Identify boundary faces. Mark interior tets. Save missing faces.
16085     for (i = 0; i < cavfaces->objects; i++) {
16086       parytet = (triface *) fastlookup(cavfaces, i);
16087       // Skip an interior face (due to the enlargement of the cavity).
16088       if (infected(*parytet)) continue;
16089       parytet->ver = epivot[parytet->ver];
16090       pt[0] = org(*parytet);
16091       pt[1] = dest(*parytet);
16092       pt[2] = apex(*parytet);
16093       // Create a temp subface.
16094       makeshellface(subfaces, &tmpsh);
16095       setshvertices(tmpsh, pt[0], pt[1], pt[2]);
16096       // Insert tmpsh in DT.
16097       searchtet.tet = nullptr;
16098       dir = scoutsubface(&tmpsh, &searchtet);
16099       if (dir == SHAREFACE) {
16100         // Inserted! 'tmpsh' must face toward the inside of the cavity.
16101         // Remember the boundary tet (outside the cavity) in tmpsh
16102         //   (use the adjacent tet slot).
16103         tmpsh.sh[0] = (shellface) encode(*parytet);
16104         // Save this subface.
16105         cavshells->newindex((void **) &parysh);
16106         *parysh = tmpsh;
16107       }
16108       else {
16109         // This boundary face is missing.
16110         shellfacedealloc(subfaces, tmpsh.sh);
16111         // Save this face in list.
16112         misfaces->newindex((void **) &parytet1);
16113         *parytet1 = *parytet;
16114       }
16115     } // i
16116 
16117     if (misfaces->objects > 0) {
16118       if (b->verbose > 2) {
16119         printf("      Enlarging the cavity. %ld missing bdry faces\n",
16120                misfaces->objects);
16121       }
16122 
16123       // Removing all tempoaray subfaces.
16124       for (i = 0; i < cavshells->objects; i++) {
16125         parysh = (face *) fastlookup(cavshells, i);
16126         stpivot(*parysh, neightet);
16127         tsdissolve(neightet); // Detach it from adj. tets.
16128         fsymself(neightet);
16129         tsdissolve(neightet);
16130         shellfacedealloc(subfaces, parysh->sh);
16131       }
16132       cavshells->restart();
16133 
16134       // Infect the points which are of the cavity.
16135       for (i = 0; i < cavpoints->objects; i++) {
16136         pt[0] = * (point *) fastlookup(cavpoints, i);
16137         pinfect(pt[0]); // Mark it as inserted.
16138       }
16139 
16140       // Enlarge the cavity.
16141       for (i = 0; i < misfaces->objects; i++) {
16142         // Get a missing face.
16143         parytet = (triface *) fastlookup(misfaces, i);
16144         if (!infected(*parytet)) {
16145           // Put it into crossing tet list.
16146           infect(*parytet);
16147           crosstets->newindex((void **) &parytet1);
16148           *parytet1 = *parytet;
16149           // Insert the opposite point if it is not in DT.
16150           pd = oppo(*parytet);
16151           if (!pinfected(pd)) {
16152             searchtet = recenttet;
16153             ivf.iloc = (int) OUTSIDE;
16154             insertpoint(pd, &searchtet, nullptr, nullptr, &ivf);
16155             pinfect(pd);
16156             cavpoints->newindex((void **) &parypt);
16157             *parypt = pd;
16158           }
16159           // Add three opposite faces into the boundary list.
16160           for (j = 0; j < 3; j++) {
16161             esym(*parytet, neightet);
16162             fsymself(neightet);
16163             if (!infected(neightet)) {
16164               cavfaces->newindex((void **) &parytet1);
16165               *parytet1 = neightet;
16166             }
16167             enextself(*parytet);
16168           } // j
16169         } // if (!infected(parytet))
16170       } // i
16171 
16172       // Uninfect the points which are of the cavity.
16173       for (i = 0; i < cavpoints->objects; i++) {
16174         pt[0] = * (point *) fastlookup(cavpoints, i);
16175         puninfect(pt[0]);
16176       }
16177 
16178       misfaces->restart();
16179       continue;
16180     } // if (misfaces->objects > 0)
16181 
16182     break;
16183 
16184   } // while (1)
16185 
16186   // Collect all tets of the DT. All new tets are marktested.
16187   marktest(recenttet);
16188   newtets->newindex((void **) &parytet);
16189   *parytet = recenttet;
16190   for (i = 0; i < newtets->objects; i++) {
16191     searchtet = * (triface *) fastlookup(newtets, i);
16192     for (j = 0; j < 4; j++) {
16193       decode(searchtet.tet[j], neightet);
16194       if (!marktested(neightet)) {
16195         marktest(neightet);
16196         newtets->newindex((void **) &parytet);
16197         *parytet = neightet;
16198       }
16199     }
16200   }
16201 
16202   cavpoints->restart();
16203   cavfaces->restart();
16204 
16205   if (crosstets->objects > baknum) {
16206     // The cavity has been enlarged.
16207     cavityexpcount++;
16208   }
16209 
16210   // Restore the original values.
16211   hullsize = bakhullsize;
16212   checksubsegflag = bakchecksubsegflag;
16213   checksubfaceflag = bakchecksubfaceflag;
16214   b->verbose++;
16215   b->plc = 1;
16216 }
16217 
16218 ///////////////////////////////////////////////////////////////////////////////
16219 //                                                                           //
16220 // fillcavity()    Fill new tets into the cavity.                            //
16221 //                                                                           //
16222 // The new tets are stored in two disjoint sets(which share the same facet). //
16223 // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect-  //
16224 // ively. 'midfaces' is empty on input, and will store faces in the facet.   //
16225 //                                                                           //
16226 // Important: This routine assumes all vertices of the missing region R are  //
16227 // marktested, i.e., pmarktested(p) returns true.                            //
16228 //                                                                           //
16229 ///////////////////////////////////////////////////////////////////////////////
16230 
fillcavity(arraypool * topshells,arraypool * botshells,arraypool * midfaces,arraypool * missingshs,arraypool * topnewtets,arraypool * botnewtets,triface * crossedge)16231 bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
16232                             arraypool* midfaces, arraypool* missingshs,
16233                             arraypool* topnewtets, arraypool* botnewtets,
16234                             triface* crossedge)
16235 {
16236   arraypool *cavshells;
16237   triface bdrytet, neightet, *parytet;
16238   triface searchtet, spintet;
16239   face *parysh;
16240   face checkseg;
16241   point pa, pb, pc;
16242   bool mflag;
16243   int t1ver;
16244   int i, j;
16245 
16246   // Connect newtets to tets outside the cavity.  These connections are needed
16247   //   for identifying the middle faces (which belong to R).
16248   for (j = 0; j < 2; j++) {
16249     cavshells = (j == 0 ? topshells : botshells);
16250     if (cavshells != nullptr) {
16251       for (i = 0; i < cavshells->objects; i++) {
16252         // Get a temp subface.
16253         parysh = (face *) fastlookup(cavshells, i);
16254         // Get the boundary tet outside the cavity (saved in sh[0]).
16255         decode(parysh->sh[0], bdrytet);
16256         pa = org(bdrytet);
16257         pb = dest(bdrytet);
16258         pc = apex(bdrytet);
16259         // Get the adjacent new tet inside the cavity.
16260         stpivot(*parysh, neightet);
16261         // Mark neightet as an interior tet of this cavity.
16262         infect(neightet);
16263         // Connect the two tets (the old connections are replaced).
16264         bond(bdrytet, neightet);
16265         tsdissolve(neightet); // Clear the pointer to tmpsh.
16266         // Update the point-to-tets map.
16267         setpoint2tet(pa, (tetrahedron) neightet.tet);
16268         setpoint2tet(pb, (tetrahedron) neightet.tet);
16269         setpoint2tet(pc, (tetrahedron) neightet.tet);
16270       } // i
16271     } // if (cavshells != nullptr)
16272   } // j
16273 
16274   if (crossedge != nullptr) {
16275     // Glue top and bottom tets at their common facet.
16276     triface toptet, bottet, spintet, *midface;
16277     point pd, pe;
16278     REAL ori;
16279     int types[2], poss[4];
16280     int interflag;
16281     int bflag;
16282 
16283     mflag = false;
16284     pd = org(*crossedge);
16285     pe = dest(*crossedge);
16286 
16287     // Search the first (middle) face in R.
16288     // Since R may be non-convex, we must make sure that the face is in the
16289     //   interior of R.  We search a face in 'topnewtets' whose three vertices
16290     //   are on R and it intersects 'crossedge' in its interior. Then search
16291     //   a matching face in 'botnewtets'.
16292     for (i = 0; i < topnewtets->objects && !mflag; i++) {
16293       searchtet = * (triface *) fastlookup(topnewtets, i);
16294       for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
16295         pa = org(searchtet);
16296         if (pmarktested(pa)) {
16297           pb = dest(searchtet);
16298           if (pmarktested(pb)) {
16299             pc = apex(searchtet);
16300             if (pmarktested(pc)) {
16301               // Check if this face intersects [d,e].
16302               interflag = tri_edge_test(pa,pb,pc,pd,pe,nullptr,1,types,poss);
16303               if (interflag == 2) {
16304                 // They intersect at a single point. Found.
16305                 toptet = searchtet;
16306                 // The face lies in the interior of R.
16307                 // Get the tet (in topnewtets) which lies above R.
16308                 ori = orient3d(pa, pb, pc, pd);
16309                 assert(ori != 0);
16310                 if (ori < 0) {
16311                   fsymself(toptet);
16312                   pa = org(toptet);
16313                   pb = dest(toptet);
16314                 }
16315                 // Search the face [b,a,c] in 'botnewtets'.
16316                 for (j = 0; j < botnewtets->objects; j++) {
16317                   neightet = * (triface *) fastlookup(botnewtets, j);
16318                   // Is neightet contains 'b'.
16319                   if ((point) neightet.tet[4] == pb) {
16320                     neightet.ver = 11;
16321                   } else if ((point) neightet.tet[5] == pb) {
16322                     neightet.ver = 3;
16323                   } else if ((point) neightet.tet[6] == pb) {
16324                     neightet.ver = 7;
16325                   } else if ((point) neightet.tet[7] == pb) {
16326                     neightet.ver = 0;
16327                   } else {
16328                     continue;
16329                   }
16330                   // Is the 'neightet' contains edge [b,a].
16331                   if (dest(neightet) == pa) {
16332                     // 'neightet' is just the edge.
16333                   } else if (apex(neightet) == pa) {
16334                     eprevesymself(neightet);
16335                   } else if (oppo(neightet) == pa) {
16336                     esymself(neightet);
16337                     enextself(neightet);
16338                   } else {
16339                     continue;
16340                   }
16341                   // Is 'neightet' the face [b,a,c].
16342                   if (apex(neightet) == pc) {
16343                     bottet = neightet;
16344                     mflag = true;
16345                     break;
16346                   }
16347                 } // j
16348               } // if (interflag == 2)
16349             } // pc
16350           } // pb
16351         } // pa
16352       } // toptet.ver
16353     } // i
16354 
16355     if (mflag) {
16356       // Found a pair of matched faces in 'toptet' and 'bottet'.
16357       bond(toptet, bottet);
16358       // Both are interior tets.
16359       infect(toptet);
16360       infect(bottet);
16361       // Add this face into search list.
16362       markface(toptet);
16363       midfaces->newindex((void **) &parytet);
16364       *parytet = toptet;
16365     } else {
16366       // No pair of 'toptet' and 'bottet'.
16367       toptet.tet = nullptr;
16368       // Randomly split an interior edge of R.
16369       i = randomnation(missingshs->objects - 1);
16370       recentsh = * (face *) fastlookup(missingshs, i);
16371     }
16372 
16373     // Find other middle faces, connect top and bottom tets.
16374     for (i = 0; i < midfaces->objects && mflag; i++) {
16375       // Get a matched middle face [a, b, c]
16376       midface = (triface *) fastlookup(midfaces, i);
16377       // The tet must be a new created tet (marktested).
16378       assert(marktested(*midface)); // SELF_CHECK
16379       // Check the neighbors at the edges of this face.
16380       for (j = 0; j < 3 && mflag; j++) {
16381         toptet = *midface;
16382         bflag = false;
16383         while (1) {
16384           // Go to the next face in the same tet.
16385           esymself(toptet);
16386           pc = apex(toptet);
16387           if (pmarktested(pc)) {
16388             break; // Find a subface.
16389           }
16390           if (pc == dummypoint) {
16391             assert(0); // Check this case.
16392             break; // Find a subface.
16393           }
16394           // Go to the adjacent tet.
16395           fsymself(toptet);
16396           // Do we walk outside the cavity?
16397           if (!marktested(toptet)) {
16398             // Yes, the adjacent face is not a middle face.
16399             bflag = true; break;
16400           }
16401         }
16402         if (!bflag) {
16403           // assert(marktested(toptet)); // SELF_CHECK
16404           if (!facemarked(toptet)) {
16405             fsym(*midface, bottet);
16406             spintet = bottet;
16407             while (1) {
16408               esymself(bottet);
16409               pd = apex(bottet);
16410               if (pd == pc) break; // Face matched.
16411               fsymself(bottet);
16412               if (bottet.tet == spintet.tet) {
16413                 // Not found a matched bottom face.
16414                 mflag = false;
16415                 break;
16416               }
16417             } // while (1)
16418             if (mflag) {
16419               if (marktested(bottet)) {
16420                 // Connect two tets together.
16421                 bond(toptet, bottet);
16422                 // Both are interior tets.
16423                 infect(toptet);
16424                 infect(bottet);
16425                 // Add this face into list.
16426                 markface(toptet);
16427                 midfaces->newindex((void **) &parytet);
16428                 *parytet = toptet;
16429               }
16430             } else { // mflag == false
16431               // Adjust 'toptet' and 'bottet' to be the crossing edges.
16432               fsym(*midface, bottet);
16433               spintet = bottet;
16434               while (1) {
16435                 esymself(bottet);
16436                 pd = apex(bottet);
16437                 if (pmarktested(pd)) {
16438                   // assert(pd != pc);
16439                   // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
16440                   // Adjust 'toptet' and 'bottet' to be the crossing edges.
16441                   // Test orient3d(b,c,#,d).
16442                   ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
16443                   if (ori < 0) {
16444                     // Edges [a,d] and [b,c] cross each other.
16445                     enextself(toptet); // [b,c]
16446                     enextself(bottet); // [a,d]
16447                   } else if (ori > 0) {
16448                     // Edges [a,c] and [b,d] cross each other.
16449                     eprevself(toptet); // [c,a]
16450                     eprevself(bottet); // [d,b]
16451                   } else {
16452                     // b,c,#,and d are coplanar!.
16453                     assert(0);
16454                   }
16455                   break; // Not matched
16456                 }
16457                 fsymself(bottet);
16458                 assert (bottet.tet != spintet.tet);
16459               }
16460             } // if (!mflag)
16461           } // if (!facemarked(toptet))
16462         } // if (!bflag)
16463         enextself(*midface);
16464       } // j
16465     } // i
16466 
16467     if (mflag) {
16468       if (b->verbose > 2) {
16469         printf("      Found %ld middle subfaces.\n", midfaces->objects);
16470       }
16471       face oldsh, newsh, casout, casin, neighsh;
16472 
16473       oldsh = * (face *) fastlookup(missingshs, 0);
16474 
16475       // Create new subfaces to fill the region R.
16476       for (i = 0; i < midfaces->objects; i++) {
16477         // Get a matched middle face [a, b, c]
16478         midface = (triface *) fastlookup(midfaces, i);
16479         unmarkface(*midface);
16480         makeshellface(subfaces, &newsh);
16481         setsorg(newsh, org(*midface));
16482         setsdest(newsh, dest(*midface));
16483         setsapex(newsh, apex(*midface));
16484         // The new subface gets its markers from the old one.
16485         setshellmark(newsh, shellmark(oldsh));
16486         if (checkconstraints) {
16487           setareabound(newsh, areabound(oldsh));
16488         }
16489         // Connect the new subface to adjacent tets.
16490         tsbond(*midface, newsh);
16491         fsym(*midface, neightet);
16492         sesymself(newsh);
16493         tsbond(neightet, newsh);
16494       }
16495 
16496       // Connect new subfaces together and to the bdry of R.
16497       // Delete faked segments.
16498       for (i = 0; i < midfaces->objects; i++) {
16499         // Get a matched middle face [a, b, c]
16500         midface = (triface *) fastlookup(midfaces, i);
16501         for (j = 0; j < 3; j++) {
16502           tspivot(*midface, newsh);
16503           spivot(newsh, casout);
16504           if (casout.sh == nullptr) {
16505             // Search its neighbor.
16506             fnext(*midface, searchtet);
16507             while (1) {
16508               // (1) First check if this side is a bdry edge of R.
16509               tsspivot1(searchtet, checkseg);
16510               if (checkseg.sh != nullptr) {
16511                 // It's a bdry edge of R.
16512                 assert(!infected(searchtet)); // It must not be a cavity tet.
16513                 // Get the old subface.
16514                 checkseg.shver = 0;
16515                 spivot(checkseg, oldsh);
16516                 if (sinfected(checkseg)) {
16517                   // It's a faked segment. Delete it.
16518                   spintet = searchtet;
16519                   while (1) {
16520                     tssdissolve1(spintet);
16521                     fnextself(spintet);
16522                     if (spintet.tet == searchtet.tet) break;
16523                   }
16524                   shellfacedealloc(subsegs, checkseg.sh);
16525                   ssdissolve(oldsh);
16526                   checkseg.sh = nullptr;
16527                 }
16528                 spivot(oldsh, casout);
16529                 if (casout.sh != nullptr) {
16530                   casin = casout;
16531                   if (checkseg.sh != nullptr) {
16532                     // Make sure that the subface has the right ori at the
16533                     //   segment.
16534                     checkseg.shver = 0;
16535                     if (sorg(newsh) != sorg(checkseg)) {
16536                       sesymself(newsh);
16537                     }
16538                     spivot(casin, neighsh);
16539                     while (neighsh.sh != oldsh.sh) {
16540                       casin = neighsh;
16541                       spivot(casin, neighsh);
16542                     }
16543                   }
16544                   sbond1(newsh, casout);
16545                   sbond1(casin, newsh);
16546                 }
16547                 if (checkseg.sh != nullptr) {
16548                   ssbond(newsh, checkseg);
16549                 }
16550                 break;
16551               } // if (checkseg.sh != nullptr)
16552               // (2) Second check if this side is an interior edge of R.
16553               tspivot(searchtet, neighsh);
16554               if (neighsh.sh != nullptr) {
16555                 // Found an adjacent subface of newsh (an interior edge).
16556                 sbond(newsh, neighsh);
16557                 break;
16558               }
16559               fnextself(searchtet);
16560               assert(searchtet.tet != midface->tet);
16561             } // while (1)
16562           } // if (casout.sh == nullptr)
16563           enextself(*midface);
16564         } // j
16565       } // i
16566 
16567       // Delete old subfaces.
16568       for (i = 0; i < missingshs->objects; i++) {
16569         parysh = (face *) fastlookup(missingshs, i);
16570         shellfacedealloc(subfaces, parysh->sh);
16571       }
16572     } else {
16573       if (toptet.tet != nullptr) {
16574         // Faces at top and bottom are not matched.
16575         // Choose a Steiner point in R.
16576         // Split one of the crossing edges.
16577         pa = org(toptet);
16578         pb = dest(toptet);
16579         pc = org(bottet);
16580         pd = dest(bottet);
16581         // Search an edge in R which is either [a,b] or [c,d].
16582         // Reminder:  Subfaces in this list 'missingshs', except the first
16583         //   one, represents an interior edge of R.
16584         for (i = 1; i < missingshs->objects; i++) {
16585           parysh = (face *) fastlookup(missingshs, i);
16586           if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
16587               ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
16588           if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
16589               ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
16590         }
16591         if (i < missingshs->objects) {
16592           // Found. Return it.
16593           recentsh = *parysh;
16594         } else {
16595           assert(0);
16596         }
16597       }
16598     }
16599 
16600     midfaces->restart();
16601   } else {
16602     mflag = true;
16603   }
16604 
16605   // Delete the temp subfaces.
16606   for (j = 0; j < 2; j++) {
16607     cavshells = (j == 0 ? topshells : botshells);
16608     if (cavshells != nullptr) {
16609       for (i = 0; i < cavshells->objects; i++) {
16610         parysh = (face *) fastlookup(cavshells, i);
16611         shellfacedealloc(subfaces, parysh->sh);
16612       }
16613     }
16614   }
16615 
16616   topshells->restart();
16617   if (botshells != nullptr) {
16618     botshells->restart();
16619   }
16620 
16621   return mflag;
16622 }
16623 
16624 ///////////////////////////////////////////////////////////////////////////////
16625 //                                                                           //
16626 // carvecavity()    Delete old tets and outer new tets of the cavity.        //
16627 //                                                                           //
16628 ///////////////////////////////////////////////////////////////////////////////
16629 
carvecavity(arraypool * crosstets,arraypool * topnewtets,arraypool * botnewtets)16630 void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
16631                              arraypool *botnewtets)
16632 {
16633   arraypool *newtets;
16634   shellface *sptr, *ssptr;
16635   triface *parytet, *pnewtet, newtet, neightet, spintet;
16636   face checksh, *parysh;
16637   face checkseg, *paryseg;
16638   int t1ver;
16639   int i, j;
16640 
16641   if (b->verbose > 2) {
16642     printf("      Carve cavity: %ld old tets.\n", crosstets->objects);
16643   }
16644 
16645   // First process subfaces and segments which are adjacent to the cavity.
16646   //   They must be re-connected to new tets in the cavity.
16647   // Comment: It is possible that some subfaces and segments are completely
16648   //   inside the cavity. This can happen even if the cavity is not enlarged.
16649   //   Before deleting the old tets, find and queue all interior subfaces
16650   //   and segments. They will be recovered later. 2010-05-06.
16651 
16652   // Collect all subfaces and segments which attached to the old tets.
16653   for (i = 0; i < crosstets->objects; i++) {
16654     parytet = (triface *) fastlookup(crosstets, i);
16655     if ((sptr = (shellface*) parytet->tet[9]) != nullptr) {
16656       for (j = 0; j < 4; j++) {
16657         if (sptr[j]) {
16658           sdecode(sptr[j], checksh);
16659           if (!sinfected(checksh)) {
16660             sinfect(checksh);
16661             cavetetshlist->newindex((void **) &parysh);
16662             *parysh = checksh;
16663           }
16664         }
16665       } // j
16666     }
16667     if ((ssptr = (shellface*) parytet->tet[8]) != nullptr) {
16668       for (j = 0; j < 6; j++) {
16669         if (ssptr[j]) {
16670           sdecode(ssptr[j], checkseg);
16671           // Skip a deleted segment (was a faked segment)
16672           if (checkseg.sh[3] != nullptr) {
16673             if (!sinfected(checkseg)) {
16674               sinfect(checkseg);
16675               cavetetseglist->newindex((void **) &paryseg);
16676               *paryseg = checkseg;
16677             }
16678           }
16679         }
16680       } // j
16681     }
16682   } // i
16683 
16684   // Uninfect collected subfaces.
16685   for (i = 0; i < cavetetshlist->objects; i++) {
16686     parysh = (face *) fastlookup(cavetetshlist, i);
16687     suninfect(*parysh);
16688   }
16689   // Uninfect collected segments.
16690   for (i = 0; i < cavetetseglist->objects; i++) {
16691     paryseg = (face *) fastlookup(cavetetseglist, i);
16692     suninfect(*paryseg);
16693   }
16694 
16695   // Connect subfaces to new tets.
16696   for (i = 0; i < cavetetshlist->objects; i++) {
16697     parysh = (face *) fastlookup(cavetetshlist, i);
16698     // Get an adjacent tet at this subface.
16699     stpivot(*parysh, neightet);
16700     // Does this tet lie inside the cavity.
16701     if (infected(neightet)) {
16702       // Yes. Get the other adjacent tet at this subface.
16703       sesymself(*parysh);
16704       stpivot(*parysh, neightet);
16705       // Does this tet lie inside the cavity.
16706       if (infected(neightet)) {
16707         checksh = *parysh;
16708         stdissolve(checksh);
16709         caveencshlist->newindex((void **) &parysh);
16710         *parysh = checksh;
16711       }
16712     }
16713     if (!infected(neightet)) {
16714       // Found an outside tet. Re-connect this subface to a new tet.
16715       fsym(neightet, newtet);
16716       assert(marktested(newtet)); // It's a new tet.
16717       sesymself(*parysh);
16718       tsbond(newtet, *parysh);
16719     }
16720   } // i
16721 
16722 
16723   for (i = 0; i < cavetetseglist->objects; i++) {
16724     checkseg = * (face *) fastlookup(cavetetseglist, i);
16725     // Check if the segment is inside the cavity.
16726     sstpivot1(checkseg, neightet);
16727     spintet = neightet;
16728     while (1) {
16729       if (!infected(spintet)) {
16730         // This segment is on the boundary of the cavity.
16731         break;
16732       }
16733       fnextself(spintet);
16734       if (spintet.tet == neightet.tet) {
16735         sstdissolve1(checkseg);
16736         caveencseglist->newindex((void **) &paryseg);
16737         *paryseg = checkseg;
16738         break;
16739       }
16740     }
16741     if (!infected(spintet)) {
16742       // A boundary segment. Connect this segment to the new tets.
16743       sstbond1(checkseg, spintet);
16744       neightet = spintet;
16745       while (1) {
16746         tssbond1(spintet, checkseg);
16747         fnextself(spintet);
16748         if (spintet.tet == neightet.tet) break;
16749       }
16750     }
16751   } // i
16752 
16753 
16754   cavetetshlist->restart();
16755   cavetetseglist->restart();
16756 
16757   // Delete the old tets in cavity.
16758   for (i = 0; i < crosstets->objects; i++) {
16759     parytet = (triface *) fastlookup(crosstets, i);
16760     if (ishulltet(*parytet)) {
16761       hullsize--;
16762     }
16763     tetrahedrondealloc(parytet->tet);
16764   }
16765 
16766   crosstets->restart(); // crosstets will be re-used.
16767 
16768   // Collect new tets in cavity.  Some new tets have already been found
16769   //   (and infected) in the fillcavity(). We first collect them.
16770   for (j = 0; j < 2; j++) {
16771     newtets = (j == 0 ? topnewtets : botnewtets);
16772     if (newtets != nullptr) {
16773       for (i = 0; i < newtets->objects; i++) {
16774         parytet = (triface *) fastlookup(newtets, i);
16775         if (infected(*parytet)) {
16776           crosstets->newindex((void **) &pnewtet);
16777           *pnewtet = *parytet;
16778         }
16779       } // i
16780     }
16781   } // j
16782 
16783   // Now we collect all new tets in cavity.
16784   for (i = 0; i < crosstets->objects; i++) {
16785     parytet = (triface *) fastlookup(crosstets, i);
16786     for (j = 0; j < 4; j++) {
16787       decode(parytet->tet[j], neightet);
16788       if (marktested(neightet)) { // Is it a new tet?
16789         if (!infected(neightet)) {
16790           // Find an interior tet.
16791           //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
16792           infect(neightet);
16793           crosstets->newindex((void **) &pnewtet);
16794           *pnewtet = neightet;
16795         }
16796       }
16797     } // j
16798   } // i
16799 
16800   parytet = (triface *) fastlookup(crosstets, 0);
16801   recenttet = *parytet; // Remember a live handle.
16802 
16803   // Delete outer new tets.
16804   for (j = 0; j < 2; j++) {
16805     newtets = (j == 0 ? topnewtets : botnewtets);
16806     if (newtets != nullptr) {
16807       for (i = 0; i < newtets->objects; i++) {
16808         parytet = (triface *) fastlookup(newtets, i);
16809         if (infected(*parytet)) {
16810           // This is an interior tet.
16811           uninfect(*parytet);
16812           unmarktest(*parytet);
16813           if (ishulltet(*parytet)) {
16814             hullsize++;
16815           }
16816         } else {
16817           // An outer tet. Delete it.
16818           tetrahedrondealloc(parytet->tet);
16819         }
16820       }
16821     }
16822   }
16823 
16824   crosstets->restart();
16825   topnewtets->restart();
16826   if (botnewtets != nullptr) {
16827     botnewtets->restart();
16828   }
16829 }
16830 
16831 ///////////////////////////////////////////////////////////////////////////////
16832 //                                                                           //
16833 // restorecavity()    Reconnect old tets and delete new tets of the cavity.  //
16834 //                                                                           //
16835 ///////////////////////////////////////////////////////////////////////////////
16836 
restorecavity(arraypool * crosstets,arraypool * topnewtets,arraypool * botnewtets,arraypool * missingshbds)16837 void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
16838                                arraypool *botnewtets, arraypool *missingshbds)
16839 {
16840   triface *parytet, neightet, spintet;
16841   face *parysh;
16842   face checkseg;
16843   point *ppt;
16844   int t1ver;
16845   int i, j;
16846 
16847   // Reconnect crossing tets to cavity boundary.
16848   for (i = 0; i < crosstets->objects; i++) {
16849     parytet = (triface *) fastlookup(crosstets, i);
16850     assert(infected(*parytet)); // SELF_CHECK
16851     parytet->ver = 0;
16852     for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
16853       fsym(*parytet, neightet);
16854       if (!infected(neightet)) {
16855         // Restore the old connections of tets.
16856         bond(*parytet, neightet);
16857       }
16858     }
16859     // Update the point-to-tet map.
16860     parytet->ver = 0;
16861     ppt = (point *) &(parytet->tet[4]);
16862     for (j = 0; j < 4; j++) {
16863       setpoint2tet(ppt[j], encode(*parytet));
16864     }
16865   }
16866 
16867   // Uninfect all crossing tets.
16868   for (i = 0; i < crosstets->objects; i++) {
16869     parytet = (triface *) fastlookup(crosstets, i);
16870     uninfect(*parytet);
16871   }
16872 
16873   // Remember a live handle.
16874   recenttet = * (triface *) fastlookup(crosstets, 0);
16875 
16876   // Delete faked segments.
16877   for (i = 0; i < missingshbds->objects; i++) {
16878     parysh = (face *) fastlookup(missingshbds, i);
16879     sspivot(*parysh, checkseg);
16880     assert(checkseg.sh != nullptr);
16881     if (checkseg.sh[3] != nullptr) {
16882       if (sinfected(checkseg)) {
16883             // It's a faked segment. Delete it.
16884         sstpivot1(checkseg, neightet);
16885         spintet = neightet;
16886         while (1) {
16887           tssdissolve1(spintet);
16888           fnextself(spintet);
16889           if (spintet.tet == neightet.tet) break;
16890         }
16891         shellfacedealloc(subsegs, checkseg.sh);
16892         ssdissolve(*parysh);
16893         //checkseg.sh = nullptr;
16894       }
16895     }
16896   } // i
16897 
16898   // Delete new tets.
16899   for (i = 0; i < topnewtets->objects; i++) {
16900     parytet = (triface *) fastlookup(topnewtets, i);
16901     tetrahedrondealloc(parytet->tet);
16902   }
16903 
16904   if (botnewtets != nullptr) {
16905     for (i = 0; i < botnewtets->objects; i++) {
16906       parytet = (triface *) fastlookup(botnewtets, i);
16907       tetrahedrondealloc(parytet->tet);
16908     }
16909   }
16910 
16911   crosstets->restart();
16912   topnewtets->restart();
16913   if (botnewtets != nullptr) {
16914     botnewtets->restart();
16915   }
16916 }
16917 
16918 ///////////////////////////////////////////////////////////////////////////////
16919 //                                                                           //
16920 // flipcertify()    Insert a crossing face into priority queue.              //
16921 //                                                                           //
16922 // A crossing face of a facet must have at least one top and one bottom ver- //
16923 // tex of the facet.                                                         //
16924 //                                                                           //
16925 ///////////////////////////////////////////////////////////////////////////////
16926 
flipcertify(triface * chkface,badface ** pqueue,point plane_pa,point plane_pb,point plane_pc)16927 void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
16928                              point plane_pb, point plane_pc)
16929 {
16930   badface *parybf, *prevbf, *nextbf;
16931   triface neightet;
16932   face checksh;
16933   point p[5];
16934   REAL w[5];
16935   REAL insph, ori4;
16936   int topi, boti;
16937   int i;
16938 
16939   // Compute the flip time \tau.
16940   fsym(*chkface, neightet);
16941 
16942   p[0] = org(*chkface);
16943   p[1] = dest(*chkface);
16944   p[2] = apex(*chkface);
16945   p[3] = oppo(*chkface);
16946   p[4] = oppo(neightet);
16947 
16948   // Check if the face is a crossing face.
16949   topi = boti = 0;
16950   for (i = 0; i < 3; i++) {
16951     if (pmarktest2ed(p[i])) topi++;
16952     if (pmarktest3ed(p[i])) boti++;
16953   }
16954   if ((topi == 0) || (boti == 0)) {
16955     // It is not a crossing face.
16956     // return;
16957     for (i = 3; i < 5; i++) {
16958       if (pmarktest2ed(p[i])) topi++;
16959       if (pmarktest3ed(p[i])) boti++;
16960     }
16961     if ((topi == 0) || (boti == 0)) {
16962       // The two tets sharing at this face are on one side of the facet.
16963       // Check if this face is locally Delaunay (due to rounding error).
16964       if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
16965         // Do not check it if it is a subface.
16966         tspivot(*chkface, checksh);
16967         if (checksh.sh == nullptr) {
16968           insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
16969           assert(insph != 0);
16970           if (insph > 0) {
16971             // Add the face into queue.
16972             if (b->verbose > 2) {
16973               printf("      A locally non-Delanay face (%d, %d, %d)-%d,%d\n",
16974                      pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
16975                      pointmark(p[3]), pointmark(p[4]));
16976             }
16977             parybf = (badface *) flippool->alloc();
16978             parybf->key = 0.;  // tau = 0, do immediately.
16979             parybf->tt = *chkface;
16980             parybf->forg = p[0];
16981             parybf->fdest = p[1];
16982             parybf->fapex = p[2];
16983             parybf->foppo = p[3];
16984             parybf->noppo = p[4];
16985             // Add it at the top of the priority queue.
16986             if (*pqueue == nullptr) {
16987               *pqueue = parybf;
16988               parybf->nextitem = nullptr;
16989             } else {
16990               parybf->nextitem = *pqueue;
16991               *pqueue = parybf;
16992             }
16993           } // if (insph > 0)
16994         } // if (checksh.sh == nullptr)
16995       }
16996       //return;
16997     }
16998     return; // Test: omit this face.
16999   }
17000 
17001   // Decide the "height" for each point.
17002   for (i = 0; i < 5; i++) {
17003     if (pmarktest2ed(p[i])) {
17004       // A top point has a positive weight.
17005       w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);
17006       if (w[i] < 0) w[i] = -w[i];
17007       assert(w[i] != 0);
17008     } else {
17009       w[i] = 0;
17010     }
17011   }
17012 
17013   // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
17014   //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
17015   //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
17016   //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
17017   //     p[4] lies below the oriented hyperplane passing through
17018   //     p[1], p[0], p[2], p[3].
17019 
17020   insph = insphere(p[1], p[0], p[2], p[3], p[4]);
17021   ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
17022 
17023   if (b->verbose > 2) {
17024     printf("      Heights: (%g, %g, %g, %g, %g)\n", w[0],w[1],w[2],w[3],w[4]);
17025     printf("      Insph: %g, ori4: %g, tau = %g\n", insph, ori4, -insph/ori4);
17026   }
17027 
17028   if (ori4 > 0) {
17029     // Add the face into queue.
17030     if (b->verbose > 2) {
17031       printf("      Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
17032         pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
17033     }
17034 
17035     parybf = (badface *) flippool->alloc();
17036 
17037     parybf->key = -insph / ori4;
17038     parybf->tt = *chkface;
17039     parybf->forg = p[0];
17040     parybf->fdest = p[1];
17041     parybf->fapex = p[2];
17042     parybf->foppo = p[3];
17043     parybf->noppo = p[4];
17044 
17045     // Push the face into priority queue.
17046     //pq.push(bface);
17047     if (*pqueue == nullptr) {
17048       *pqueue = parybf;
17049       parybf->nextitem = nullptr;
17050     } else {
17051       // Search an item whose key is larger or equal to current key.
17052       prevbf = nullptr;
17053       nextbf = *pqueue;
17054       //if (!b->flipinsert_random) { // Default use a priority queue.
17055         // Insert the item into priority queue.
17056         while (nextbf != nullptr) {
17057           if (nextbf->key < parybf->key) {
17058             prevbf = nextbf;
17059             nextbf = nextbf->nextitem;
17060           } else {
17061             break;
17062           }
17063         }
17064       //} // if (!b->flipinsert_random)
17065       // Insert the new item between prev and next items.
17066       if (prevbf == nullptr) {
17067         *pqueue = parybf;
17068       } else {
17069         prevbf->nextitem = parybf;
17070       }
17071       parybf->nextitem = nextbf;
17072     }
17073   } else if (ori4 == 0) {
17074 
17075   }
17076 }
17077 
17078 ///////////////////////////////////////////////////////////////////////////////
17079 //                                                                           //
17080 // flipinsertfacet()    Insert a facet into a CDT by flips.                  //
17081 //                                                                           //
17082 // The algorithm is described in Shewchuk's paper "Updating and Constructing //
17083 // Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
17084 // Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003.                     //
17085 //                                                                           //
17086 // 'crosstets' contains the set of crossing tetrahedra (infected) of the     //
17087 // facet.  'toppoints' and 'botpoints' are points lies above and below the   //
17088 // facet, not on the facet.                                                  //
17089 //                                                                           //
17090 ///////////////////////////////////////////////////////////////////////////////
17091 
flipinsertfacet(arraypool * crosstets,arraypool * toppoints,arraypool * botpoints,arraypool * midpoints)17092 void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
17093                                  arraypool *botpoints, arraypool *midpoints)
17094 {
17095   arraypool *crossfaces, *bfacearray;
17096   triface fliptets[6], baktets[2], fliptet, newface;
17097   triface neightet, *parytet;
17098   face checksh;
17099   face checkseg;
17100   badface *pqueue;
17101   badface *popbf, bface;
17102   point plane_pa, plane_pb, plane_pc;
17103   point p1, p2, pd, pe;
17104   point *parypt;
17105   flipconstraints fc;
17106   REAL ori[3];
17107   int convcount, copcount;
17108   int flipflag, fcount;
17109   int n, i;
17110   long f23count, f32count, f44count;
17111   long totalfcount;
17112 
17113   f23count = flip23count;
17114   f32count = flip32count;
17115   f44count = flip44count;
17116 
17117   // Get three affinely independent vertices in the missing region R.
17118   calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
17119 
17120   // Mark top and bottom points. Do not mark midpoints.
17121   for (i = 0; i < toppoints->objects; i++) {
17122     parypt = (point *) fastlookup(toppoints, i);
17123     if (!pmarktested(*parypt)) {
17124       pmarktest2(*parypt);
17125     }
17126   }
17127   for (i = 0; i < botpoints->objects; i++) {
17128     parypt = (point *) fastlookup(botpoints, i);
17129     if (!pmarktested(*parypt)) {
17130       pmarktest3(*parypt);
17131     }
17132   }
17133 
17134   // Collect crossing faces.
17135   crossfaces = cavetetlist;  // Re-use array 'cavetetlist'.
17136 
17137   // Each crossing face contains at least one bottom vertex and
17138   //   one top vertex.
17139   for (i = 0; i < crosstets->objects; i++) {
17140     parytet = (triface *) fastlookup(crosstets, i);
17141     fliptet = *parytet;
17142     for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
17143       fsym(fliptet, neightet);
17144       if (infected(neightet)) { // It is an interior face.
17145         if (!marktested(neightet)) { // It is an unprocessed face.
17146           crossfaces->newindex((void **) &parytet);
17147           *parytet = fliptet;
17148         }
17149       }
17150     }
17151     marktest(fliptet);
17152   }
17153 
17154   if (b->verbose > 1) {
17155     printf("    Found %ld crossing faces.\n", crossfaces->objects);
17156   }
17157 
17158   for (i = 0; i < crosstets->objects; i++) {
17159     parytet = (triface *) fastlookup(crosstets, i);
17160     unmarktest(*parytet);
17161     uninfect(*parytet);
17162   }
17163 
17164   // Initialize the priority queue.
17165   pqueue = nullptr;
17166 
17167   for (i = 0; i < crossfaces->objects; i++) {
17168     parytet = (triface *) fastlookup(crossfaces, i);
17169     flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17170   }
17171   crossfaces->restart();
17172 
17173   // The list for temporarily storing unflipable faces.
17174   bfacearray = new arraypool(sizeof(triface), 4);
17175 
17176 
17177   fcount = 0;  // Count the number of flips.
17178 
17179   // Flip insert the facet.
17180   while (pqueue != nullptr) {
17181 
17182     // Pop a face from the priotity queue.
17183     popbf = pqueue;
17184     bface = *popbf;
17185 
17186     // Update the queue.
17187     pqueue = pqueue->nextitem;
17188 
17189     // Delete the popped item from the pool.
17190     flippool->dealloc((void *) popbf);
17191 
17192     if (!isdeadtet(bface.tt)) {
17193       if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
17194           (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
17195         // It is still a crossing face of R.
17196         fliptet = bface.tt;
17197         fsym(fliptet, neightet);
17198         assert(!isdeadtet(neightet));
17199         if (oppo(neightet) == bface.noppo) {
17200           pd = oppo(fliptet);
17201           pe = oppo(neightet);
17202 
17203           if (b->verbose > 2) {
17204             printf("      Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17205                    pointmark(bface.forg), pointmark(bface.fdest),
17206                    pointmark(bface.fapex), pointmark(bface.foppo),
17207                    pointmark(bface.noppo), bface.key);
17208           }
17209           flipflag = 0;
17210 
17211           // Check for which type of flip can we do.
17212           convcount = 3;
17213           copcount = 0;
17214           for (i = 0; i < 3; i++) {
17215             p1 = org(fliptet);
17216             p2 = dest(fliptet);
17217             ori[i] = orient3d(p1, p2, pd, pe);
17218             if (ori[i] < 0) {
17219               convcount--;
17220               //break;
17221             } else if (ori[i] == 0) {
17222               convcount--; // Possible 4-to-4 flip.
17223               copcount++;
17224               //break;
17225             }
17226             enextself(fliptet);
17227           }
17228 
17229           if (convcount == 3) {
17230             // A 2-to-3 flip is found.
17231             // The face should not be a subface.
17232             tspivot(fliptet, checksh);
17233             assert(checksh.sh == nullptr);
17234 
17235             fliptets[0] = fliptet; // abcd, d may be the new vertex.
17236             fliptets[1] = neightet; // bace.
17237             flip23(fliptets, 1, &fc);
17238             // Put the link faces into check list.
17239             for (i = 0; i < 3; i++) {
17240               eprevesym(fliptets[i], newface);
17241               crossfaces->newindex((void **) &parytet);
17242               *parytet = newface;
17243             }
17244             for (i = 0; i < 3; i++) {
17245               enextesym(fliptets[i], newface);
17246               crossfaces->newindex((void **) &parytet);
17247               *parytet = newface;
17248             }
17249             flipflag = 1;
17250           } else if (convcount == 2) {
17251             assert(copcount <= 1);
17252             //if (copcount <= 1) {
17253             // A 3-to-2 or 4-to-4 may be possible.
17254             // Get the edge which is locally non-convex or flat.
17255             for (i = 0; i < 3; i++) {
17256               if (ori[i] <= 0) break;
17257               enextself(fliptet);
17258             }
17259             // The edge should not be a segment.
17260             tsspivot1(fliptet, checkseg);
17261             assert(checkseg.sh == nullptr);
17262 
17263             // Collect tets sharing at this edge.
17264             // NOTE: This operation may collect tets which lie outside the
17265             //   cavity, e.g., when the edge lies on the boundary of the
17266             //   cavity. Do not flip if there are outside tets at this edge.
17267             //   2012-07-27.
17268             esym(fliptet, fliptets[0]); // [b,a,d,c]
17269             n = 0;
17270             do {
17271               p1 = apex(fliptets[n]);
17272               if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
17273                 // This apex is not on the cavity. Hence the face does not
17274                 //   lie inside the cavity. Do not flip this edge.
17275                 n = 1000; break;
17276               }
17277               fnext(fliptets[n], fliptets[n + 1]);
17278               n++;
17279             } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
17280 
17281             if (n == 3) {
17282               // Found a 3-to-2 flip.
17283               flip32(fliptets, 1, &fc);
17284               // Put the link faces into check list.
17285               for (i = 0; i < 3; i++) {
17286                 esym(fliptets[0], newface);
17287                 crossfaces->newindex((void **) &parytet);
17288                 *parytet = newface;
17289                 enextself(fliptets[0]);
17290               }
17291               for (i = 0; i < 3; i++) {
17292                 esym(fliptets[1], newface);
17293                 crossfaces->newindex((void **) &parytet);
17294                 *parytet = newface;
17295                 enextself(fliptets[1]);
17296               }
17297               flipflag = 1;
17298             } else if (n == 4) {
17299               if (copcount == 1) {
17300                 // Found a 4-to-4 flip.
17301                 // Let the six vertices are: a,b,c,d,e,f, where
17302                 //   fliptets[0] = [b,a,d,c]
17303                 //           [1] = [b,a,c,e]
17304                 //           [2] = [b,a,e,f]
17305                 //           [3] = [b,a,f,d]
17306                 // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
17307                 //   is created.
17308                 // First do a 2-to-3 flip.
17309                 // Comment: This flip temporarily creates a degenerated
17310                 //   tet (whose volume is zero). It will be removed by the
17311                 //   followed 3-to-2 flip.
17312                 fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
17313                 // fliptets[1];        // = [b,a,c,e].
17314                 baktets[0] = fliptets[2]; // = [b,a,e,f]
17315                 baktets[1] = fliptets[3]; // = [b,a,f,d]
17316                 // The flip may involve hull tets.
17317                 flip23(fliptets, 1, &fc);
17318                 // Put the "outer" link faces into check list.
17319                 //   fliptets[0] = [e,d,a,b] => will be flipped, so
17320                 //   [a,b,d] and [a,b,e] are not "outer" link faces.
17321                 for (i = 1; i < 3; i++) {
17322                   eprevesym(fliptets[i], newface);
17323                   crossfaces->newindex((void **) &parytet);
17324                   *parytet = newface;
17325                 }
17326                 for (i = 1; i < 3; i++) {
17327                   enextesym(fliptets[i], newface);
17328                   crossfaces->newindex((void **) &parytet);
17329                   *parytet = newface;
17330                 }
17331                 // Then do a 3-to-2 flip.
17332                 enextesymself(fliptets[0]);  // fliptets[0] is [e,d,a,b].
17333                 eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
17334                 fliptets[1] = baktets[0]; // = [b,a,e,f]
17335                 fliptets[2] = baktets[1]; // = [b,a,f,d]
17336                 flip32(fliptets, 1, &fc);
17337                 // Put the "outer" link faces into check list.
17338                 //   fliptets[0] = [d,e,f,a]
17339                 //   fliptets[1] = [e,d,f,b]
17340                 //   Faces [a,b,d] and [a,b,e] are not "outer" link faces.
17341                 enextself(fliptets[0]);
17342                 for (i = 1; i < 3; i++) {
17343                   esym(fliptets[0], newface);
17344                   crossfaces->newindex((void **) &parytet);
17345                   *parytet = newface;
17346                   enextself(fliptets[0]);
17347                 }
17348                 enextself(fliptets[1]);
17349                 for (i = 1; i < 3; i++) {
17350                   esym(fliptets[1], newface);
17351                   crossfaces->newindex((void **) &parytet);
17352                   *parytet = newface;
17353                   enextself(fliptets[1]);
17354                 }
17355                 flip23count--;
17356                 flip32count--;
17357                 flip44count++;
17358                 flipflag = 1;
17359               } else {
17360                 //n == 4, convflag != 0; assert(0);
17361               }
17362             } else {
17363               // n > 4 => unflipable. //assert(0);
17364             }
17365           } else {
17366             // There are more than 1 non-convex or coplanar cases.
17367             flipflag = -1; // Ignore this face.
17368             if (b->verbose > 2) {
17369               printf("        Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17370                      pointmark(bface.forg), pointmark(bface.fdest),
17371                      pointmark(bface.fapex), pointmark(bface.foppo),
17372                      pointmark(bface.noppo), bface.key);
17373             }
17374           } // if (convcount == 1)
17375 
17376           if (flipflag == 1) {
17377             // Update the priority queue.
17378             for (i = 0; i < crossfaces->objects; i++) {
17379               parytet = (triface *) fastlookup(crossfaces, i);
17380               flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17381             }
17382             crossfaces->restart();
17383             if (1) { // if (!b->flipinsert_random) {
17384               // Insert all queued unflipped faces.
17385               for (i = 0; i < bfacearray->objects; i++) {
17386                 parytet = (triface *) fastlookup(bfacearray, i);
17387                 // This face may be changed.
17388                 if (!isdeadtet(*parytet)) {
17389                   flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17390                 }
17391               }
17392               bfacearray->restart();
17393             }
17394             fcount++;
17395           } else if (flipflag == 0) {
17396             // Queue an unflippable face. To process it later.
17397             bfacearray->newindex((void **) &parytet);
17398             *parytet = fliptet;
17399           }
17400         } // if (pe == bface.noppo)
17401       } // if ((pa == bface.forg) && ...)
17402     } // if (bface.tt != nullptr)
17403 
17404   } // while (pqueue != nullptr)
17405 
17406   if (bfacearray->objects > 0) {
17407     if (fcount == 0) {
17408       printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
17409       assert(0);
17410     }
17411   }
17412 
17413   // 'bfacearray' may be not empty (for what reason ??).
17414   //dbg_unflip_facecount += bfacearray->objects;
17415 
17416   assert(flippool->items == 0l);
17417   delete bfacearray;
17418 
17419   // Un-mark top and bottom points.
17420   for (i = 0; i < toppoints->objects; i++) {
17421     parypt = (point *) fastlookup(toppoints, i);
17422     punmarktest2(*parypt);
17423   }
17424   for (i = 0; i < botpoints->objects; i++) {
17425     parypt = (point *) fastlookup(botpoints, i);
17426     punmarktest3(*parypt);
17427   }
17428 
17429   f23count = flip23count - f23count;
17430   f32count = flip32count - f32count;
17431   f44count = flip44count - f44count;
17432   totalfcount = f23count + f32count + f44count;
17433   if (b->verbose > 2) {
17434     printf("      Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
17435            totalfcount, f23count, f32count, f44count);
17436   }
17437 }
17438 
17439 ///////////////////////////////////////////////////////////////////////////////
17440 //                                                                           //
17441 // fillregion()    Fill the missing region by a set of new subfaces.         //
17442 //                                                                           //
17443 // 'missingshs' contains the list of subfaces in R.  Moreover, each subface  //
17444 // (except the first one) in this list represents an interior edge of R.     //
17445 //                                                                           //
17446 // Note: We assume that all vertices of R are marktested so we can detect    //
17447 // new subface by checking the flag in apexes.                               //
17448 //                                                                           //
17449 ///////////////////////////////////////////////////////////////////////////////
17450 
fillregion(arraypool * missingshs,arraypool * missingshbds,arraypool * newshs)17451 bool tetgenmesh::fillregion(arraypool* missingshs, arraypool* missingshbds,
17452                             arraypool* newshs)
17453 {
17454   badface *newflipface, *popface;
17455   triface searchtet, spintet, neightet;
17456   face oldsh, newsh, opensh, *parysh;
17457   face casout, casin, neighsh, checksh;
17458   face neighseg, checkseg;
17459   point pc;
17460   int success;
17461   int t1ver;
17462   int i, j;
17463 
17464 
17465   // Search the first new subface to fill the region.
17466   for (i = 0; i < missingshbds->objects; i++) {
17467     parysh = (face *) fastlookup(missingshbds, i);
17468     sspivot(*parysh, neighseg);
17469     sstpivot1(neighseg, searchtet);
17470     j = 0; // Count the number of passes of R.
17471     spintet = searchtet;
17472     while (1) {
17473       pc = apex(spintet);
17474       if (pmarktested(pc)) {
17475         neightet = spintet;
17476         j++;
17477       }
17478       fnextself(spintet);
17479       if (spintet.tet == searchtet.tet) break;
17480     }
17481     assert(j >= 1);
17482     if (j == 1) {
17483       // Found an interior new subface.
17484       searchtet = neightet;
17485       oldsh = *parysh;
17486       break;
17487     }
17488   } // i
17489 
17490   if (i == missingshbds->objects) {
17491     // Failed to find any interior subface.
17492     // Need Steiner points.
17493     return false;
17494   }
17495 
17496   makeshellface(subfaces, &newsh);
17497   setsorg(newsh, org(searchtet));
17498   setsdest(newsh, dest(searchtet));
17499   setsapex(newsh, apex(searchtet));
17500   // The new subface gets its markers from the old one.
17501   setshellmark(newsh, shellmark(oldsh));
17502   if (checkconstraints) {
17503     setareabound(newsh, areabound(oldsh));
17504   }
17505   // Connect the new subface to adjacent tets.
17506   tsbond(searchtet, newsh);
17507   fsymself(searchtet);
17508   sesymself(newsh);
17509   tsbond(searchtet, newsh);
17510   // Connect newsh to outer subfaces.
17511   sspivot(oldsh, checkseg);
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 = nullptr;
17523   }
17524   spivot(oldsh, casout);
17525   if (casout.sh != nullptr) {
17526     casin = casout;
17527     if (checkseg.sh != nullptr) {
17528       // Make sure that the subface has the right ori at the segment.
17529       checkseg.shver = 0;
17530       if (sorg(newsh) != sorg(checkseg)) {
17531         sesymself(newsh);
17532       }
17533       spivot(casin, neighsh);
17534       while (neighsh.sh != oldsh.sh) {
17535         casin = neighsh;
17536         spivot(casin, neighsh);
17537       }
17538     }
17539     sbond1(newsh, casout);
17540     sbond1(casin, newsh);
17541   }
17542   if (checkseg.sh != nullptr) {
17543     ssbond(newsh, checkseg);
17544   }
17545   // Add this new subface into list.
17546   sinfect(newsh);
17547   newshs->newindex((void **) &parysh);
17548   *parysh = newsh;
17549 
17550   // Push two "open" side of the new subface into stack.
17551   for (i = 0; i < 2; i++) {
17552     senextself(newsh);
17553     newflipface = (badface *) flippool->alloc();
17554     newflipface->ss = newsh;
17555     newflipface->nextitem = flipstack;
17556     flipstack = newflipface;
17557   }
17558 
17559   success = 1;
17560 
17561   // Loop until 'flipstack' is empty.
17562   while ((flipstack != nullptr) && success) {
17563     // Pop an "open" side from the stack.
17564     popface = flipstack;
17565     opensh = popface->ss;
17566     flipstack = popface->nextitem; // The next top item in stack.
17567     flippool->dealloc((void *) popface);
17568 
17569     // opensh is either (1) an interior edge or (2) a bdry edge.
17570     stpivot(opensh, searchtet);
17571     tsspivot1(searchtet, checkseg);
17572     if (checkseg.sh == nullptr) {
17573       // No segment. It is an interior edge of R.
17574       // Search for a new face in R.
17575       spintet = searchtet;
17576       fnextself(spintet); // Skip the current face.
17577       while (1) {
17578         pc = apex(spintet);
17579         if (pmarktested(pc)) {
17580           // 'opensh' is an interior edge.
17581           if (!issubface(spintet)) {
17582             // Create a new subface.
17583             makeshellface(subfaces, &newsh);
17584             setsorg(newsh, org(spintet));
17585             setsdest(newsh, dest(spintet));
17586             setsapex(newsh, pc);
17587             // The new subface gets its markers from its neighbor.
17588             setshellmark(newsh, shellmark(opensh));
17589             if (checkconstraints) {
17590               setareabound(newsh, areabound(opensh));
17591             }
17592             // Connect the new subface to adjacent tets.
17593             tsbond(spintet, newsh);
17594             fsymself(spintet);
17595             sesymself(newsh);
17596             tsbond(spintet, newsh);
17597             // Connect newsh to its adjacent subface.
17598             sbond(newsh, opensh);
17599             // Add this new subface into list.
17600             sinfect(newsh);
17601             newshs->newindex((void **) &parysh);
17602             *parysh = newsh;
17603             // Push two "open" side of the new subface into stack.
17604             for (i = 0; i < 2; i++) {
17605               senextself(newsh);
17606               newflipface = (badface *) flippool->alloc();
17607               newflipface->ss = newsh;
17608               newflipface->nextitem = flipstack;
17609               flipstack = newflipface;
17610             }
17611           } else {
17612             // Connect to another open edge.
17613             tspivot(spintet, checksh);
17614             sbond(opensh, checksh);
17615           }
17616           break;
17617         } // if (pmarktested(pc))
17618         fnextself(spintet);
17619         if (spintet.tet == searchtet.tet) {
17620           // Not find any face to fill in R at this side.
17621           // Suggest a point to split the edge.
17622           success = 0;
17623           break;
17624         }
17625       } // while (1)
17626     } else {
17627       // This side coincident with a boundary edge of R.
17628       checkseg.shver = 0;
17629       spivot(checkseg, oldsh);
17630       if (sinfected(checkseg)) {
17631         // It's a faked segment. Delete it.
17632         spintet = searchtet;
17633         while (1) {
17634           tssdissolve1(spintet);
17635           fnextself(spintet);
17636           if (spintet.tet == searchtet.tet) break;
17637         }
17638         shellfacedealloc(subsegs, checkseg.sh);
17639         ssdissolve(oldsh);
17640         checkseg.sh = nullptr;
17641       }
17642       spivot(oldsh, casout);
17643       if (casout.sh != nullptr) {
17644         casin = casout;
17645         if (checkseg.sh != nullptr) {
17646           // Make sure that the subface has the right ori at the segment.
17647           checkseg.shver = 0;
17648           if (sorg(opensh) != sorg(checkseg)) {
17649             sesymself(opensh);
17650               }
17651           spivot(casin, neighsh);
17652           while (neighsh.sh != oldsh.sh) {
17653             casin = neighsh;
17654             spivot(casin, neighsh);
17655           }
17656         }
17657         sbond1(opensh, casout);
17658         sbond1(casin, opensh);
17659       }
17660       if (checkseg.sh != nullptr) {
17661         ssbond(opensh, checkseg);
17662       }
17663     } // if (checkseg.sh != nullptr)
17664   } // while ((flipstack != nullptr) && success)
17665 
17666   if (success) {
17667     // Uninfect all new subfaces.
17668     for (i = 0; i < newshs->objects; i++) {
17669       parysh = (face *) fastlookup(newshs, i);
17670       suninfect(*parysh);
17671     }
17672     // Delete old subfaces.
17673     for (i = 0; i < missingshs->objects; i++) {
17674       parysh = (face *) fastlookup(missingshs, i);
17675       shellfacedealloc(subfaces, parysh->sh);
17676     }
17677     fillregioncount++;
17678   } else {
17679     // Failed to fill the region.
17680     // Re-connect old subfaces at boundaries of R.
17681     // Also delete fake segments.
17682     for (i = 0; i < missingshbds->objects; i++) {
17683       parysh = (face *) fastlookup(missingshbds, i);
17684       // It still connect to 'casout'.
17685       // Re-connect 'casin' to it.
17686       spivot(*parysh, casout);
17687       casin = casout;
17688       spivot(casin, neighsh);
17689       while (1) {
17690         if (sinfected(neighsh)) break;
17691         if (neighsh.sh == parysh->sh) break;
17692         casin = neighsh;
17693         spivot(casin, neighsh);
17694       }
17695       if (sinfected(neighsh)) {
17696         sbond1(casin, *parysh);
17697       }
17698       sspivot(*parysh, checkseg);
17699       if (checkseg.sh != nullptr) {
17700         if (checkseg.sh[3] != nullptr) {
17701           if (sinfected(checkseg)) {
17702             sstpivot1(checkseg, searchtet);
17703             spintet = searchtet;
17704             while (1) {
17705               tssdissolve1(spintet);
17706               fnextself(spintet);
17707               if (spintet.tet == searchtet.tet) break;
17708             }
17709             ssdissolve(*parysh);
17710             shellfacedealloc(subsegs, checkseg.sh);
17711           }
17712         }
17713       }
17714     }
17715     // Delete all new subfaces.
17716     for (i = 0; i < newshs->objects; i++) {
17717       parysh = (face *) fastlookup(newshs, i);
17718       shellfacedealloc(subfaces, parysh->sh);
17719     }
17720     // Clear the flip pool.
17721     flippool->restart();
17722     flipstack = nullptr;
17723 
17724     // Choose an interior edge of R to split.
17725     assert(missingshs->objects > 1);
17726     // Skip the first subface in 'missingshs'.
17727     i = randomnation(missingshs->objects - 1) + 1;
17728     parysh = (face *) fastlookup(missingshs, i);
17729     recentsh = *parysh;
17730   }
17731 
17732   newshs->restart();
17733 
17734   return (success!=0);
17735 }
17736 
17737 ///////////////////////////////////////////////////////////////////////////////
17738 //                                                                           //
17739 // insertpoint_cdt()    Insert a new point into a CDT.                       //
17740 //                                                                           //
17741 ///////////////////////////////////////////////////////////////////////////////
17742 
insertpoint_cdt(point newpt,triface * searchtet,face * splitsh,face * splitseg,insertvertexflags * ivf,arraypool * cavpoints,arraypool * cavfaces,arraypool * cavshells,arraypool * newtets,arraypool * crosstets,arraypool * misfaces)17743 int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh,
17744                                 face *splitseg, insertvertexflags *ivf,
17745                                 arraypool *cavpoints, arraypool *cavfaces,
17746                                 arraypool *cavshells, arraypool *newtets,
17747                                 arraypool *crosstets, arraypool *misfaces)
17748 {
17749   triface neightet, *parytet;
17750   face checksh, *parysh, *parysh1;
17751   face *paryseg, *paryseg1;
17752   point *parypt;
17753   int t1ver;
17754   int i;
17755 
17756   if (b->verbose > 2) {
17757     printf("      Insert point %d into CDT\n", pointmark(newpt));
17758   }
17759 
17760   if (!insertpoint(newpt, searchtet, nullptr, nullptr, ivf)) {
17761     // Point is not inserted. Check ivf->iloc for reason.
17762     return 0;
17763   }
17764 
17765 
17766   for (i = 0; i < cavetetvertlist->objects; i++) {
17767     cavpoints->newindex((void **) &parypt);
17768     *parypt = * (point *) fastlookup(cavetetvertlist, i);
17769   }
17770   // Add the new point into the point list.
17771   cavpoints->newindex((void **) &parypt);
17772   *parypt = newpt;
17773 
17774   for (i = 0; i < cavebdrylist->objects; i++) {
17775     cavfaces->newindex((void **) &parytet);
17776     *parytet = * (triface *) fastlookup(cavebdrylist, i);
17777   }
17778 
17779   for (i = 0; i < caveoldtetlist->objects; i++) {
17780     crosstets->newindex((void **) &parytet);
17781     *parytet = * (triface *) fastlookup(caveoldtetlist, i);
17782   }
17783 
17784   cavetetvertlist->restart();
17785   cavebdrylist->restart();
17786   caveoldtetlist->restart();
17787 
17788   // Insert the point using the cavity algorithm.
17789   delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets,
17790                   misfaces);
17791   fillcavity(cavshells, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
17792   carvecavity(crosstets, newtets, nullptr);
17793 
17794   if ((splitsh != nullptr) || (splitseg != nullptr)) {
17795     // Insert the point into the surface mesh.
17796     sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
17797 
17798     // Put all new subfaces into stack.
17799     for (i = 0; i < caveshbdlist->objects; i++) {
17800       // Get an old subface at edge [a, b].
17801       parysh = (face *) fastlookup(caveshbdlist, i);
17802       spivot(*parysh, checksh); // The new subface [a, b, p].
17803       // Do not recover a deleted new face (degenerated).
17804       if (checksh.sh[3] != nullptr) {
17805         subfacstack->newindex((void **) &parysh);
17806         *parysh = checksh;
17807       }
17808     }
17809 
17810     if (splitseg != nullptr) {
17811       // Queue two new subsegments in C(p) for recovery.
17812       for (i = 0; i < cavesegshlist->objects; i++) {
17813         paryseg = (face *) fastlookup(cavesegshlist, i);
17814         subsegstack->newindex((void **) &paryseg1);
17815         *paryseg1 = *paryseg;
17816       }
17817     } // if (splitseg != nullptr)
17818 
17819     // Delete the old subfaces in sC(p).
17820     for (i = 0; i < caveshlist->objects; i++) {
17821       parysh = (face *) fastlookup(caveshlist, i);
17822       if (checksubfaceflag) {
17823         // It is possible that this subface still connects to adjacent
17824         //   tets which are not in C(p). If so, clear connections in the
17825         //   adjacent tets at this subface.
17826         stpivot(*parysh, neightet);
17827         if (neightet.tet != nullptr) {
17828           if (neightet.tet[4] != nullptr) {
17829             // Found an adjacent tet. It must be not in C(p).
17830             assert(!infected(neightet));
17831             tsdissolve(neightet);
17832             fsymself(neightet);
17833             assert(!infected(neightet));
17834             tsdissolve(neightet);
17835           }
17836         }
17837       }
17838       shellfacedealloc(subfaces, parysh->sh);
17839     }
17840     if (splitseg != nullptr) {
17841       // Delete the old segment in sC(p).
17842       shellfacedealloc(subsegs, splitseg->sh);
17843     }
17844 
17845     // Clear working lists.
17846     caveshlist->restart();
17847     caveshbdlist->restart();
17848     cavesegshlist->restart();
17849   } // if ((splitsh != nullptr) || (splitseg != nullptr))
17850 
17851   // Put all interior subfaces into stack for recovery.
17852   // They were collected in carvecavity().
17853   // Note: Some collected subfaces may be deleted by sinsertvertex().
17854   for (i = 0; i < caveencshlist->objects; i++) {
17855     parysh = (face *) fastlookup(caveencshlist, i);
17856     if (parysh->sh[3] != nullptr) {
17857       subfacstack->newindex((void **) &parysh1);
17858       *parysh1 = *parysh;
17859     }
17860   }
17861 
17862   // Put all interior segments into stack for recovery.
17863   // They were collected in carvecavity().
17864   // Note: Some collected segments may be deleted by sinsertvertex().
17865   for (i = 0; i < caveencseglist->objects; i++) {
17866     paryseg = (face *) fastlookup(caveencseglist, i);
17867     if (paryseg->sh[3] != nullptr) {
17868       subsegstack->newindex((void **) &paryseg1);
17869       *paryseg1 = *paryseg;
17870     }
17871   }
17872 
17873   caveencshlist->restart();
17874   caveencseglist->restart();
17875 
17876   return 1;
17877 }
17878 
17879 ///////////////////////////////////////////////////////////////////////////////
17880 //                                                                           //
17881 // refineregion()    Refine a missing region by inserting points.            //
17882 //                                                                           //
17883 // 'splitsh' represents an edge of the facet to be split. It must be not a   //
17884 // segment.
17885 //                                                                           //
17886 // Assumption: The current mesh is a CDT and is convex.                      //
17887 //                                                                           //
17888 ///////////////////////////////////////////////////////////////////////////////
17889 
refineregion(face & splitsh,arraypool * cavpoints,arraypool * cavfaces,arraypool * cavshells,arraypool * newtets,arraypool * crosstets,arraypool * misfaces)17890 void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints,
17891                               arraypool *cavfaces, arraypool *cavshells,
17892                               arraypool *newtets, arraypool *crosstets,
17893                               arraypool *misfaces)
17894 {
17895   triface searchtet, spintet;
17896   face splitseg, *paryseg;
17897   point steinpt, pa, pb, refpt;
17898   insertvertexflags ivf;
17899   enum interresult dir;
17900   long baknum = points->items;
17901   int t1ver;
17902   int i;
17903 
17904   if (b->verbose > 2) {
17905     printf("      Refining region at edge (%d, %d, %d).\n",
17906            pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
17907            pointmark(sapex(splitsh)));
17908   }
17909 
17910   // Add the Steiner point at the barycenter of the face.
17911   pa = sorg(splitsh);
17912   pb = sdest(splitsh);
17913   // Create a new point.
17914   makepoint(&steinpt, FREEFACETVERTEX);
17915   for (i = 0; i < 3; i++) {
17916     steinpt[i] = 0.5 * (pa[i] + pb[i]);
17917   }
17918 
17919   ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
17920   ivf.cdtflag = 1; // Only create the initial cavity.
17921   ivf.sloc = (int) ONEDGE;
17922   ivf.sbowywat = 1;
17923   ivf.assignmeshsize = b->metric;
17924 
17925   point2tetorg(pa, searchtet); // Start location from it.
17926   ivf.iloc = (int) OUTSIDE;
17927 
17928   ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
17929   if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, nullptr, &ivf, cavpoints,
17930                        cavfaces, cavshells, newtets, crosstets, misfaces)) {
17931     if (ivf.iloc == (int) ENCSEGMENT) {
17932       pointdealloc(steinpt);
17933       // Split an encroached segment.
17934       assert(encseglist->objects > 0);
17935       i = randomnation(encseglist->objects);
17936       paryseg = (face *) fastlookup(encseglist, i);
17937       splitseg = *paryseg;
17938       encseglist->restart();
17939 
17940       // Split the segment.
17941       pa = sorg(splitseg);
17942       pb = sdest(splitseg);
17943       // Create a new point.
17944       makepoint(&steinpt, FREESEGVERTEX);
17945       for (i = 0; i < 3; i++) {
17946         steinpt[i] = 0.5 * (pa[i] + pb[i]);
17947       }
17948       point2tetorg(pa, searchtet);
17949       ivf.iloc = (int) OUTSIDE;
17950       ivf.rejflag = 0;
17951       if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
17952                            cavpoints, cavfaces, cavshells, newtets,
17953                            crosstets, misfaces)) {
17954         assert(0);
17955       }
17956       st_segref_count++;
17957       if (steinerleft > 0) steinerleft--;
17958     } else {
17959       assert(0);
17960     }
17961   } else {
17962     st_facref_count++;
17963     if (steinerleft > 0) steinerleft--;
17964   }
17965 
17966   while (subsegstack->objects > 0l) {
17967     // seglist is used as a stack.
17968     subsegstack->objects--;
17969     paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
17970     splitseg = *paryseg;
17971 
17972     // Check if this segment has been recovered.
17973     sstpivot1(splitseg, searchtet);
17974     if (searchtet.tet != nullptr) continue;
17975 
17976     // Search the segment.
17977     dir = scoutsegment(sorg(splitseg), sdest(splitseg), &searchtet, &refpt,
17978                        nullptr);
17979     if (dir == SHAREEDGE) {
17980       // Found this segment, insert it.
17981       if (!issubseg(searchtet)) {
17982         // Let the segment remember an adjacent tet.
17983         sstbond1(splitseg, searchtet);
17984         // Bond the segment to all tets containing it.
17985         spintet = searchtet;
17986         do {
17987           tssbond1(spintet, splitseg);
17988           fnextself(spintet);
17989         } while (spintet.tet != searchtet.tet);
17990       } else {
17991         // Collision! Should not happen.
17992         assert(0);
17993       }
17994     } else {
17995       if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
17996         // Split the segment.
17997         // Create a new point.
17998         makepoint(&steinpt, FREESEGVERTEX);
17999         //setpointtype(newpt, FREESEGVERTEX);
18000         getsteinerptonsegment(&splitseg, refpt, steinpt);
18001         ivf.iloc = (int) OUTSIDE;
18002         ivf.rejflag = 0;
18003         if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
18004                              cavpoints, cavfaces, cavshells, newtets,
18005                              crosstets, misfaces)) {
18006           assert(0);
18007         }
18008         st_segref_count++;
18009         if (steinerleft > 0) steinerleft--;
18010       } else {
18011         // Maybe a PLC problem.
18012         assert(0);
18013       }
18014     }
18015   } // while
18016 
18017   if (b->verbose > 2) {
18018     printf("      Added %ld Steiner points.\n", points->items - baknum);
18019   }
18020 }
18021 
18022 ///////////////////////////////////////////////////////////////////////////////
18023 //                                                                           //
18024 // constrainedfacets()    Recover constrained facets in a CDT.               //
18025 //                                                                           //
18026 // All unrecovered subfaces are queued in 'subfacestack'.                    //
18027 //                                                                           //
18028 ///////////////////////////////////////////////////////////////////////////////
18029 
constrainedfacets()18030 void tetgenmesh::constrainedfacets()
18031 {
18032   arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
18033   arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
18034   arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
18035   arraypool *tg_toppoints, *tg_botpoints;
18036   arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
18037   triface searchtet, neightet, crossedge;
18038   face searchsh, *parysh, *parysh1;
18039   face *paryseg;
18040   point *parypt;
18041   enum interresult dir;
18042   int facetcount;
18043   int success;
18044   int t1ver;
18045   int i, j;
18046 
18047   // Initialize arrays.
18048   tg_crosstets      = new arraypool(sizeof(triface), 10);
18049   tg_topnewtets     = new arraypool(sizeof(triface), 10);
18050   tg_botnewtets     = new arraypool(sizeof(triface), 10);
18051   tg_topfaces       = new arraypool(sizeof(triface), 10);
18052   tg_botfaces       = new arraypool(sizeof(triface), 10);
18053   tg_midfaces       = new arraypool(sizeof(triface), 10);
18054   tg_toppoints      = new arraypool(sizeof(point), 8);
18055   tg_botpoints      = new arraypool(sizeof(point), 8);
18056   tg_facfaces       = new arraypool(sizeof(face), 10);
18057   tg_topshells      = new arraypool(sizeof(face), 10);
18058   tg_botshells      = new arraypool(sizeof(face), 10);
18059   tg_missingshs     = new arraypool(sizeof(face), 10);
18060   tg_missingshbds   = new arraypool(sizeof(face), 10);
18061   tg_missingshverts = new arraypool(sizeof(point), 8);
18062   // This is a global array used by refineregion().
18063   encseglist        = new arraypool(sizeof(face), 4);
18064 
18065   facetcount = 0;
18066 
18067   while (subfacstack->objects > 0l) {
18068 
18069     subfacstack->objects--;
18070     parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
18071     searchsh = *parysh;
18072 
18073     if (searchsh.sh[3] == nullptr) continue; // It is dead.
18074     if (isshtet(searchsh)) continue; // It is recovered.
18075 
18076     // Collect all unrecovered subfaces which are co-facet.
18077     smarktest(searchsh);
18078     tg_facfaces->newindex((void **) &parysh);
18079     *parysh = searchsh;
18080     for (i = 0; i < tg_facfaces->objects; i++) {
18081       parysh = (face *) fastlookup(tg_facfaces, i);
18082       for (j = 0; j < 3; j++) {
18083         if (!isshsubseg(*parysh)) {
18084           spivot(*parysh, searchsh);
18085           assert(searchsh.sh != nullptr); // SELF_CHECK
18086           if (!smarktested(searchsh)) {
18087             if (!isshtet(searchsh)) {
18088               smarktest(searchsh);
18089               tg_facfaces->newindex((void **) &parysh1);
18090               *parysh1 = searchsh;
18091             }
18092           }
18093         }
18094         senextself(*parysh);
18095       } // j
18096     } // i
18097     // Have found all facet subfaces. Unmark them.
18098     for (i = 0; i < tg_facfaces->objects; i++) {
18099       parysh = (face *) fastlookup(tg_facfaces, i);
18100       sunmarktest(*parysh);
18101     }
18102 
18103     if (b->verbose > 2) {
18104       printf("    Recovering facet #%d: %ld subfaces.\n", facetcount + 1,
18105              tg_facfaces->objects);
18106     }
18107     facetcount++;
18108 
18109     while (tg_facfaces->objects > 0l) {
18110 
18111       tg_facfaces->objects--;
18112       parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
18113       searchsh = *parysh;
18114 
18115       if (searchsh.sh[3] == nullptr) continue; // It is dead.
18116       if (isshtet(searchsh)) continue; // It is recovered.
18117 
18118       searchtet.tet = nullptr;
18119       dir = scoutsubface(&searchsh, &searchtet);
18120       if (dir == SHAREFACE) continue; // The subface is inserted.
18121 
18122       // The subface is missing. Form the missing region.
18123       //   Re-use 'tg_crosstets' for 'adjtets'.
18124       formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
18125 
18126       if (scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs)) {
18127         // Save this crossing edge, will be used by fillcavity().
18128         crossedge = searchtet;
18129         // Form a cavity of crossing tets.
18130         success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
18131                              tg_topfaces, tg_botfaces, tg_toppoints,
18132                              tg_botpoints);
18133         if (success) {
18134           if (!b->flipinsert) {
18135             // Tetrahedralize the top part. Re-use 'tg_midfaces'.
18136             delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
18137                             tg_topnewtets, tg_crosstets, tg_midfaces);
18138             // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
18139             delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
18140                             tg_botnewtets, tg_crosstets, tg_midfaces);
18141             // Fill the cavity with new tets.
18142             success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
18143                                  tg_missingshs, tg_topnewtets, tg_botnewtets,
18144                                  &crossedge);
18145             if (success) {
18146               // Cavity is remeshed. Delete old tets and outer new tets.
18147               carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
18148             } else {
18149               restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18150                             tg_missingshbds);
18151             }
18152           } else {
18153             // Use the flip algorithm of Shewchuk to recover the subfaces.
18154             flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints,
18155                             tg_missingshverts);
18156             // Recover the missing region.
18157             success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18158             assert(success);
18159             // Clear working lists.
18160             tg_crosstets->restart();
18161             tg_topfaces->restart();
18162             tg_botfaces->restart();
18163             tg_toppoints->restart();
18164             tg_botpoints->restart();
18165           } // b->flipinsert
18166 
18167           if (success) {
18168             // Recover interior subfaces.
18169             for (i = 0; i < caveencshlist->objects; i++) {
18170               parysh = (face *) fastlookup(caveencshlist, i);
18171               dir = scoutsubface(parysh, &searchtet);
18172               if (dir != SHAREFACE) {
18173                 // Add this face at the end of the list, so it will be
18174                 //   processed immediately.
18175                 tg_facfaces->newindex((void **) &parysh1);
18176                 *parysh1 = *parysh;
18177               }
18178             }
18179             caveencshlist->restart();
18180             // Recover interior segments. This should always be recovered.
18181             for (i = 0; i < caveencseglist->objects; i++) {
18182               paryseg = (face *) fastlookup(caveencseglist, i);
18183               dir = scoutsegment(sorg(*paryseg),sdest(*paryseg),&searchtet,
18184                                  nullptr, nullptr);
18185               assert(dir == SHAREEDGE);
18186               // Insert this segment.
18187               if (!issubseg(searchtet)) {
18188                 // Let the segment remember an adjacent tet.
18189                 sstbond1(*paryseg, searchtet);
18190                 // Bond the segment to all tets containing it.
18191                 neightet = searchtet;
18192                 do {
18193                   tssbond1(neightet, *paryseg);
18194                   fnextself(neightet);
18195                 } while (neightet.tet != searchtet.tet);
18196               } else {
18197                 // Collision! Should not happen.
18198                 assert(0);
18199               }
18200             }
18201             caveencseglist->restart();
18202           } // success - remesh cavity
18203         } // success - form cavity
18204       } else {
18205         // Recover subfaces by retriangulate the surface mesh.
18206         //   Re-use tg_topshells for newshs.
18207         success = fillregion(tg_missingshs, tg_missingshbds, tg_topshells);
18208       }
18209 
18210       // Unmarktest all points of the missing region.
18211       for (i = 0; i < tg_missingshverts->objects; i++) {
18212         parypt = (point *) fastlookup(tg_missingshverts, i);
18213         punmarktest(*parypt);
18214       }
18215       tg_missingshverts->restart();
18216       tg_missingshbds->restart();
18217       tg_missingshs->restart();
18218 
18219       if (!success) {
18220         // The missing region can not be recovered. Refine it.
18221         refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
18222                      tg_topnewtets, tg_crosstets, tg_midfaces);
18223         // Clean the current list of facet subfaces.
18224         // tg_facfaces->restart();
18225       }
18226     } // while (tg_facfaces->objects)
18227 
18228   } // while ((subfacstack->objects)
18229 
18230   // Accumulate the dynamic memory.
18231   totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
18232                       tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
18233                       tg_botfaces->totalmemory + tg_midfaces->totalmemory +
18234                       tg_toppoints->totalmemory + tg_botpoints->totalmemory +
18235                       tg_facfaces->totalmemory + tg_topshells->totalmemory +
18236                       tg_botshells->totalmemory + tg_missingshs->totalmemory +
18237                       tg_missingshbds->totalmemory +
18238                       tg_missingshverts->totalmemory +
18239                       encseglist->totalmemory);
18240 
18241   // Delete arrays.
18242   delete tg_crosstets;
18243   delete tg_topnewtets;
18244   delete tg_botnewtets;
18245   delete tg_topfaces;
18246   delete tg_botfaces;
18247   delete tg_midfaces;
18248   delete tg_toppoints;
18249   delete tg_botpoints;
18250   delete tg_facfaces;
18251   delete tg_topshells;
18252   delete tg_botshells;
18253   delete tg_missingshs;
18254   delete tg_missingshbds;
18255   delete tg_missingshverts;
18256   delete encseglist;
18257 }
18258 
18259 ///////////////////////////////////////////////////////////////////////////////
18260 //                                                                           //
18261 // constraineddelaunay()    Create a constrained Delaunay tetrahedralization.//
18262 //                                                                           //
18263 ///////////////////////////////////////////////////////////////////////////////
18264 
constraineddelaunay(clock_t & tv)18265 void tetgenmesh::constraineddelaunay(clock_t& tv)
18266 {
18267   face searchsh, *parysh;
18268   face searchseg, *paryseg;
18269   int s, i;
18270 
18271   // Statistics.
18272   long bakfillregioncount;
18273   long bakcavitycount, bakcavityexpcount;
18274   long bakseg_ref_count;
18275 
18276   if (!b->quiet) {
18277     printf("Constrained Delaunay...\n");
18278   }
18279 
18280   // Identify acute vertex for PLC inputs.
18281   markacutevertices();
18282 
18283   if (b->verbose) {
18284     printf("  Delaunizing segments.\n");
18285   }
18286 
18287   checksubsegflag = 1;
18288 
18289   // Put all segments into the list (in random order).
18290   subsegs->traversalinit();
18291   for (i = 0; i < subsegs->items; i++) {
18292     s = randomnation(i + 1);
18293     // Move the s-th seg to the i-th.
18294     subsegstack->newindex((void **) &paryseg);
18295     *paryseg = * (face *) fastlookup(subsegstack, s);
18296     // Put i-th seg to be the s-th.
18297     searchseg.sh = shellfacetraverse(subsegs);
18298     //sinfect(searchseg);  // Only save it once.
18299     paryseg = (face *) fastlookup(subsegstack, s);
18300     *paryseg = searchseg;
18301   }
18302 
18303   // Recover non-Delaunay segments.
18304   delaunizesegments();
18305 
18306   if (b->verbose) {
18307     printf("  Inserted %ld Steiner points.\n", st_segref_count);
18308   }
18309 
18310   tv = clock();
18311 
18312   if (b->verbose) {
18313     printf("  Constraining facets.\n");
18314   }
18315 
18316   // Subfaces will be introduced.
18317   checksubfaceflag = 1;
18318 
18319   bakfillregioncount = fillregioncount;
18320   bakcavitycount = cavitycount;
18321   bakcavityexpcount = cavityexpcount;
18322   bakseg_ref_count = st_segref_count;
18323 
18324   // Randomly order the subfaces.
18325   subfaces->traversalinit();
18326   for (i = 0; i < subfaces->items; i++) {
18327     s = randomnation(i + 1);
18328     // Move the s-th subface to the i-th.
18329     subfacstack->newindex((void **) &parysh);
18330     *parysh = * (face *) fastlookup(subfacstack, s);
18331     // Put i-th subface to be the s-th.
18332     searchsh.sh = shellfacetraverse(subfaces);
18333     parysh = (face *) fastlookup(subfacstack, s);
18334     *parysh = searchsh;
18335   }
18336 
18337   // Recover facets.
18338   constrainedfacets();
18339 
18340   if (b->verbose) {
18341     if (fillregioncount > bakfillregioncount) {
18342       printf("  Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
18343     }
18344     if (cavitycount > bakcavitycount) {
18345       printf("  Remeshed %ld cavities", cavitycount - bakcavitycount);
18346       if (cavityexpcount - bakcavityexpcount) {
18347         printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
18348       }
18349       printf(".\n");
18350     }
18351     if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
18352       printf("  Inserted %ld (%ld, %ld) refine points.\n",
18353              st_segref_count + st_facref_count - bakseg_ref_count,
18354              st_segref_count - bakseg_ref_count, st_facref_count);
18355     }
18356   }
18357 }
18358 
18359 ////                                                                       ////
18360 ////                                                                       ////
18361 //// constrained_cxx //////////////////////////////////////////////////////////
18362 
18363 //// steiner_cxx //////////////////////////////////////////////////////////////
18364 ////                                                                       ////
18365 ////                                                                       ////
18366 
18367 ///////////////////////////////////////////////////////////////////////////////
18368 //                                                                           //
18369 // checkflipeligibility()    A call back function for boundary recovery.     //
18370 //                                                                           //
18371 // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
18372 // and 2 : 3-to-2, respectively.                                             //
18373 //                                                                           //
18374 // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is    //
18375 // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
18376 // other points must not be 'dummypoint'.                                    //
18377 //                                                                           //
18378 ///////////////////////////////////////////////////////////////////////////////
18379 
checkflipeligibility(int fliptype,point pa,point pb,point pc,point pd,point pe,int level,int edgepivot,flipconstraints * fc)18380 int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
18381                                      point pc, point pd, point pe,
18382                                      int level, int edgepivot,
18383                                      flipconstraints* fc)
18384 {
18385   point tmppts[3];
18386   enum interresult dir;
18387   int types[2], poss[4];
18388   int intflag;
18389   int rejflag = 0;
18390   int i;
18391 
18392   if (fc->seg[0] != nullptr) {
18393     // A constraining edge is given (e.g., for edge recovery).
18394     if (fliptype == 1) {
18395       // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18396       tmppts[0] = pa;
18397       tmppts[1] = pb;
18398       tmppts[2] = pc;
18399       for (i = 0; i < 3 && !rejflag; i++) {
18400         if (tmppts[i] != dummypoint) {
18401           // Test if the face [e,d,#] intersects the edge.
18402           intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
18403                                   nullptr, 1, types, poss);
18404           if (intflag == 2) {
18405             // They intersect at a single point.
18406             dir = (enum interresult) types[0];
18407             if (dir == ACROSSFACE) {
18408               // The interior of [e,d,#] intersect the segment.
18409               rejflag = 1;
18410             } else if (dir == ACROSSEDGE) {
18411               if (poss[0] == 0) {
18412                 // The interior of [e,d] intersect the segment.
18413                 // Since [e,d] is the newly created edge. Reject this flip.
18414                 rejflag = 1;
18415               }
18416             }
18417           } else if (intflag == 4) {
18418             // They may intersect at either a point or a line segment.
18419             dir = (enum interresult) types[0];
18420             if (dir == ACROSSEDGE) {
18421               if (poss[0] == 0) {
18422                 // The interior of [e,d] intersect the segment.
18423                 // Since [e,d] is the newly created edge. Reject this flip.
18424                 rejflag = 1;
18425               }
18426             }
18427           }
18428         } // if (tmppts[0] != dummypoint)
18429       } // i
18430     } else if (fliptype == 2) {
18431       // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18432       if (pc != dummypoint) {
18433         // Check if the new face [a,b,c] intersect the edge in its interior.
18434         intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], nullptr,
18435                                 1, types, poss);
18436         if (intflag == 2) {
18437           // They intersect at a single point.
18438           dir = (enum interresult) types[0];
18439           if (dir == ACROSSFACE) {
18440             // The interior of [a,b,c] intersect the segment.
18441             rejflag = 1; // Do not flip.
18442           }
18443         } else if (intflag == 4) {
18444           // [a,b,c] is coplanar with the edge.
18445           dir = (enum interresult) types[0];
18446           if (dir == ACROSSEDGE) {
18447             // The boundary of [a,b,c] intersect the segment.
18448             rejflag = 1; // Do not flip.
18449           }
18450         }
18451       } // if (pc != dummypoint)
18452     }
18453   } // if (fc->seg[0] != nullptr)
18454 
18455   if ((fc->fac[0] != nullptr) && !rejflag) {
18456     // A constraining face is given (e.g., for face recovery).
18457     if (fliptype == 1) {
18458       // A 2-to-3 flip.
18459       // Test if the new edge [e,d] intersects the face.
18460       intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
18461                               nullptr, 1, types, poss);
18462       if (intflag == 2) {
18463         // They intersect at a single point.
18464         dir = (enum interresult) types[0];
18465         if (dir == ACROSSFACE) {
18466           rejflag = 1;
18467         } else if (dir == ACROSSEDGE) {
18468           rejflag = 1;
18469         }
18470       } else if (intflag == 4) {
18471         // The edge [e,d] is coplanar with the face.
18472         // There may be two intersections.
18473         for (i = 0; i < 2 && !rejflag; i++) {
18474           dir = (enum interresult) types[i];
18475           if (dir == ACROSSFACE) {
18476             rejflag = 1;
18477           } else if (dir == ACROSSEDGE) {
18478             rejflag = 1;
18479           }
18480         }
18481       }
18482     } // if (fliptype == 1)
18483   } // if (fc->fac[0] != nullptr)
18484 
18485   if ((fc->remvert != nullptr) && !rejflag) {
18486     // The vertex is going to be removed. Do not create a new edge which
18487     //   contains this vertex.
18488     if (fliptype == 1) {
18489       // A 2-to-3 flip.
18490       if ((pd == fc->remvert) || (pe == fc->remvert)) {
18491         rejflag = 1;
18492       }
18493     }
18494   }
18495 
18496   if (fc->remove_large_angle && !rejflag) {
18497     // Remove a large dihedral angle. Do not create a new small angle.
18498     REAL cosmaxd = 0, diff;
18499     if (fliptype == 1) {
18500       // We assume that neither 'a' nor 'b' is dummypoint.
18501       assert((pa != dummypoint) && (pb != dummypoint)); // SELF_CHECK
18502       // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18503       // The new tet [e,d,a,b] will be flipped later. Only two new tets:
18504       //   [e,d,b,c] and [e,d,c,a] need to be checked.
18505       if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
18506         // Get the largest dihedral angle of [e,d,b,c].
18507         tetalldihedral(pe, pd, pb, pc, nullptr, &cosmaxd, nullptr);
18508         diff = cosmaxd - fc->cosdihed_in;
18509         if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18510         if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18511           rejflag = 1;
18512         } else {
18513           // Record the largest new angle.
18514           if (cosmaxd < fc->cosdihed_out) {
18515             fc->cosdihed_out = cosmaxd;
18516           }
18517           // Get the largest dihedral angle of [e,d,c,a].
18518           tetalldihedral(pe, pd, pc, pa, nullptr, &cosmaxd, nullptr);
18519           diff = cosmaxd - fc->cosdihed_in;
18520           if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18521           if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18522             rejflag = 1;
18523           } else {
18524             // Record the largest new angle.
18525             if (cosmaxd < fc->cosdihed_out) {
18526               fc->cosdihed_out = cosmaxd;
18527             }
18528           }
18529         }
18530       } // if (pc != dummypoint && ...)
18531     } else if (fliptype == 2) {
18532       // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18533       // We assume that neither 'e' nor 'd' is dummypoint.
18534       assert((pe != dummypoint) && (pd != dummypoint)); // SELF_CHECK
18535       if (level == 0) {
18536         // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
18537         if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18538           // Get the largest dihedral angle of [a,b,c,d].
18539           tetalldihedral(pa, pb, pc, pd, nullptr, &cosmaxd, nullptr);
18540           diff = cosmaxd - fc->cosdihed_in;
18541           if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
18542           if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18543             rejflag = 1;
18544           } else {
18545             // Record the largest new angle.
18546             if (cosmaxd < fc->cosdihed_out) {
18547               fc->cosdihed_out = cosmaxd;
18548             }
18549             // Get the largest dihedral angle of [b,a,c,e].
18550             tetalldihedral(pb, pa, pc, pe, nullptr, &cosmaxd, nullptr);
18551             diff = cosmaxd - fc->cosdihed_in;
18552             if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18553             if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18554               rejflag = 1;
18555             } else {
18556               // Record the largest new angle.
18557               if (cosmaxd < fc->cosdihed_out) {
18558                 fc->cosdihed_out = cosmaxd;
18559               }
18560             }
18561           }
18562         }
18563       } else { // level > 0
18564         assert(edgepivot != 0);
18565         if (edgepivot == 1) {
18566           // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
18567           if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18568             // Get the largest dihedral angle of [b,a,c,e].
18569             tetalldihedral(pb, pa, pc, pe, nullptr, &cosmaxd, nullptr);
18570             diff = cosmaxd - fc->cosdihed_in;
18571             if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18572             if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18573               rejflag = 1;
18574             } else {
18575               // Record the largest new angle.
18576               if (cosmaxd < fc->cosdihed_out) {
18577                 fc->cosdihed_out = cosmaxd;
18578               }
18579             }
18580           }
18581         } else {
18582           assert(edgepivot == 2);
18583           // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
18584           if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18585             // Get the largest dihedral angle of [b,a,c,e].
18586             tetalldihedral(pa, pb, pc, pd, nullptr, &cosmaxd, nullptr);
18587             diff = cosmaxd - fc->cosdihed_in;
18588             if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18589             if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18590               rejflag = 1;
18591             } else {
18592               // Record the largest new angle.
18593               if (cosmaxd < fc->cosdihed_out) {
18594                 fc->cosdihed_out = cosmaxd;
18595               }
18596             }
18597           }
18598         } // edgepivot
18599       } // level
18600     }
18601   }
18602 
18603   return rejflag;
18604 }
18605 
18606 ///////////////////////////////////////////////////////////////////////////////
18607 //                                                                           //
18608 // removeedgebyflips()    Remove an edge by flips.                           //
18609 //                                                                           //
18610 // 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed.          //
18611 //                                                                           //
18612 // The return value is a positive integer, it indicates whether the edge is  //
18613 // removed or not.  A value "2" means the edge is removed, othereise, the    //
18614 // edge is not removed and the value (must >= 3) is the current number of    //
18615 // tets in the edge star.                                                    //
18616 //                                                                           //
18617 ///////////////////////////////////////////////////////////////////////////////
18618 
removeedgebyflips(triface * flipedge,flipconstraints * fc)18619 int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
18620 {
18621   triface *abtets, spintet;
18622   int t1ver;
18623   int n, nn, i;
18624 
18625 
18626   if (checksubsegflag) {
18627     // Do not flip a segment.
18628     if (issubseg(*flipedge)) {
18629       if (fc->collectencsegflag) {
18630         face checkseg, *paryseg;
18631         tsspivot1(*flipedge, checkseg);
18632         if (!sinfected(checkseg)) {
18633           // Queue this segment in list.
18634           sinfect(checkseg);
18635           caveencseglist->newindex((void **) &paryseg);
18636           *paryseg = checkseg;
18637         }
18638       }
18639       return 0;
18640     }
18641   }
18642 
18643   // Count the number of tets at edge [a,b].
18644   n = 0;
18645   spintet = *flipedge;
18646   while (1) {
18647     n++;
18648     fnextself(spintet);
18649     if (spintet.tet == flipedge->tet) break;
18650   }
18651   assert(n >= 3);
18652 
18653   if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
18654     // The star size exceeds the limit.
18655     return 0; // Do not flip it.
18656   }
18657 
18658   // Allocate spaces.
18659   abtets = new triface[n];
18660   // Collect the tets at edge [a,b].
18661   spintet = *flipedge;
18662   i = 0;
18663   while (1) {
18664     abtets[i] = spintet;
18665     setelemcounter(abtets[i], 1);
18666     i++;
18667     fnextself(spintet);
18668     if (spintet.tet == flipedge->tet) break;
18669   }
18670 
18671 
18672   // Try to flip the edge (level = 0, edgepivot = 0).
18673   nn = flipnm(abtets, n, 0, 0, fc);
18674 
18675 
18676   if (nn > 2) {
18677     // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
18678     for (i = 0; i < nn; i++) {
18679       setelemcounter(abtets[i], 0);
18680     }
18681     // Restore the input edge (needed by Lawson's flip).
18682     *flipedge = abtets[0];
18683   }
18684 
18685   // Release the temporary allocated spaces.
18686   // NOTE: fc->unflip must be 0.
18687   int bakunflip = fc->unflip;
18688   fc->unflip = 0;
18689   flipnm_post(abtets, n, nn, 0, fc);
18690   fc->unflip = bakunflip;
18691 
18692   delete [] abtets;
18693 
18694   return nn;
18695 }
18696 
18697 ///////////////////////////////////////////////////////////////////////////////
18698 //                                                                           //
18699 // removefacebyflips()    Remove a face by flips.                            //
18700 //                                                                           //
18701 // Return 1 if the face is removed. Otherwise, return 0.                     //
18702 //                                                                           //
18703 // ASSUMPTIONS:                                                              //
18704 //   - 'flipface' must not be a hull face.                                   //
18705 //                                                                           //
18706 ///////////////////////////////////////////////////////////////////////////////
18707 
removefacebyflips(triface * flipface,flipconstraints * fc)18708 int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
18709 {
18710   if (checksubfaceflag) {
18711     if (issubface(*flipface)) {
18712       return 0;
18713     }
18714   }
18715 
18716   triface fliptets[3], flipedge;
18717   point pa, pb, pc, pd, pe;
18718   REAL ori;
18719   int reducflag = 0;
18720 
18721   fliptets[0] = *flipface;
18722   fsym(*flipface, fliptets[1]);
18723   pa = org(fliptets[0]);
18724   pb = dest(fliptets[0]);
18725   pc = apex(fliptets[0]);
18726   pd = oppo(fliptets[0]);
18727   pe = oppo(fliptets[1]);
18728 
18729   ori = orient3d(pa, pb, pd, pe);
18730   if (ori > 0) {
18731     ori = orient3d(pb, pc, pd, pe);
18732     if (ori > 0) {
18733       ori = orient3d(pc, pa, pd, pe);
18734       if (ori > 0) {
18735         // Found a 2-to-3 flip.
18736         reducflag = 1;
18737       } else {
18738         eprev(*flipface, flipedge); // [c,a]
18739       }
18740     } else {
18741       enext(*flipface, flipedge); // [b,c]
18742     }
18743   } else {
18744     flipedge = *flipface; // [a,b]
18745   }
18746 
18747   if (reducflag) {
18748     // A 2-to-3 flip is found.
18749     flip23(fliptets, 0, fc);
18750     return 1;
18751   } else {
18752     // Try to flip the selected edge of this face.
18753     if (removeedgebyflips(&flipedge, fc) == 2) {
18754       return 1;
18755     }
18756   }
18757 
18758   // Face is not removed.
18759   return 0;
18760 }
18761 
18762 ///////////////////////////////////////////////////////////////////////////////
18763 //                                                                           //
18764 // recoveredge()    Recover an edge in current tetrahedralization.           //
18765 //                                                                           //
18766 // If the edge is recovered, 'searchtet' returns a tet containing the edge.  //
18767 //                                                                           //
18768 // This edge may intersect a set of faces and edges in the mesh.  All these  //
18769 // faces or edges are needed to be removed.                                  //
18770 //                                                                           //
18771 // If the parameter 'fullsearch' is set, it tries to flip any face or edge   //
18772 // that intersects the recovering edge.  Otherwise, only the face or edge    //
18773 // which is visible by 'startpt' is tried.                                   //
18774 //                                                                           //
18775 ///////////////////////////////////////////////////////////////////////////////
18776 
recoveredgebyflips(point startpt,point endpt,triface * searchtet,int fullsearch)18777 int tetgenmesh::recoveredgebyflips(point startpt, point endpt,
18778                                    triface* searchtet, int fullsearch)
18779 {
18780   flipconstraints fc;
18781   enum interresult dir;
18782 
18783   fc.seg[0] = startpt;
18784   fc.seg[1] = endpt;
18785   fc.checkflipeligibility = 1;
18786 
18787   // The mainloop of the edge reocvery.
18788   while (1) { // Loop I
18789 
18790     // Search the edge from 'startpt'.
18791     point2tetorg(startpt, *searchtet);
18792     dir = finddirection(searchtet, endpt);
18793     if (dir == ACROSSVERT) {
18794       if (dest(*searchtet) == endpt) {
18795         return 1; // Edge is recovered.
18796       } else {
18797         terminatetetgen(3); // // It may be a PLC problem.
18798       }
18799     }
18800 
18801     // The edge is missing.
18802 
18803     // Try to flip the first intersecting face/edge.
18804     enextesymself(*searchtet); // Go to the opposite face.
18805     if (dir == ACROSSFACE) {
18806       // A face is intersected with the segment. Try to flip it.
18807       if (removefacebyflips(searchtet, &fc)) {
18808         continue;
18809       }
18810     } else if (dir == ACROSSEDGE) {
18811       // An edge is intersected with the segment. Try to flip it.
18812       if (removeedgebyflips(searchtet, &fc) == 2) {
18813         continue;
18814       }
18815     } else {
18816       terminatetetgen(3); // It may be a PLC problem.
18817     }
18818 
18819     // The edge is missing.
18820 
18821     if (fullsearch) {
18822       // Try to flip one of the faces/edges which intersects the edge.
18823       triface neightet, spintet;
18824       point pa, pb, pc, pd;
18825       badface bakface;
18826       enum interresult dir1;
18827       int types[2], poss[4], pos = 0;
18828       int success = 0;
18829       int t1ver;
18830       int i, j;
18831 
18832       // Loop through the sequence of intersecting faces/edges from
18833       //   'startpt' to 'endpt'.
18834       point2tetorg(startpt, *searchtet);
18835       dir = finddirection(searchtet, endpt);
18836       //assert(dir != ACROSSVERT);
18837 
18838       // Go to the face/edge intersecting the searching edge.
18839       enextesymself(*searchtet); // Go to the opposite face.
18840       // This face/edge has been tried in previous step.
18841 
18842       while (1) { // Loop I-I
18843 
18844         // Find the next intersecting face/edge.
18845         fsymself(*searchtet);
18846         if (dir == ACROSSFACE) {
18847           neightet = *searchtet;
18848           j = (neightet.ver & 3); // j is the current face number.
18849           for (i = j + 1; i < j + 4; i++) {
18850             neightet.ver = (i % 4);
18851             pa = org(neightet);
18852             pb = dest(neightet);
18853             pc = apex(neightet);
18854             pd = oppo(neightet); // The above point.
18855             if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
18856               dir = (enum interresult) types[0];
18857               pos = poss[0];
18858               break;
18859             } else {
18860               dir = DISJOINT;
18861               pos = 0;
18862             }
18863           } // i
18864           // There must be an intersection face/edge.
18865           assert(dir != DISJOINT);  // SELF_CHECK
18866         } else {
18867           assert(dir == ACROSSEDGE);
18868           while (1) { // Loop I-I-I
18869             // Check the two opposite faces (of the edge) in 'searchtet'.
18870             for (i = 0; i < 2; i++) {
18871               if (i == 0) {
18872                 enextesym(*searchtet, neightet);
18873               } else {
18874                 eprevesym(*searchtet, neightet);
18875               }
18876               pa = org(neightet);
18877               pb = dest(neightet);
18878               pc = apex(neightet);
18879               pd = oppo(neightet); // The above point.
18880               if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
18881                 dir = (enum interresult) types[0];
18882                 pos = poss[0];
18883                 break; // for loop
18884               } else {
18885                 dir = DISJOINT;
18886                 pos = 0;
18887               }
18888             } // i
18889             if (dir != DISJOINT) {
18890               // Find an intersection face/edge.
18891               break;  // Loop I-I-I
18892             }
18893             // No intersection. Rotate to the next tet at the edge.
18894             fnextself(*searchtet);
18895           } // while (1) // Loop I-I-I
18896         }
18897 
18898         // Adjust to the intersecting edge/vertex.
18899         for (i = 0; i < pos; i++) {
18900           enextself(neightet);
18901         }
18902 
18903         if (dir == SHAREVERT) {
18904           // Check if we have reached the 'endpt'.
18905           pd = org(neightet);
18906           if (pd == endpt) {
18907             // Failed to recover the edge.
18908             break; // Loop I-I
18909           } else {
18910             // We need to further check this case. It might be a PLC problem
18911             //   or a Steiner point that was added at a bad location.
18912             assert(0);
18913           }
18914         }
18915 
18916         // The next to be flipped face/edge.
18917         *searchtet = neightet;
18918 
18919         // Bakup this face (tetrahedron).
18920         bakface.forg = org(*searchtet);
18921         bakface.fdest = dest(*searchtet);
18922         bakface.fapex = apex(*searchtet);
18923         bakface.foppo = oppo(*searchtet);
18924 
18925         // Try to flip this intersecting face/edge.
18926         if (dir == ACROSSFACE) {
18927           if (removefacebyflips(searchtet, &fc)) {
18928             success = 1;
18929             break; // Loop I-I
18930           }
18931         } else if (dir == ACROSSEDGE) {
18932           if (removeedgebyflips(searchtet, &fc) == 2) {
18933             success = 1;
18934             break; // Loop I-I
18935           }
18936         } else {
18937           assert(0); // A PLC problem.
18938         }
18939 
18940         // The face/edge is not flipped.
18941         if ((searchtet->tet == nullptr) ||
18942             (org(*searchtet) != bakface.forg) ||
18943             (dest(*searchtet) != bakface.fdest) ||
18944             (apex(*searchtet) != bakface.fapex) ||
18945             (oppo(*searchtet) != bakface.foppo)) {
18946           // 'searchtet' was flipped. We must restore it.
18947           point2tetorg(bakface.forg, *searchtet);
18948           dir1 = finddirection(searchtet, bakface.fdest);
18949           if (dir1 == ACROSSVERT) {
18950             assert(dest(*searchtet) == bakface.fdest);
18951             spintet = *searchtet;
18952             while (1) {
18953               if (apex(spintet) == bakface.fapex) {
18954                 // Found the face.
18955                 *searchtet = spintet;
18956                 break;
18957               }
18958               fnextself(spintet);
18959               if (spintet.tet == searchtet->tet) {
18960                 searchtet->tet = nullptr;
18961                 break; // Not find.
18962               }
18963                 } // while (1)
18964             if (searchtet->tet != nullptr) {
18965               if (oppo(*searchtet) != bakface.foppo) {
18966                 fsymself(*searchtet);
18967                 if (oppo(*searchtet) != bakface.foppo) {
18968                   assert(0); // Check this case.
18969                   searchtet->tet = nullptr;
18970                   break; // Not find.
18971                 }
18972               }
18973             }
18974           } else {
18975             searchtet->tet = nullptr; // Not find.
18976           }
18977           if (searchtet->tet == nullptr) {
18978             success = 0; // This face/edge has been destroed.
18979             break; // Loop I-I
18980           }
18981         }
18982       } // while (1) // Loop I-I
18983 
18984       if (success) {
18985         // One of intersecting faces/edges is flipped.
18986         continue;
18987       }
18988 
18989     } // if (fullsearch)
18990 
18991     // The edge is missing.
18992     break; // Loop I
18993 
18994   } // while (1) // Loop I
18995 
18996   return 0;
18997 }
18998 
18999 ///////////////////////////////////////////////////////////////////////////////
19000 //                                                                           //
19001 // add_steinerpt_in_schoenhardtpoly()    Insert a Steiner point in a Schoen- //
19002 //                                       hardt polyhedron.                   //
19003 //                                                                           //
19004 // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
19005 // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)].  Moreover, //
19006 // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'.  A special  //
19007 // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b].       //
19008 // Such set of tets arises when we want to recover an edge from 'p0' to 'p_  //
19009 // (n-1)', and the number of tets at [a,b] can not be reduced by any flip.   //
19010 //                                                                           //
19011 ///////////////////////////////////////////////////////////////////////////////
19012 
add_steinerpt_in_schoenhardtpoly(triface * abtets,int n,int chkencflag)19013 int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
19014                                                  int chkencflag)
19015 {
19016   triface worktet, *parytet;
19017   triface faketet1, faketet2;
19018   point pc, pd, steinerpt;
19019   insertvertexflags ivf;
19020   optparameters opm;
19021   REAL vcd[3], sampt[3], smtpt[3];
19022   REAL maxminvol = 0.0, minvol = 0.0, ori;
19023   int success, maxidx = 0;
19024   int it, i;
19025 
19026 
19027   pc = apex(abtets[0]);   // pc = p0
19028   pd = oppo(abtets[n-1]); // pd = p_(n-1)
19029 
19030 
19031   // Find an optimial point in edge [c,d]. It is visible by all outer faces
19032   //   of 'abtets', and it maxmizes the min volume.
19033 
19034   // initialize the list of 2n boundary faces.
19035   for (i = 0; i < n; i++) {
19036     edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
19037     cavetetlist->newindex((void **) &parytet);
19038     *parytet = worktet;
19039     eorgoppo(abtets[i], worktet);  // [p_i+1,p_i,b]
19040     cavetetlist->newindex((void **) &parytet);
19041     *parytet = worktet;
19042   }
19043 
19044   int N = 100;
19045   REAL stepi = 0.01;
19046 
19047   // Search the point along the edge [c,d].
19048   for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
19049 
19050   // Sample N points in edge [c,d].
19051   for (it = 1; it < N; it++) {
19052     for (i = 0; i < 3; i++) {
19053       sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
19054     }
19055     for (i = 0; i < cavetetlist->objects; i++) {
19056       parytet = (triface *) fastlookup(cavetetlist, i);
19057       ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
19058       if (i == 0) {
19059         minvol = ori;
19060       } else {
19061         if (minvol > ori) minvol = ori;
19062       }
19063     } // i
19064     if (it == 1) {
19065       maxminvol = minvol;
19066       maxidx = it;
19067     } else {
19068       if (maxminvol < minvol) {
19069         maxminvol = minvol;
19070         maxidx = it;
19071       }
19072     }
19073   } // it
19074 
19075   if (maxminvol <= 0) {
19076     cavetetlist->restart();
19077     return 0;
19078   }
19079 
19080   for (i = 0; i < 3; i++) {
19081     smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
19082   }
19083 
19084   // Create two faked tets to hold the two non-existing boundary faces:
19085   //   [d,c,a] and [c,d,b].
19086   maketetrahedron(&faketet1);
19087   setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
19088   cavetetlist->newindex((void **) &parytet);
19089   *parytet = faketet1;
19090   maketetrahedron(&faketet2);
19091   setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
19092   cavetetlist->newindex((void **) &parytet);
19093   *parytet = faketet2;
19094 
19095   // Point smooth options.
19096   opm.max_min_volume = 1;
19097   opm.numofsearchdirs = 20;
19098   opm.searchstep = 0.001;
19099   opm.maxiter = 100; // Limit the maximum iterations.
19100   opm.initval = 0.0; // Initial volume is zero.
19101 
19102   // Try to relocate the point into the inside of the polyhedron.
19103   success = smoothpoint(smtpt, cavetetlist, 1, &opm);
19104 
19105   if (success) {
19106     while (opm.smthiter == 100) {
19107       // It was relocated and the prescribed maximum iteration reached.
19108       // Try to increase the search stepsize.
19109       opm.searchstep *= 10.0;
19110       //opm.maxiter = 100; // Limit the maximum iterations.
19111       opm.initval = opm.imprval;
19112       opm.smthiter = 0; // Init.
19113       smoothpoint(smtpt, cavetetlist, 1, &opm);
19114     }
19115   } // if (success)
19116 
19117   // Delete the two faked tets.
19118   tetrahedrondealloc(faketet1.tet);
19119   tetrahedrondealloc(faketet2.tet);
19120 
19121   cavetetlist->restart();
19122 
19123   if (!success) {
19124     return 0;
19125   }
19126 
19127 
19128   // Insert the Steiner point.
19129   makepoint(&steinerpt, FREEVOLVERTEX);
19130   for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
19131 
19132   // Insert the created Steiner point.
19133   for (i = 0; i < n; i++) {
19134     infect(abtets[i]);
19135     caveoldtetlist->newindex((void **) &parytet);
19136     *parytet = abtets[i];
19137   }
19138   worktet = abtets[0]; // No need point location.
19139   ivf.iloc = (int) INSTAR;
19140   ivf.chkencflag = chkencflag;
19141   ivf.assignmeshsize = b->metric;
19142   if (ivf.assignmeshsize) {
19143     // Search the tet containing 'steinerpt' for size interpolation.
19144     locate(steinerpt, &(abtets[0]), 0);
19145     worktet = abtets[0];
19146   }
19147 
19148   // Insert the new point into the tetrahedralization T.
19149   // Note that T is convex (nonconvex = 0).
19150   if (insertpoint(steinerpt, &worktet, nullptr, nullptr, &ivf)) {
19151     // The vertex has been inserted.
19152     st_volref_count++;
19153     if (steinerleft > 0) steinerleft--;
19154     return 1;
19155   } else {
19156     // Not inserted.
19157     pointdealloc(steinerpt);
19158     return 0;
19159   }
19160 }
19161 
19162 ///////////////////////////////////////////////////////////////////////////////
19163 //                                                                           //
19164 // add_steinerpt_in_segment()    Add a Steiner point inside a segment.       //
19165 //                                                                           //
19166 ///////////////////////////////////////////////////////////////////////////////
19167 
add_steinerpt_in_segment(face * misseg,int searchlevel)19168 int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
19169 {
19170   triface searchtet;
19171   face *paryseg, candseg;
19172   point startpt, endpt, pc, pd;
19173   flipconstraints fc;
19174   enum interresult dir;
19175   REAL P[3], Q[3], tp, tq;
19176   REAL len, smlen = 0, split = 0, split_q = 0;
19177   int success;
19178   int i;
19179 
19180   startpt = sorg(*misseg);
19181   endpt = sdest(*misseg);
19182 
19183   fc.seg[0] = startpt;
19184   fc.seg[1] = endpt;
19185   fc.checkflipeligibility = 1;
19186   fc.collectencsegflag = 1;
19187 
19188   point2tetorg(startpt, searchtet);
19189   dir = finddirection(&searchtet, endpt);
19190   //assert(dir != ACROSSVERT);
19191 
19192   // Try to flip the first intersecting face/edge.
19193   enextesymself(searchtet); // Go to the opposite face.
19194 
19195   int bak_fliplinklevel = b->fliplinklevel;
19196   b->fliplinklevel = searchlevel;
19197 
19198   if (dir == ACROSSFACE) {
19199     // A face is intersected with the segment. Try to flip it.
19200     success = removefacebyflips(&searchtet, &fc);
19201     assert(success == 0);
19202   } else if (dir == ACROSSEDGE) {
19203     // An edge is intersected with the segment. Try to flip it.
19204     success = removeedgebyflips(&searchtet, &fc);
19205     assert(success != 2);
19206   } else {
19207     terminatetetgen(3); // It may be a PLC problem.
19208   }
19209 
19210   split = 0;
19211   for (i = 0; i < caveencseglist->objects; i++) {
19212     paryseg = (face *) fastlookup(caveencseglist, i);
19213     suninfect(*paryseg);
19214     // Calculate the shortest edge betwenn the two lines.
19215     pc = sorg(*paryseg);
19216     pd = sdest(*paryseg);
19217     tp = tq = 0;
19218     if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
19219       // Does the shortest edge lie between the two segments?
19220       // Round tp and tq.
19221       if ((tp > 0) && (tq < 1)) {
19222         if (tp < 0.5) {
19223           if (tp < (b->epsilon * 1e+3)) tp = 0.0;
19224         } else {
19225           if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
19226         }
19227       }
19228       if ((tp <= 0) || (tp >= 1)) continue;
19229       if ((tq > 0) && (tq < 1)) {
19230         if (tq < 0.5) {
19231           if (tq < (b->epsilon * 1e+3)) tq = 0.0;
19232         } else {
19233           if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
19234         }
19235       }
19236       if ((tq <= 0) || (tq >= 1)) continue;
19237       // It is a valid shortest edge. Calculate its length.
19238       len = distance(P, Q);
19239       if (split == 0) {
19240         smlen = len;
19241         split = tp;
19242         split_q = tq;
19243         candseg = *paryseg;
19244       } else {
19245         if (len < smlen) {
19246           smlen = len;
19247           split = tp;
19248           split_q = tq;
19249           candseg = *paryseg;
19250         }
19251       }
19252     }
19253   }
19254 
19255   caveencseglist->restart();
19256   b->fliplinklevel = bak_fliplinklevel;
19257 
19258   if (split == 0) {
19259     // Found no crossing segment.
19260     return 0;
19261   }
19262 
19263   face splitsh;
19264   face splitseg;
19265   point steinerpt, *parypt;
19266   insertvertexflags ivf;
19267 
19268   if (b->addsteiner_algo == 1) {
19269     // Split the segment at the closest point to a near segment.
19270     makepoint(&steinerpt, FREESEGVERTEX);
19271     for (i = 0; i < 3; i++) {
19272       steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19273     }
19274   } else { // b->addsteiner_algo == 2
19275     for (i = 0; i < 3; i++) {
19276       P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19277     }
19278     pc = sorg(candseg);
19279     pd = sdest(candseg);
19280     for (i = 0; i < 3; i++) {
19281       Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
19282     }
19283     makepoint(&steinerpt, FREEVOLVERTEX);
19284     for (i = 0; i < 3; i++) {
19285       steinerpt[i] = 0.5 * (P[i] + Q[i]);
19286     }
19287   }
19288 
19289   // We need to locate the point. Start searching from 'searchtet'.
19290   if (split < 0.5) {
19291     point2tetorg(startpt, searchtet);
19292   } else {
19293     point2tetorg(endpt, searchtet);
19294   }
19295   if (b->addsteiner_algo == 1) {
19296     splitseg = *misseg;
19297     spivot(*misseg, splitsh);
19298   } else {
19299     splitsh.sh = nullptr;
19300     splitseg.sh = nullptr;
19301   }
19302   ivf.iloc = (int) OUTSIDE;
19303   ivf.bowywat = 1;
19304   ivf.lawson = 0;
19305   ivf.rejflag = 0;
19306   ivf.chkencflag = 0;
19307   ivf.sloc = (int) ONEDGE;
19308   ivf.sbowywat = 1;
19309   ivf.splitbdflag = 0;
19310   ivf.validflag = 1;
19311   ivf.respectbdflag = 1;
19312   ivf.assignmeshsize = b->metric;
19313 
19314   if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
19315     pointdealloc(steinerpt);
19316     return 0;
19317   }
19318 
19319   if (b->addsteiner_algo == 1) {
19320     // Save this Steiner point (for removal).
19321     //   Re-use the array 'subvertstack'.
19322     subvertstack->newindex((void **) &parypt);
19323     *parypt = steinerpt;
19324     st_segref_count++;
19325   } else { // b->addsteiner_algo == 2
19326     // Queue the segment for recovery.
19327     subsegstack->newindex((void **) &paryseg);
19328     *paryseg = *misseg;
19329     st_volref_count++;
19330   }
19331   if (steinerleft > 0) steinerleft--;
19332 
19333   return 1;
19334 }
19335 
19336 ///////////////////////////////////////////////////////////////////////////////
19337 //                                                                           //
19338 // addsteiner4recoversegment()    Add a Steiner point for recoveing a seg.   //
19339 //                                                                           //
19340 ///////////////////////////////////////////////////////////////////////////////
19341 
addsteiner4recoversegment(face * misseg,int splitsegflag)19342 int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
19343 {
19344   triface *abtets, searchtet, spintet;
19345   face splitsh;
19346   face *paryseg;
19347   point startpt, endpt;
19348   point pa, pb, pd, steinerpt, *parypt;
19349   enum interresult dir;
19350   insertvertexflags ivf;
19351   int types[2], poss[4];
19352   int n, endi, success;
19353   int t1ver;
19354   int i;
19355 
19356   startpt = sorg(*misseg);
19357   if (pointtype(startpt) == FREESEGVERTEX) {
19358     sesymself(*misseg);
19359     startpt = sorg(*misseg);
19360   }
19361   endpt = sdest(*misseg);
19362 
19363   // Try to recover the edge by adding Steiner points.
19364   point2tetorg(startpt, searchtet);
19365   dir = finddirection(&searchtet, endpt);
19366   enextself(searchtet);
19367   //assert(apex(searchtet) == startpt);
19368 
19369   if (dir == ACROSSFACE) {
19370     // The segment is crossing at least 3 faces. Find the common edge of
19371     //   the first 3 crossing faces.
19372     esymself(searchtet);
19373     fsym(searchtet, spintet);
19374     pd = oppo(spintet);
19375     for (i = 0; i < 3; i++) {
19376       pa = org(spintet);
19377       pb = dest(spintet);
19378       //pc = apex(neightet);
19379       if (tri_edge_test(pa, pb, pd, startpt, endpt, nullptr, 1, types, poss)) {
19380         break; // Found the edge.
19381       }
19382       enextself(spintet);
19383       eprevself(searchtet);
19384     }
19385     assert(i < 3);
19386     esymself(searchtet);
19387   } else {
19388     assert(dir == ACROSSEDGE);
19389     // PLC check.
19390     if (issubseg(searchtet)) {
19391       face checkseg;
19392       tsspivot1(searchtet, checkseg);
19393       printf("Found two segments intersect each other.\n");
19394       pa = farsorg(*misseg);
19395       pb = farsdest(*misseg);
19396       printf("  1st: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19397              shellmark(*misseg));
19398       pa = farsorg(checkseg);
19399       pb = farsdest(checkseg);
19400       printf("  2nd: [%d,%d] %d.\n", pointmark(pa), pointmark(pb),
19401              shellmark(checkseg));
19402       terminatetetgen(3);
19403     }
19404   }
19405   assert(apex(searchtet) == startpt);
19406 
19407   spintet = searchtet;
19408   n = 0; endi = -1;
19409   while (1) {
19410     // Check if the endpt appears in the star.
19411     if (apex(spintet) == endpt) {
19412       endi = n; // Remember the position of endpt.
19413     }
19414     n++; // Count a tet in the star.
19415     fnextself(spintet);
19416     if (spintet.tet == searchtet.tet) break;
19417   }
19418   assert(n >= 3);
19419 
19420   if (endi > 0) {
19421     // endpt is also in the edge star
19422     // Get all tets in the edge star.
19423     abtets = new triface[n];
19424     spintet = searchtet;
19425     for (i = 0; i < n; i++) {
19426       abtets[i] = spintet;
19427       fnextself(spintet);
19428     }
19429 
19430     success = 0;
19431 
19432     if (dir == ACROSSFACE) {
19433       // Find a Steiner points inside the polyhedron.
19434       if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19435         success = 1;
19436       }
19437     } else if (dir == ACROSSEDGE) {
19438       if (n > 4) {
19439         // In this case, 'abtets' is separated by the plane (containing the
19440         //   two intersecting edges) into two parts, P1 and P2, where P1
19441         //   consists of 'endi' tets: abtets[0], abtets[1], ...,
19442         //   abtets[endi-1], and P2 consists of 'n - endi' tets:
19443         //   abtets[endi], abtets[endi+1], abtets[n-1].
19444         if (endi > 2) { // P1
19445           // There are at least 3 tets in the first part.
19446           if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19447             success++;
19448           }
19449         }
19450         if ((n - endi) > 2) { // P2
19451           // There are at least 3 tets in the first part.
19452           if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
19453             success++;
19454           }
19455         }
19456       } else {
19457         // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
19458         //   However, there will be invalid tets (either zero or negtive
19459         //   volume). Otherwise, [c,d] should already be recovered by the
19460         //   recoveredge() function.
19461         assert(0); // DEBUG IT
19462       }
19463     } else {
19464       assert(0); // A PLC problem.
19465     }
19466 
19467     delete [] abtets;
19468 
19469     if (success) {
19470       // Add the missing segment back to the recovering list.
19471       subsegstack->newindex((void **) &paryseg);
19472       *paryseg = *misseg;
19473       return 1;
19474     }
19475   } // if (endi > 0)
19476 
19477   if (!splitsegflag) {
19478     return 0;
19479   }
19480 
19481   if (b->verbose > 2) {
19482     printf("      Splitting segment (%d, %d)\n", pointmark(startpt),
19483            pointmark(endpt));
19484   }
19485   steinerpt = nullptr;
19486 
19487   if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
19488     if (add_steinerpt_in_segment(misseg, 3)) {
19489       return 1;
19490     }
19491     sesymself(*misseg);
19492     if (add_steinerpt_in_segment(misseg, 3)) {
19493       return 1;
19494     }
19495     sesymself(*misseg);
19496   }
19497 
19498 
19499 
19500 
19501   if (steinerpt == nullptr) {
19502     // Split the segment at its midpoint.
19503     makepoint(&steinerpt, FREESEGVERTEX);
19504     for (i = 0; i < 3; i++) {
19505       steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
19506     }
19507 
19508     // We need to locate the point.
19509     assert(searchtet.tet != nullptr); // Start searching from 'searchtet'.
19510     spivot(*misseg, splitsh);
19511     ivf.iloc = (int) OUTSIDE;
19512     ivf.bowywat = 1;
19513     ivf.lawson = 0;
19514     ivf.rejflag = 0;
19515     ivf.chkencflag = 0;
19516     ivf.sloc = (int) ONEDGE;
19517     ivf.sbowywat = 1;
19518     ivf.splitbdflag = 0;
19519     ivf.validflag = 1;
19520     ivf.respectbdflag = 1;
19521     ivf.assignmeshsize = b->metric;
19522     if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
19523       assert(0);
19524     }
19525   } // if (endi > 0)
19526 
19527   // Save this Steiner point (for removal).
19528   //   Re-use the array 'subvertstack'.
19529   subvertstack->newindex((void **) &parypt);
19530   *parypt = steinerpt;
19531 
19532   st_segref_count++;
19533   if (steinerleft > 0) steinerleft--;
19534 
19535   return 1;
19536 }
19537 
19538 ///////////////////////////////////////////////////////////////////////////////
19539 //                                                                           //
19540 // recoversegments()    Recover all segments.                                //
19541 //                                                                           //
19542 // All segments need to be recovered are in 'subsegstack'.                   //
19543 //                                                                           //
19544 // This routine first tries to recover each segment by only using flips. If  //
19545 // no flip is possible, and the flag 'steinerflag' is set, it then tries to  //
19546 // insert Steiner points near or in the segment.                             //
19547 //                                                                           //
19548 ///////////////////////////////////////////////////////////////////////////////
19549 
recoversegments(arraypool * misseglist,int fullsearch,int steinerflag)19550 int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
19551                                 int steinerflag)
19552 {
19553   triface searchtet, spintet;
19554   face sseg, *paryseg;
19555   point startpt, endpt;
19556   int success;
19557   int t1ver;
19558   long bak_inpoly_count = st_volref_count;
19559   long bak_segref_count = st_segref_count;
19560 
19561   if (b->verbose > 1) {
19562     printf("    Recover segments [%s level = %2d] #:  %ld.\n",
19563            (b->fliplinklevel > 0) ? "fixed" : "auto",
19564            (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19565            subsegstack->objects);
19566   }
19567 
19568   // Loop until 'subsegstack' is empty.
19569   while (subsegstack->objects > 0l) {
19570     // seglist is used as a stack.
19571     subsegstack->objects--;
19572     paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
19573     sseg = *paryseg;
19574 
19575     // Check if this segment has been recovered.
19576     sstpivot1(sseg, searchtet);
19577     if (searchtet.tet != nullptr) {
19578       continue; // Not a missing segment.
19579     }
19580 
19581     startpt = sorg(sseg);
19582     endpt = sdest(sseg);
19583 
19584     if (b->verbose > 2) {
19585       printf("      Recover segment (%d, %d).\n", pointmark(startpt),
19586              pointmark(endpt));
19587     }
19588 
19589     success = 0;
19590 
19591     if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19592       success = 1;
19593     } else {
19594       // Try to recover it from the other direction.
19595       if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19596         success = 1;
19597       }
19598     }
19599 
19600     if (!success && fullsearch) {
19601       if (recoveredgebyflips(startpt, endpt, &searchtet, fullsearch)) {
19602         success = 1;
19603       }
19604     }
19605 
19606     if (success) {
19607       // Segment is recovered. Insert it.
19608       // Let the segment remember an adjacent tet.
19609       sstbond1(sseg, searchtet);
19610       // Bond the segment to all tets containing it.
19611       spintet = searchtet;
19612       do {
19613         tssbond1(spintet, sseg);
19614         fnextself(spintet);
19615       } while (spintet.tet != searchtet.tet);
19616     } else {
19617       if (steinerflag > 0) {
19618         // Try to recover the segment but do not split it.
19619         if (addsteiner4recoversegment(&sseg, 0)) {
19620           success = 1;
19621         }
19622         if (!success && (steinerflag > 1)) {
19623           // Split the segment.
19624           addsteiner4recoversegment(&sseg, 1);
19625           success = 1;
19626         }
19627       }
19628       if (!success) {
19629         if (misseglist != nullptr) {
19630           // Save this segment.
19631           misseglist->newindex((void **) &paryseg);
19632           *paryseg = sseg;
19633         }
19634       }
19635     }
19636 
19637   } // while (subsegstack->objects > 0l)
19638 
19639   if (steinerflag) {
19640     if (b->verbose > 1) {
19641       // Report the number of added Steiner points.
19642       if (st_volref_count > bak_inpoly_count) {
19643         printf("    Add %ld Steiner points in volume.\n",
19644                st_volref_count - bak_inpoly_count);
19645       }
19646       if (st_segref_count > bak_segref_count) {
19647         printf("    Add %ld Steiner points in segments.\n",
19648                st_segref_count - bak_segref_count);
19649       }
19650     }
19651   }
19652 
19653   return 0;
19654 }
19655 
19656 ///////////////////////////////////////////////////////////////////////////////
19657 //                                                                           //
19658 // recoverfacebyflips()    Recover a face by flips.                          //
19659 //                                                                           //
19660 // If 'searchsh' is not nullptr, it is a subface to be recovered.  It is only   //
19661 // used for checking self-intersections.                                     //
19662 //                                                                           //
19663 ///////////////////////////////////////////////////////////////////////////////
19664 
recoverfacebyflips(point pa,point pb,point pc,face * searchsh,triface * searchtet)19665 int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
19666                                    face *searchsh, triface* searchtet)
19667 {
19668   triface spintet, flipedge;
19669   point pd, pe;
19670   enum interresult dir;
19671   flipconstraints fc;
19672   int types[2], poss[4], intflag;
19673   int success, success1;
19674   int t1ver;
19675   int i, j;
19676 
19677 
19678   fc.fac[0] = pa;
19679   fc.fac[1] = pb;
19680   fc.fac[2] = pc;
19681   fc.checkflipeligibility = 1;
19682   success = 0;
19683 
19684   for (i = 0; i < 3 && !success; i++) {
19685     while (1) {
19686       // Get a tet containing the edge [a,b].
19687       point2tetorg(fc.fac[i], *searchtet);
19688       dir = finddirection(searchtet, fc.fac[(i+1)%3]);
19689       //assert(dir == ACROSSVERT);
19690       assert(dest(*searchtet) == fc.fac[(i+1)%3]);
19691       // Search the face [a,b,c]
19692       spintet = *searchtet;
19693       while (1) {
19694         if (apex(spintet) == fc.fac[(i+2)%3]) {
19695           // Found the face.
19696           *searchtet = spintet;
19697           // Return the face [a,b,c].
19698           for (j = i; j > 0; j--) {
19699             eprevself(*searchtet);
19700           }
19701           success = 1;
19702           break;
19703         }
19704         fnextself(spintet);
19705         if (spintet.tet == searchtet->tet) break;
19706       } // while (1)
19707       if (success) break;
19708       // The face is missing. Try to recover it.
19709       success1 = 0;
19710       // Find a crossing edge of this face.
19711       spintet = *searchtet;
19712       while (1) {
19713         pd = apex(spintet);
19714         pe = oppo(spintet);
19715         if ((pd != dummypoint) && (pe != dummypoint)) {
19716           // Check if [d,e] intersects [a,b,c]
19717           intflag = tri_edge_test(pa, pb, pc, pd, pe, nullptr, 1, types, poss);
19718           if (intflag > 0) {
19719             // By our assumptions, they can only intersect at a single point.
19720             if (intflag == 2) {
19721               // Check the intersection type.
19722               dir = (enum interresult) types[0];
19723               if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
19724                 // Go to the edge [d,e].
19725                 edestoppo(spintet, flipedge); // [d,e,a,b]
19726                 if (searchsh != nullptr) {
19727                   // Check if [e,d] is a segment.
19728                   if (issubseg(flipedge)) {
19729                     if (!b->quiet) {
19730                         face checkseg;
19731                         tsspivot1(flipedge, checkseg);
19732                         printf("Found a segment and a subface intersect.\n");
19733                         pd = farsorg(checkseg);
19734                         pe = farsdest(checkseg);
19735                         printf("  1st: [%d, %d] %d.\n",  pointmark(pd),
19736                                pointmark(pe), shellmark(checkseg));
19737                         printf("  2nd: [%d,%d,%d] %d\n", pointmark(pa),
19738                                pointmark(pb), pointmark(pc), shellmark(*searchsh));
19739                     }
19740                     // [Bruno] Keep track of intersecting facets.
19741                     in->isectfaces.insert(shellmark(*searchsh));
19742                     terminatetetgen(3);
19743                   }
19744                 }
19745                 // Try to flip the edge [d,e].
19746                 success1 = (removeedgebyflips(&flipedge, &fc) == 2);
19747               } else {
19748                 if (dir == TOUCHFACE) {
19749                   point touchpt, *parypt;
19750                   if (poss[1] == 0) {
19751                     touchpt = pd; // pd is a coplanar vertex.
19752                   } else {
19753                     touchpt = pe; // pe is a coplanar vertex.
19754                   }
19755                   if (pointtype(touchpt) == FREEVOLVERTEX) {
19756                     // A volume Steiner point was added in this subface.
19757                     // Split this subface by this point.
19758                     face checksh, *parysh;
19759                     int siloc = (int) ONFACE;
19760                     int sbowat = 0; // Only split this subface.
19761                     setpointtype(touchpt, FREEFACETVERTEX);
19762                     sinsertvertex(touchpt, searchsh, nullptr, siloc, sbowat, 0);
19763                     st_volref_count--;
19764                     st_facref_count++;
19765                     // Queue this vertex for removal.
19766                     subvertstack->newindex((void **) &parypt);
19767                     *parypt = touchpt;
19768                     // Queue new subfaces for recovery.
19769                     // Put all new subfaces into stack for recovery.
19770                     for (i = 0; i < caveshbdlist->objects; i++) {
19771                       // Get an old subface at edge [a, b].
19772                       parysh = (face *) fastlookup(caveshbdlist, i);
19773                       spivot(*parysh, checksh); // The new subface [a, b, p].
19774                       // Do not recover a deleted new face (degenerated).
19775                       if (checksh.sh[3] != nullptr) {
19776                         subfacstack->newindex((void **) &parysh);
19777                         *parysh = checksh;
19778                       }
19779                     }
19780                     // Delete the old subfaces in sC(p).
19781                     assert(caveshlist->objects == 1);
19782                     for (i = 0; i < caveshlist->objects; i++) {
19783                       parysh = (face *) fastlookup(caveshlist, i);
19784                       shellfacedealloc(subfaces, parysh->sh);
19785                     }
19786                     // Clear working lists.
19787                     caveshlist->restart();
19788                     caveshbdlist->restart();
19789                     cavesegshlist->restart();
19790                     // We can return this function.
19791                     searchsh->sh = nullptr; // It has been split.
19792                     success1 = 0;
19793                     success = 1;
19794                   } else {
19795                     // It should be a PLC problem.
19796                     if (pointtype(touchpt) == FREESEGVERTEX) {
19797                       // A segment and a subface intersect.
19798                     } else if (pointtype(touchpt) == FREEFACETVERTEX) {
19799                       // Two facets self-intersect.
19800                     }
19801                     terminatetetgen(3);
19802                   }
19803                 } else {
19804                   assert(0); // Unknown cases. Debug.
19805                 }
19806               }
19807               break;
19808             } else { // intflag == 4. Coplanar case.
19809               // This may be an input PLC error.
19810               assert(0);
19811             }
19812           } // if (intflag > 0)
19813         }
19814         fnextself(spintet);
19815         assert(spintet.tet != searchtet->tet);
19816       } // while (1)
19817       if (!success1) break;
19818     } // while (1)
19819   } // i
19820 
19821   return success;
19822 }
19823 
19824 ///////////////////////////////////////////////////////////////////////////////
19825 //                                                                           //
19826 // recoversubfaces()    Recover all subfaces.                                //
19827 //                                                                           //
19828 ///////////////////////////////////////////////////////////////////////////////
19829 
recoversubfaces(arraypool * misshlist,int steinerflag)19830 int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
19831 {
19832   triface searchtet, neightet, spintet;
19833   face searchsh, neighsh, neineish, *parysh;
19834   face bdsegs[3];
19835   point startpt, endpt, apexpt, *parypt;
19836   point steinerpt;
19837   enum interresult dir;
19838   insertvertexflags ivf;
19839   int success;
19840   int t1ver;
19841   int i, j;
19842 
19843   if (b->verbose > 1) {
19844     printf("    Recover subfaces [%s level = %2d] #:  %ld.\n",
19845            (b->fliplinklevel > 0) ? "fixed" : "auto",
19846            (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19847            subfacstack->objects);
19848   }
19849 
19850   // Loop until 'subfacstack' is empty.
19851   while (subfacstack->objects > 0l) {
19852 
19853     subfacstack->objects--;
19854     parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
19855     searchsh = *parysh;
19856 
19857     if (searchsh.sh[3] == nullptr) continue; // Skip a dead subface.
19858 
19859     stpivot(searchsh, neightet);
19860     if (neightet.tet != nullptr) continue; // Skip a recovered subface.
19861 
19862 
19863     if (b->verbose > 2) {
19864       printf("      Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
19865              pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
19866     }
19867 
19868     // The three edges of the face need to be existed first.
19869     for (i = 0; i < 3; i++) {
19870       sspivot(searchsh, bdsegs[i]);
19871       if (bdsegs[i].sh != nullptr) {
19872         // The segment must exist.
19873         sstpivot1(bdsegs[i], searchtet);
19874         if (searchtet.tet == nullptr) {
19875           assert(0);
19876         }
19877       } else {
19878         // This edge is not a segment (due to a Steiner point).
19879         // Check whether it exists or not.
19880         success = 0;
19881         startpt = sorg(searchsh);
19882         endpt = sdest(searchsh);
19883         point2tetorg(startpt, searchtet);
19884         dir = finddirection(&searchtet, endpt);
19885         if (dir == ACROSSVERT) {
19886           if (dest(searchtet) == endpt) {
19887             success = 1;
19888           } else {
19889             //assert(0); // A PLC problem.
19890             terminatetetgen(3);
19891           }
19892         } else {
19893           // The edge is missing. Try to recover it.
19894           if (recoveredgebyflips(startpt, endpt, &searchtet, 0)) {
19895             success = 1;
19896           } else {
19897             if (recoveredgebyflips(endpt, startpt, &searchtet, 0)) {
19898               success = 1;
19899             }
19900           }
19901         }
19902         if (success) {
19903           // Insert a temporary segment to protect this edge.
19904           makeshellface(subsegs, &(bdsegs[i]));
19905           setshvertices(bdsegs[i], startpt, endpt, nullptr);
19906           smarktest2(bdsegs[i]); // It's a temporary segment.
19907           // Insert this segment into surface mesh.
19908           ssbond(searchsh, bdsegs[i]);
19909           spivot(searchsh, neighsh);
19910           if (neighsh.sh != nullptr) {
19911             ssbond(neighsh, bdsegs[i]);
19912           }
19913           // Insert this segment into tetrahedralization.
19914           sstbond1(bdsegs[i], searchtet);
19915           // Bond the segment to all tets containing it.
19916           spintet = searchtet;
19917           do {
19918             tssbond1(spintet, bdsegs[i]);
19919             fnextself(spintet);
19920           } while (spintet.tet != searchtet.tet);
19921         } else {
19922           // An edge of this subface is missing. Can't recover this subface.
19923           // Delete any temporary segment that has been created.
19924           for (j = (i - 1); j >= 0; j--) {
19925             if (smarktest2ed(bdsegs[j])) {
19926               spivot(bdsegs[j], neineish);
19927               assert(neineish.sh != nullptr);
19928               //if (neineish.sh != nullptr) {
19929                 ssdissolve(neineish);
19930                 spivot(neineish, neighsh);
19931                 if (neighsh.sh != nullptr) {
19932                   ssdissolve(neighsh);
19933                   // There should be only two subfaces at this segment.
19934                   spivotself(neighsh); // SELF_CHECK
19935                   assert(neighsh.sh == neineish.sh);
19936                 }
19937                   //}
19938               sstpivot1(bdsegs[j], searchtet);
19939               assert(searchtet.tet != nullptr);
19940               //if (searchtet.tet != nullptr) {
19941                 spintet = searchtet;
19942                 while (1) {
19943                   tssdissolve1(spintet);
19944                   fnextself(spintet);
19945                   if (spintet.tet == searchtet.tet) break;
19946                 }
19947                   //}
19948               shellfacedealloc(subsegs, bdsegs[j].sh);
19949             }
19950           } // j
19951           if (steinerflag) {
19952             // Add a Steiner point at the midpoint of this edge.
19953             if (b->verbose > 2) {
19954               printf("      Add a Steiner point in subedge (%d, %d).\n",
19955                      pointmark(startpt), pointmark(endpt));
19956             }
19957             makepoint(&steinerpt, FREEFACETVERTEX);
19958             for (j = 0; j < 3; j++) {
19959               steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
19960             }
19961 
19962             point2tetorg(startpt, searchtet); // Start from 'searchtet'.
19963             ivf.iloc = (int) OUTSIDE; // Need point location.
19964             ivf.bowywat = 1;
19965             ivf.lawson = 0;
19966             ivf.rejflag = 0;
19967             ivf.chkencflag = 0;
19968             ivf.sloc = (int) ONEDGE;
19969             ivf.sbowywat = 1; // Allow flips in facet.
19970             ivf.splitbdflag = 0;
19971             ivf.validflag = 1;
19972             ivf.respectbdflag = 1;
19973             ivf.assignmeshsize = b->metric;
19974             if (!insertpoint(steinerpt, &searchtet, &searchsh, nullptr, &ivf)) {
19975               assert(0);
19976             }
19977             // Save this Steiner point (for removal).
19978             //   Re-use the array 'subvertstack'.
19979             subvertstack->newindex((void **) &parypt);
19980             *parypt = steinerpt;
19981 
19982             st_facref_count++;
19983             if (steinerleft > 0) steinerleft--;
19984           } // if (steinerflag)
19985           break;
19986         }
19987       }
19988       senextself(searchsh);
19989     } // i
19990 
19991     if (i == 3) {
19992       // Recover the subface.
19993       startpt = sorg(searchsh);
19994       endpt   = sdest(searchsh);
19995       apexpt  = sapex(searchsh);
19996 
19997       success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
19998 
19999       // Delete any temporary segment that has been created.
20000       for (j = 0; j < 3; j++) {
20001         if (smarktest2ed(bdsegs[j])) {
20002           spivot(bdsegs[j], neineish);
20003           assert(neineish.sh != nullptr);
20004           //if (neineish.sh != nullptr) {
20005             ssdissolve(neineish);
20006             spivot(neineish, neighsh);
20007             if (neighsh.sh != nullptr) {
20008               ssdissolve(neighsh);
20009               // There should be only two subfaces at this segment.
20010               spivotself(neighsh); // SELF_CHECK
20011               assert(neighsh.sh == neineish.sh);
20012             }
20013               //}
20014           sstpivot1(bdsegs[j], neightet);
20015           assert(neightet.tet != nullptr);
20016           //if (neightet.tet != nullptr) {
20017             spintet = neightet;
20018             while (1) {
20019               tssdissolve1(spintet);
20020               fnextself(spintet);
20021               if (spintet.tet == neightet.tet) break;
20022             }
20023               //}
20024           shellfacedealloc(subsegs, bdsegs[j].sh);
20025         }
20026       } // j
20027 
20028       if (success) {
20029         if (searchsh.sh != nullptr) {
20030           // Face is recovered. Insert it.
20031           tsbond(searchtet, searchsh);
20032           fsymself(searchtet);
20033           sesymself(searchsh);
20034           tsbond(searchtet, searchsh);
20035         }
20036       } else {
20037         if (steinerflag) {
20038           // Add a Steiner point at the barycenter of this subface.
20039           if (b->verbose > 2) {
20040             printf("      Add a Steiner point in subface (%d, %d, %d).\n",
20041                    pointmark(startpt), pointmark(endpt), pointmark(apexpt));
20042           }
20043           makepoint(&steinerpt, FREEFACETVERTEX);
20044           for (j = 0; j < 3; j++) {
20045             steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
20046           }
20047 
20048           point2tetorg(startpt, searchtet); // Start from 'searchtet'.
20049           ivf.iloc = (int) OUTSIDE; // Need point location.
20050           ivf.bowywat = 1;
20051           ivf.lawson = 0;
20052           ivf.rejflag = 0;
20053           ivf.chkencflag = 0;
20054           ivf.sloc = (int) ONFACE;
20055           ivf.sbowywat = 1; // Allow flips in facet.
20056           ivf.splitbdflag = 0;
20057           ivf.validflag = 1;
20058           ivf.respectbdflag = 1;
20059           ivf.assignmeshsize = b->metric;
20060           if (!insertpoint(steinerpt, &searchtet, &searchsh, nullptr, &ivf)) {
20061             assert(0);
20062           }
20063           // Save this Steiner point (for removal).
20064           //   Re-use the array 'subvertstack'.
20065           subvertstack->newindex((void **) &parypt);
20066           *parypt = steinerpt;
20067 
20068           st_facref_count++;
20069           if (steinerleft > 0) steinerleft--;
20070         } // if (steinerflag)
20071       }
20072     } else {
20073       success = 0;
20074     }
20075 
20076     if (!success) {
20077       if (misshlist != nullptr) {
20078         // Save this subface.
20079         misshlist->newindex((void **) &parysh);
20080         *parysh = searchsh;
20081       }
20082     }
20083 
20084   } // while (subfacstack->objects > 0l)
20085 
20086   return 0;
20087 }
20088 
20089 ///////////////////////////////////////////////////////////////////////////////
20090 //                                                                           //
20091 // getvertexstar()    Return the star of a vertex.                           //
20092 //                                                                           //
20093 // If the flag 'fullstar' is set, return the complete star of this vertex.   //
20094 // Otherwise, only a part of the star which is bounded by facets is returned.//
20095 //                                                                           //
20096 // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'.  //
20097 // Every tet in 'tetlist' is at the face oppsiting to 'searchpt'.            //
20098 //                                                                           //
20099 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
20100 //                                                                           //
20101 // 'shlist' returns the list of subfaces in the star. Each subface must face //
20102 // to the interior of this star.                                             //
20103 //                                                                           //
20104 ///////////////////////////////////////////////////////////////////////////////
20105 
getvertexstar(int fullstar,point searchpt,arraypool * tetlist,arraypool * vertlist,arraypool * shlist)20106 int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
20107                               arraypool* vertlist, arraypool* shlist)
20108 {
20109   triface searchtet, neightet, *parytet;
20110   face checksh, *parysh;
20111   point pt, *parypt;
20112   int collectflag;
20113   int t1ver;
20114   int i, j;
20115 
20116   point2tetorg(searchpt, searchtet);
20117 
20118   // Go to the opposite face (the link face) of the vertex.
20119   enextesymself(searchtet);
20120   //assert(oppo(searchtet) == searchpt);
20121   infect(searchtet); // Collect this tet (link face).
20122   tetlist->newindex((void **) &parytet);
20123   *parytet = searchtet;
20124   if (vertlist != nullptr) {
20125     // Collect three (link) vertices.
20126     j = (searchtet.ver & 3); // The current vertex index.
20127     for (i = 1; i < 4; i++) {
20128       pt = (point) searchtet.tet[4 + ((j + i) % 4)];
20129       pinfect(pt);
20130       vertlist->newindex((void **) &parypt);
20131       *parypt = pt;
20132     }
20133   }
20134 
20135   collectflag = 1;
20136   esym(searchtet, neightet);
20137   if (issubface(neightet)) {
20138     if (shlist != nullptr) {
20139       tspivot(neightet, checksh);
20140       if (!sinfected(checksh)) {
20141         // Collect this subface (link edge).
20142         sinfected(checksh);
20143         shlist->newindex((void **) &parysh);
20144         *parysh = checksh;
20145       }
20146     }
20147     if (!fullstar) {
20148       collectflag = 0;
20149     }
20150   }
20151   if (collectflag) {
20152     fsymself(neightet); // Goto the adj tet of this face.
20153     esymself(neightet); // Goto the oppo face of this vertex.
20154     // assert(oppo(neightet) == searchpt);
20155     infect(neightet); // Collect this tet (link face).
20156     tetlist->newindex((void **) &parytet);
20157     *parytet = neightet;
20158     if (vertlist != nullptr) {
20159       // Collect its apex.
20160       pt = apex(neightet);
20161       pinfect(pt);
20162       vertlist->newindex((void **) &parypt);
20163       *parypt = pt;
20164     }
20165   } // if (collectflag)
20166 
20167   // Continue to collect all tets in the star.
20168   for (i = 0; i < tetlist->objects; i++) {
20169     searchtet = * (triface *) fastlookup(tetlist, i);
20170     // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
20171     //   tet at the current edge is already collected.
20172     // Check the neighors at the other two edges of this face.
20173     for (j = 0; j < 2; j++) {
20174       collectflag = 1;
20175       enextself(searchtet);
20176       esym(searchtet, neightet);
20177       if (issubface(neightet)) {
20178         if (shlist != nullptr) {
20179           tspivot(neightet, checksh);
20180           if (!sinfected(checksh)) {
20181             // Collect this subface (link edge).
20182             sinfected(checksh);
20183             shlist->newindex((void **) &parysh);
20184             *parysh = checksh;
20185           }
20186         }
20187         if (!fullstar) {
20188           collectflag = 0;
20189         }
20190       }
20191       if (collectflag) {
20192         fsymself(neightet);
20193         if (!infected(neightet)) {
20194           esymself(neightet); // Go to the face opposite to 'searchpt'.
20195           infect(neightet);
20196           tetlist->newindex((void **) &parytet);
20197           *parytet = neightet;
20198           if (vertlist != nullptr) {
20199             // Check if a vertex is collected.
20200             pt = apex(neightet);
20201             if (!pinfected(pt)) {
20202               pinfect(pt);
20203               vertlist->newindex((void **) &parypt);
20204               *parypt = pt;
20205             }
20206           }
20207         } // if (!infected(neightet))
20208       } // if (collectflag)
20209     } // j
20210   } // i
20211 
20212 
20213   // Uninfect the list of tets and vertices.
20214   for (i = 0; i < tetlist->objects; i++) {
20215     parytet = (triface *) fastlookup(tetlist, i);
20216     uninfect(*parytet);
20217   }
20218 
20219   if (vertlist != nullptr) {
20220     for (i = 0; i < vertlist->objects; i++) {
20221       parypt = (point *) fastlookup(vertlist, i);
20222       puninfect(*parypt);
20223     }
20224   }
20225 
20226   if (shlist != nullptr) {
20227     for (i = 0; i < shlist->objects; i++) {
20228       parysh = (face *) fastlookup(shlist, i);
20229       suninfect(*parysh);
20230     }
20231   }
20232 
20233   return (int) tetlist->objects;
20234 }
20235 
20236 ///////////////////////////////////////////////////////////////////////////////
20237 //                                                                           //
20238 // getedge()    Get a tetrahedron having the two endpoints.                  //
20239 //                                                                           //
20240 // The method here is to search the second vertex in the link faces of the   //
20241 // first vertex. The global array 'cavetetlist' is re-used for searching.    //
20242 //                                                                           //
20243 // This function is used for the case when the mesh is non-convex. Otherwise,//
20244 // the function finddirection() should be faster than this.                  //
20245 //                                                                           //
20246 ///////////////////////////////////////////////////////////////////////////////
20247 
getedge(point e1,point e2,triface * tedge)20248 int tetgenmesh::getedge(point e1, point e2, triface *tedge)
20249 {
20250   triface searchtet, neightet, *parytet;
20251   point pt;
20252   int done;
20253   int i, j;
20254 
20255   if (b->verbose > 2) {
20256     printf("      Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
20257   }
20258 
20259   // Quickly check if 'tedge' is just this edge.
20260   if (!isdeadtet(*tedge)) {
20261     if (org(*tedge) == e1) {
20262       if (dest(*tedge) == e2) {
20263         return 1;
20264       }
20265     } else if (org(*tedge) == e2) {
20266       if (dest(*tedge) == e1) {
20267         esymself(*tedge);
20268         return 1;
20269       }
20270     }
20271   }
20272 
20273   // Search for the edge [e1, e2].
20274   point2tetorg(e1, *tedge);
20275   finddirection(tedge, e2);
20276   if (dest(*tedge) == e2) {
20277     return 1;
20278   } else {
20279     // Search for the edge [e2, e1].
20280     point2tetorg(e2, *tedge);
20281     finddirection(tedge, e1);
20282     if (dest(*tedge) == e1) {
20283       esymself(*tedge);
20284       return 1;
20285     }
20286   }
20287 
20288 
20289   // Go to the link face of e1.
20290   point2tetorg(e1, searchtet);
20291   enextesymself(searchtet);
20292   //assert(oppo(searchtet) == e1);
20293 
20294   assert(cavetetlist->objects == 0l); // It will re-use this list.
20295 
20296   // Search e2.
20297   for (i = 0; i < 3; i++) {
20298     pt = apex(searchtet);
20299     if (pt == e2) {
20300       // Found. 'searchtet' is [#,#,e2,e1].
20301       eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
20302       return 1;
20303     }
20304     enextself(searchtet);
20305   }
20306 
20307   // Get the adjacent link face at 'searchtet'.
20308   fnext(searchtet, neightet);
20309   esymself(neightet);
20310   // assert(oppo(neightet) == e1);
20311   pt = apex(neightet);
20312   if (pt == e2) {
20313     // Found. 'neightet' is [#,#,e2,e1].
20314     eorgoppo(neightet, *tedge); // [e1,e2,#,#].
20315     return 1;
20316   }
20317 
20318   // Continue searching in the link face of e1.
20319   infect(searchtet);
20320   cavetetlist->newindex((void **) &parytet);
20321   *parytet = searchtet;
20322   infect(neightet);
20323   cavetetlist->newindex((void **) &parytet);
20324   *parytet = neightet;
20325 
20326   done = 0;
20327 
20328   for (i = 0; (i < cavetetlist->objects) && !done; i++) {
20329     parytet = (triface *) fastlookup(cavetetlist, i);
20330     searchtet = *parytet;
20331     for (j = 0; (j < 2) && !done; j++) {
20332       enextself(searchtet);
20333       fnext(searchtet, neightet);
20334       if (!infected(neightet)) {
20335         esymself(neightet);
20336         pt = apex(neightet);
20337         if (pt == e2) {
20338           // Found. 'neightet' is [#,#,e2,e1].
20339           eorgoppo(neightet, *tedge);
20340           done = 1;
20341         } else {
20342           infect(neightet);
20343           cavetetlist->newindex((void **) &parytet);
20344           *parytet = neightet;
20345         }
20346       }
20347     } // j
20348   } // i
20349 
20350   // Uninfect the list of visited tets.
20351   for (i = 0; i < cavetetlist->objects; i++) {
20352     parytet = (triface *) fastlookup(cavetetlist, i);
20353     uninfect(*parytet);
20354   }
20355   cavetetlist->restart();
20356 
20357   return done;
20358 }
20359 
20360 ///////////////////////////////////////////////////////////////////////////////
20361 //                                                                           //
20362 // reduceedgesatvertex()    Reduce the number of edges at a given vertex.    //
20363 //                                                                           //
20364 // 'endptlist' contains the endpoints of edges connecting at the vertex.     //
20365 //                                                                           //
20366 ///////////////////////////////////////////////////////////////////////////////
20367 
reduceedgesatvertex(point startpt,arraypool * endptlist)20368 int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
20369 {
20370   triface searchtet;
20371   point *pendpt, *parypt;
20372   enum interresult dir;
20373   flipconstraints fc;
20374   int reduceflag;
20375   int count;
20376   int n, i, j;
20377 
20378 
20379   fc.remvert = startpt;
20380   fc.checkflipeligibility = 1;
20381 
20382   while (1) {
20383 
20384     count = 0;
20385 
20386     for (i = 0; i < endptlist->objects; i++) {
20387       pendpt = (point *) fastlookup(endptlist, i);
20388       if (*pendpt == dummypoint) {
20389         continue; // Do not reduce a virtual edge.
20390       }
20391       reduceflag = 0;
20392       // Find the edge.
20393       if (nonconvex) {
20394         if (getedge(startpt, *pendpt, &searchtet)) {
20395           dir = ACROSSVERT;
20396         } else {
20397           // The edge does not exist (was flipped).
20398           dir = INTERSECT;
20399         }
20400       } else {
20401         point2tetorg(startpt, searchtet);
20402         dir = finddirection(&searchtet, *pendpt);
20403       }
20404       if (dir == ACROSSVERT) {
20405         if (dest(searchtet) == *pendpt) {
20406           // Do not flip a segment.
20407           if (!issubseg(searchtet)) {
20408             n = removeedgebyflips(&searchtet, &fc);
20409             if (n == 2) {
20410               reduceflag = 1;
20411             }
20412           }
20413         } else {
20414           assert(0); // A plc problem.
20415         }
20416       } else {
20417         // The edge has been flipped.
20418         reduceflag = 1;
20419       }
20420       if (reduceflag) {
20421         count++;
20422         // Move the last vertex into this slot.
20423         j = endptlist->objects - 1;
20424         parypt = (point *) fastlookup(endptlist, j);
20425         *pendpt = *parypt;
20426         endptlist->objects--;
20427         i--;
20428       }
20429     } // i
20430 
20431     if (count == 0) {
20432       // No edge is reduced.
20433       break;
20434     }
20435 
20436   } // while (1)
20437 
20438   return (int) endptlist->objects;
20439 }
20440 
20441 ///////////////////////////////////////////////////////////////////////////////
20442 //                                                                           //
20443 // removevertexbyflips()    Remove a vertex by flips.                        //
20444 //                                                                           //
20445 // This routine attempts to remove the given vertex 'rempt' (p) from the     //
20446 // tetrahedralization (T) by a sequence of flips.                            //
20447 //                                                                           //
20448 // The algorithm used here is a simple edge reduce method. Suppose there are //
20449 // n edges connected at p. We try to reduce the number of edges by flipping  //
20450 // any edge (not a segment) that is connecting at p.                         //
20451 //                                                                           //
20452 // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
20453 // can be successfully removed.                                              //
20454 //                                                                           //
20455 ///////////////////////////////////////////////////////////////////////////////
20456 
removevertexbyflips(point steinerpt)20457 int tetgenmesh::removevertexbyflips(point steinerpt)
20458 {
20459   triface *fliptets = nullptr, wrktets[4];
20460   triface searchtet, spintet, neightet;
20461   face parentsh, spinsh, checksh;
20462   face leftseg, rightseg, checkseg;
20463   point lpt = nullptr, rpt = nullptr, apexpt; //, *parypt;
20464   flipconstraints fc;
20465   enum verttype vt;
20466   enum locateresult loc;
20467   int valence, removeflag;
20468   int slawson;
20469   int t1ver;
20470   int n, i;
20471 
20472   vt = pointtype(steinerpt);
20473 
20474   if (vt == FREESEGVERTEX) {
20475     sdecode(point2sh(steinerpt), leftseg);
20476     assert(leftseg.sh != nullptr);
20477     leftseg.shver = 0;
20478     if (sdest(leftseg) == steinerpt) {
20479       senext(leftseg, rightseg);
20480       spivotself(rightseg);
20481       assert(rightseg.sh != nullptr);
20482       rightseg.shver = 0;
20483       assert(sorg(rightseg) == steinerpt);
20484     } else {
20485       assert(sorg(leftseg) == steinerpt);
20486       rightseg = leftseg;
20487       senext2(rightseg, leftseg);
20488       spivotself(leftseg);
20489       assert(leftseg.sh != nullptr);
20490       leftseg.shver = 0;
20491       assert(sdest(leftseg) == steinerpt);
20492     }
20493     lpt = sorg(leftseg);
20494     rpt = sdest(rightseg);
20495   } else {
20496     // It is not a Steiner point.
20497     return 0;
20498   }
20499 
20500   // Try to reduce the number of edges at 'p' by flips.
20501   getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, nullptr);
20502   cavetetlist->restart(); // This list may be re-used.
20503   if (cavetetvertlist->objects > 3l) {
20504     valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
20505   } else {
20506     valence = cavetetvertlist->objects;
20507   }
20508   assert(cavetetlist->objects == 0l);
20509   cavetetvertlist->restart();
20510 
20511   removeflag = 0;
20512 
20513   if (valence == 4) {
20514     // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
20515     //   vertices. This case is due to that 'p' is not exactly on the segment.
20516     point2tetorg(steinerpt, searchtet);
20517     loc = INTETRAHEDRON;
20518     removeflag = 1;
20519   } else if (valence == 5) {
20520     // There are 5 edges.
20521     if (vt == FREESEGVERTEX) {
20522       sstpivot1(leftseg, searchtet);
20523       if (org(searchtet) != steinerpt) {
20524         esymself(searchtet);
20525       }
20526       assert(org(searchtet) == steinerpt);
20527       assert(dest(searchtet) == lpt);
20528       i = 0; // Count the numbe of tet at the edge [p,lpt].
20529       neightet.tet = nullptr; // Init the face.
20530       spintet = searchtet;
20531       while (1) {
20532         i++;
20533         if (apex(spintet) == rpt) {
20534           // Remember the face containing the edge [lpt, rpt].
20535           neightet = spintet;
20536         }
20537         fnextself(spintet);
20538         if (spintet.tet == searchtet.tet) break;
20539       }
20540       if (i == 3) {
20541         // This case has been checked below.
20542       } else if (i == 4) {
20543         // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
20544         //   at [p,rpt].  There must be a face [p, lpt, rpt].
20545         if (apex(neightet) == rpt) {
20546           // The edge (segment) has been already recovered!
20547           // Check if a 6-to-2 flip is possible (to remove 'p').
20548           // Let 'searchtet' be [p,d,a,b]
20549           esym(neightet, searchtet);
20550           enextself(searchtet);
20551           // Check if there are exactly three tets at edge [p,d].
20552           wrktets[0] = searchtet; // [p,d,a,b]
20553           for (i = 0; i < 2; i++) {
20554             fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
20555           }
20556           if (apex(wrktets[0]) == oppo(wrktets[2])) {
20557             loc = ONFACE;
20558             removeflag = 1;
20559           }
20560         }
20561       }
20562     } else if (vt == FREEFACETVERTEX) {
20563       // It is possible to do a 6-to-2 flip to remove the vertex.
20564       point2tetorg(steinerpt, searchtet);
20565       // Get the three faces of 'searchtet' which share at p.
20566       //    All faces has p as origin.
20567       wrktets[0] = searchtet;
20568       wrktets[1] = searchtet;
20569       esymself(wrktets[1]);
20570       enextself(wrktets[1]);
20571       wrktets[2] = searchtet;
20572       eprevself(wrktets[2]);
20573       esymself(wrktets[2]);
20574       // All internal edges of the six tets have valance either 3 or 4.
20575       // Get one edge which has valance 3.
20576       searchtet.tet = nullptr;
20577       for (i = 0; i < 3; i++) {
20578         spintet = wrktets[i];
20579         valence = 0;
20580         while (1) {
20581           valence++;
20582           fnextself(spintet);
20583           if (spintet.tet == wrktets[i].tet) break;
20584         }
20585         if (valence == 3) {
20586           // Found the edge.
20587           searchtet = wrktets[i];
20588           break;
20589         } else {
20590           assert(valence == 4);
20591         }
20592       }
20593       assert(searchtet.tet != nullptr);
20594       // Note, we do not detach the three subfaces at p.
20595       // They will be removed within a 4-to-1 flip.
20596       loc = ONFACE;
20597       removeflag = 1;
20598     } else {
20599       // assert(0); DEBUG IT
20600     }
20601     //removeflag = 1;
20602   }
20603 
20604   if (!removeflag) {
20605     if (vt == FREESEGVERTEX) {
20606       // Check is it possible to recover the edge [lpt,rpt].
20607       // The condition to check is:  Whether each tet containing 'leftseg' is
20608       //   adjacent to a tet containing 'rightseg'.
20609       sstpivot1(leftseg, searchtet);
20610       if (org(searchtet) != steinerpt) {
20611         esymself(searchtet);
20612       }
20613       assert(org(searchtet) == steinerpt);
20614       assert(dest(searchtet) == lpt);
20615       spintet = searchtet;
20616       while (1) {
20617         // Go to the bottom face of this tet.
20618         eprev(spintet, neightet);
20619         esymself(neightet);  // [steinerpt, p1, p2, lpt]
20620         // Get the adjacent tet.
20621         fsymself(neightet);  // [p1, steinerpt, p2, rpt]
20622         if (oppo(neightet) != rpt) {
20623           // Found a non-matching adjacent tet.
20624           break;
20625         }
20626         fnextself(spintet);
20627         if (spintet.tet == searchtet.tet) {
20628           // 'searchtet' is [p,d,p1,p2].
20629           loc = ONEDGE;
20630           removeflag = 1;
20631           break;
20632         }
20633       }
20634     } // if (vt == FREESEGVERTEX)
20635   }
20636 
20637   if (!removeflag) {
20638     if (vt == FREESEGVERTEX) {
20639       // Check if the edge [lpt, rpt] exists.
20640       if (getedge(lpt, rpt, &searchtet)) {
20641         // We have recovered this edge. Shift the vertex into the volume.
20642         // We can recover this edge if the subfaces are not recovered yet.
20643         if (!checksubfaceflag) {
20644           // Remove the vertex from the surface mesh.
20645           //   This will re-create the segment [lpt, rpt] and re-triangulate
20646           //   all the facets at the segment.
20647           // Detach the subsegments from their surronding tets.
20648           for (i = 0; i < 2; i++) {
20649             checkseg = (i == 0) ? leftseg : rightseg;
20650             sstpivot1(checkseg, neightet);
20651             spintet = neightet;
20652             while (1) {
20653               tssdissolve1(spintet);
20654               fnextself(spintet);
20655               if (spintet.tet == neightet.tet) break;
20656             }
20657             sstdissolve1(checkseg);
20658           } // i
20659           slawson = 1; // Do lawson flip after removal.
20660           spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20661           sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20662           // Clear the list for new subfaces.
20663           caveshbdlist->restart();
20664           // Insert the new segment.
20665           assert(org(searchtet) == lpt);
20666           assert(dest(searchtet) == rpt);
20667           sstbond1(rightseg, searchtet);
20668           spintet = searchtet;
20669           while (1) {
20670             tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20671             assert(checkseg.sh == nullptr);  // FOR DEBUG ONLY
20672             tssbond1(spintet, rightseg);
20673             fnextself(spintet);
20674             if (spintet.tet == searchtet.tet) break;
20675           }
20676           // The Steiner point has been shifted into the volume.
20677           setpointtype(steinerpt, FREEVOLVERTEX);
20678           st_segref_count--;
20679           st_volref_count++;
20680           return 1;
20681         } // if (!checksubfaceflag)
20682       } // if (getedge(...))
20683     } // if (vt == FREESEGVERTEX)
20684   } // if (!removeflag)
20685 
20686   if (!removeflag) {
20687     return 0;
20688   }
20689 
20690   assert(org(searchtet) == steinerpt);
20691 
20692   if (vt == FREESEGVERTEX) {
20693     // Detach the subsegments from their surronding tets.
20694     for (i = 0; i < 2; i++) {
20695       checkseg = (i == 0) ? leftseg : rightseg;
20696       sstpivot1(checkseg, neightet);
20697       spintet = neightet;
20698       while (1) {
20699         tssdissolve1(spintet);
20700         fnextself(spintet);
20701         if (spintet.tet == neightet.tet) break;
20702       }
20703       sstdissolve1(checkseg);
20704     } // i
20705     if (checksubfaceflag) {
20706       // Detach the subfaces at the subsegments from their attached tets.
20707       for (i = 0; i < 2; i++) {
20708         checkseg = (i == 0) ? leftseg : rightseg;
20709         spivot(checkseg, parentsh);
20710         if (parentsh.sh != nullptr) {
20711           spinsh = parentsh;
20712           while (1) {
20713             stpivot(spinsh, neightet);
20714             if (neightet.tet != nullptr) {
20715               tsdissolve(neightet);
20716             }
20717             sesymself(spinsh);
20718             stpivot(spinsh, neightet);
20719             if (neightet.tet != nullptr) {
20720               tsdissolve(neightet);
20721             }
20722             stdissolve(spinsh);
20723             spivotself(spinsh); // Go to the next subface.
20724             if (spinsh.sh == parentsh.sh) break;
20725           }
20726         }
20727       } // i
20728     } // if (checksubfaceflag)
20729   }
20730 
20731   if (loc == INTETRAHEDRON) {
20732     // Collect the four tets containing 'p'.
20733     fliptets = new triface[4];
20734     fliptets[0] = searchtet; // [p,d,a,b]
20735     for (i = 0; i < 2; i++) {
20736       fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20737     }
20738     eprev(fliptets[0], fliptets[3]);
20739     fnextself(fliptets[3]); // it is [a,p,b,c]
20740     eprevself(fliptets[3]);
20741     esymself(fliptets[3]); // [a,b,c,p].
20742     // Remove p by a 4-to-1 flip.
20743     //flip41(fliptets, 1, 0, 0);
20744     flip41(fliptets, 1, &fc);
20745     //recenttet = fliptets[0];
20746   } else if (loc == ONFACE) {
20747     // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
20748     //   face [a,b,c].  Let 'searchtet' be the tet [p,d,a,b].
20749     // Collect the six tets containing 'p'.
20750     fliptets = new triface[6];
20751     fliptets[0] = searchtet; // [p,d,a,b]
20752     for (i = 0; i < 2; i++) {
20753       fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
20754     }
20755     eprev(fliptets[0], fliptets[3]);
20756     fnextself(fliptets[3]); // [a,p,b,e]
20757     esymself(fliptets[3]);  // [p,a,e,b]
20758     eprevself(fliptets[3]); // [e,p,a,b]
20759     for (i = 3; i < 5; i++) {
20760       fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
20761     }
20762     if (vt == FREEFACETVERTEX) {
20763       // We need to determine the location of three subfaces at p.
20764       valence = 0; // Re-use it.
20765       // Check if subfaces are all located in the lower three tets.
20766       //   i.e., [e,p,a,b], [e,p,b,c], and [e,p,c,a].
20767       for (i = 3; i < 6; i++) {
20768         if (issubface(fliptets[i])) valence++;
20769       }
20770       if (valence > 0) {
20771         assert(valence == 2);
20772         // We must do 3-to-2 flip in the upper part. We simply re-arrange
20773         //   the six tets.
20774         for (i = 0; i < 3; i++) {
20775           esym(fliptets[i+3], wrktets[i]);
20776           esym(fliptets[i], fliptets[i+3]);
20777           fliptets[i] = wrktets[i];
20778         }
20779         // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
20780         wrktets[1] = fliptets[1];
20781         fliptets[1] = fliptets[2];
20782         fliptets[2] = wrktets[1];
20783         wrktets[1] = fliptets[4];
20784         fliptets[4] = fliptets[5];
20785         fliptets[5] = wrktets[1];
20786       }
20787     }
20788     // Remove p by a 6-to-2 flip, which is a combination of two flips:
20789     //   a 3-to-2 (deletes the edge [e,p]), and
20790     //   a 4-to-1 (deletes the vertex p).
20791     // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
20792     //   two new tets: [a,b,c,p] and [b,a,c,e].  The new tet [a,b,c,p] is
20793     //   degenerate (has zero volume). It will be deleted in the followed
20794     //   4-to-1 flip.
20795     //flip32(&(fliptets[3]), 1, 0, 0);
20796     flip32(&(fliptets[3]), 1, &fc);
20797     // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
20798     //   This creates a new tet [a,b,c,d].
20799     //flip41(fliptets, 1, 0, 0);
20800     flip41(fliptets, 1, &fc);
20801     //recenttet = fliptets[0];
20802   } else if (loc == ONEDGE) {
20803     // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
20804     //   tets sharing at edge [e,d] originally.  We number the link vertices
20805     //   of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
20806     // Count the number of tets at edge [e,p] and [p,d] (this is n).
20807     n = 0;
20808     spintet = searchtet;
20809     while (1) {
20810       n++;
20811       fnextself(spintet);
20812       if (spintet.tet == searchtet.tet) break;
20813     }
20814     assert(n >= 3);
20815     // Collect the 2n tets containing 'p'.
20816     fliptets = new triface[2 * n];
20817     fliptets[0] = searchtet; // [p,b,p_0,p_1]
20818     for (i = 0; i < (n - 1); i++) {
20819       fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
20820     }
20821     eprev(fliptets[0], fliptets[n]);
20822     fnextself(fliptets[n]); // [p_0,p,p_1,e]
20823     esymself(fliptets[n]);  // [p,p_0,e,p_1]
20824     eprevself(fliptets[n]); // [e,p,p_0,p_1]
20825     for (i = n; i <  (2 * n - 1); i++) {
20826       fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
20827     }
20828     // Remove p by a 2n-to-n flip, it is a sequence of n flips:
20829     // - Do a 2-to-3 flip on
20830     //     [p_0,p_1,p,d] and
20831     //     [p,p_1,p_0,e].
20832     //   This produces:
20833     //     [e,d,p_0,p_1],
20834     //     [e,d,p_1,p] (degenerated), and
20835     //     [e,d,p,p_0] (degenerated).
20836     wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
20837     eprevself(wrktets[0]);    // [p_0,p,d,p_1]
20838     esymself(wrktets[0]);     // [p,p_0,p_1,d]
20839     enextself(wrktets[0]);    // [p_0,p_1,p,d] [0]
20840     wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
20841     enextself(wrktets[1]);    // [p,p_0,e,p_1]
20842     esymself(wrktets[1]);     // [p_0,p,p_1,e]
20843     eprevself(wrktets[1]);    // [p_1,p_0,p,e] [1]
20844     //flip23(wrktets, 1, 0, 0);
20845     flip23(wrktets, 1, &fc);
20846     // Save the new tet [e,d,p,p_0] (degenerated).
20847     fliptets[n] = wrktets[2];
20848     // Save the new tet [e,d,p_0,p_1].
20849     fliptets[0] = wrktets[0];
20850     // - Repeat from i = 1 to n-2: (n - 2) flips
20851     //   - Do a 3-to-2 flip on
20852     //       [p,p_i,d,e],
20853     //       [p,p_i,e,p_i+1], and
20854     //       [p,p_i,p_i+1,d].
20855     //     This produces:
20856     //       [d,e,p_i+1,p_i], and
20857     //       [e,d,p_i+1,p] (degenerated).
20858     for (i = 1; i < (n - 1); i++) {
20859       wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
20860       enextself(wrktets[0]);   // [d,p_i,e,p] (...)
20861       esymself(wrktets[0]);    // [p_i,d,p,e] (...)
20862       eprevself(wrktets[0]);   // [p,p_i,d,e] (degenerated) [0].
20863       wrktets[1] = fliptets[n+i];  // [e,p,p_i,p_i+1]
20864       enextself(wrktets[1]);       // [p,p_i,e,p_i+1] [1]
20865       wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
20866       eprevself(wrktets[2]);    // [p_i,p,d,p_i+1]
20867       esymself(wrktets[2]);     // [p,p_i,p_i+1,d] [2]
20868       //flip32(wrktets, 1, 0, 0);
20869       flip32(wrktets, 1, &fc);
20870       // Save the new tet [e,d,p_i,p_i+1].         // FOR DEBUG ONLY
20871       fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
20872       esymself(fliptets[i]);    // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
20873     }
20874     // - Do a 4-to-1 flip on
20875     //     [p,p_0,e,d],     [d,e,p_0,p],
20876     //     [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
20877     //     [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
20878     //     [e,d,p_n-1,p].
20879     //   This produces
20880     //     [e,d,p_n-1,p_0] and
20881     //     deletes p.
20882     wrktets[3] = wrktets[1];  // [e,d,p_n-1,p] (degenerated) [3]
20883     wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
20884     eprevself(wrktets[0]);    // [p,e,d,p_0] (...)
20885     esymself(wrktets[0]);     // [e,p,p_0,d] (...)
20886     enextself(wrktets[0]);    // [p,p_0,e,d] (degenerated) [0]
20887     wrktets[1] = fliptets[n-1];   // [p,d,p_n-1,p_0]
20888     esymself(wrktets[1]);         // [d,p,p_0,p_n-1]
20889     enextself(wrktets[1]);        // [p,p_0,d,p_n-1] [1]
20890     wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
20891     enextself(wrktets[2]);        // [p_p_n-1,e,p_0]
20892     esymself(wrktets[2]);         // [p_n-1,p,p_0,e]
20893     enextself(wrktets[2]);        // [p,p_0,p_n-1,e] [2]
20894     //flip41(wrktets, 1, 0, 0);
20895     flip41(wrktets, 1, &fc);
20896     // Save the new tet [e,d,p_n-1,p_0]             // FOR DEBUG ONLY
20897     fliptets[n-1] = wrktets[0];  // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
20898     //recenttet = fliptets[0];
20899   } else {
20900     assert(0); // Unknown location.
20901   } // if (iloc == ...)
20902 
20903   delete [] fliptets;
20904 
20905   if (vt == FREESEGVERTEX) {
20906     // Remove the vertex from the surface mesh.
20907     //   This will re-create the segment [lpt, rpt] and re-triangulate
20908     //   all the facets at the segment.
20909     // Only do lawson flip when subfaces are not recovery yet.
20910     slawson = (checksubfaceflag ? 0 : 1);
20911     spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
20912     sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
20913 
20914     // The original segment is returned in 'rightseg'.
20915     rightseg.shver = 0;
20916     assert(sorg(rightseg) == lpt);
20917     assert(sdest(rightseg) == rpt);
20918 
20919     // Insert the new segment.
20920     point2tetorg(lpt, searchtet);
20921     finddirection(&searchtet, rpt);
20922     assert(dest(searchtet) == rpt);
20923     sstbond1(rightseg, searchtet);
20924     spintet = searchtet;
20925     while (1) {
20926       tsspivot1(spintet, checkseg); // FOR DEBUG ONLY
20927       assert(checkseg.sh == nullptr);  // FOR DEBUG ONLY
20928       tssbond1(spintet, rightseg);
20929       fnextself(spintet);
20930       if (spintet.tet == searchtet.tet) break;
20931     }
20932 
20933     if (checksubfaceflag) {
20934       // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
20935       spivot(rightseg, parentsh);
20936       if (parentsh.sh != nullptr) {
20937         spinsh = parentsh;
20938         while (1) {
20939           if (sorg(spinsh) != lpt) {
20940             sesymself(spinsh);
20941             assert(sorg(spinsh) == lpt);
20942           }
20943           assert(sdest(spinsh) == rpt);
20944           apexpt = sapex(spinsh);
20945           // Find the adjacent tet of [lpt,rpt,apexpt];
20946           spintet = searchtet;
20947           while (1) {
20948             if (apex(spintet) == apexpt) {
20949               tsbond(spintet, spinsh);
20950               sesymself(spinsh); // Get to another side of this face.
20951               fsym(spintet, neightet);
20952               tsbond(neightet, spinsh);
20953               sesymself(spinsh); // Get back to the original side.
20954               break;
20955             }
20956             fnextself(spintet);
20957             assert(spintet.tet != searchtet.tet);
20958             //if (spintet.tet == searchtet.tet) break;
20959           }
20960           spivotself(spinsh);
20961           if (spinsh.sh == parentsh.sh) break;
20962         }
20963       }
20964     } // if (checksubfaceflag)
20965 
20966     // Clear the set of new subfaces.
20967     caveshbdlist->restart();
20968   } // if (vt == FREESEGVERTEX)
20969 
20970   // The point has been removed.
20971   if (pointtype(steinerpt) != UNUSEDVERTEX) {
20972     setpointtype(steinerpt, UNUSEDVERTEX);
20973     unuverts++;
20974   }
20975   // Update the correspinding counters.
20976   if (vt == FREESEGVERTEX) {
20977     st_segref_count--;
20978   } else if (vt == FREEFACETVERTEX) {
20979     st_facref_count--;
20980   } else if (vt == FREEVOLVERTEX) {
20981     st_volref_count--;
20982   }
20983   if (steinerleft > 0) steinerleft++;
20984 
20985   return 1;
20986 }
20987 
20988 ///////////////////////////////////////////////////////////////////////////////
20989 //                                                                           //
20990 // suppressbdrysteinerpoint()    Suppress a boundary Steiner point           //
20991 //                                                                           //
20992 ///////////////////////////////////////////////////////////////////////////////
20993 
suppressbdrysteinerpoint(point steinerpt)20994 int tetgenmesh::suppressbdrysteinerpoint(point steinerpt)
20995 {
20996   face parentsh, spinsh, *parysh;
20997   face leftseg, rightseg;
20998   point lpt = nullptr, rpt = nullptr;
20999   int i;
21000 
21001   verttype vt = pointtype(steinerpt);
21002 
21003   if (vt == FREESEGVERTEX) {
21004     sdecode(point2sh(steinerpt), leftseg);
21005     leftseg.shver = 0;
21006     if (sdest(leftseg) == steinerpt) {
21007       senext(leftseg, rightseg);
21008       spivotself(rightseg);
21009       assert(rightseg.sh != nullptr);
21010       rightseg.shver = 0;
21011       assert(sorg(rightseg) == steinerpt);
21012     } else {
21013       assert(sorg(leftseg) == steinerpt);
21014       rightseg = leftseg;
21015       senext2(rightseg, leftseg);
21016       spivotself(leftseg);
21017       assert(leftseg.sh != nullptr);
21018       leftseg.shver = 0;
21019       assert(sdest(leftseg) == steinerpt);
21020     }
21021     lpt = sorg(leftseg);
21022     rpt = sdest(rightseg);
21023     if (b->verbose > 2) {
21024       printf("      Suppressing Steiner point %d in segment (%d, %d).\n",
21025              pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
21026     }
21027     // Get all subfaces at the left segment [lpt, steinerpt].
21028     spivot(leftseg, parentsh);
21029     spinsh = parentsh;
21030     while (1) {
21031       cavesegshlist->newindex((void **) &parysh);
21032       *parysh = spinsh;
21033       // Orient the face consistently.
21034       if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
21035       spivotself(spinsh);
21036       if (spinsh.sh == nullptr) break;
21037       if (spinsh.sh == parentsh.sh) break;
21038     }
21039     if (cavesegshlist->objects < 2) {
21040       // It is a single segment. Not handle it yet.
21041       cavesegshlist->restart();
21042       return 0;
21043     }
21044   } else if (vt == FREEFACETVERTEX) {
21045     if (b->verbose > 2) {
21046       printf("      Suppressing Steiner point %d from facet.\n",
21047              pointmark(steinerpt));
21048     }
21049     sdecode(point2sh(steinerpt), parentsh);
21050     // A facet Steiner point. There are exactly two sectors.
21051     for (i = 0; i < 2; i++) {
21052       cavesegshlist->newindex((void **) &parysh);
21053       *parysh = parentsh;
21054       sesymself(parentsh);
21055     }
21056   } else {
21057     return 0;
21058   }
21059 
21060   triface searchtet, neightet, *parytet;
21061   point pa, pb, pc, pd;
21062   REAL v1[3], v2[3], len, u;
21063 
21064   REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
21065   REAL ori, minvol, smallvol;
21066   int samplesize;
21067   int it, j, k;
21068 
21069   int n = (int) cavesegshlist->objects;
21070   point *newsteiners = new point[n];
21071   for (i = 0; i < n; i++) newsteiners[i] = nullptr;
21072 
21073   // Search for each sector an interior vertex.
21074   for (i = 0; i < cavesegshlist->objects; i++) {
21075     parysh = (face *) fastlookup(cavesegshlist, i);
21076     stpivot(*parysh, searchtet);
21077     // Skip it if it is outside.
21078     if (ishulltet(searchtet)) continue;
21079     // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
21080     //   opposite.  Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
21081     //   Moreover, subfaces are oriented towards the interior of the ball.
21082     setpoint2tet(steinerpt, encode(searchtet));
21083     getvertexstar(0, steinerpt, cavetetlist, nullptr, caveshlist);
21084     // Calculate the searching vector.
21085     pa = sorg(*parysh);
21086     pb = sdest(*parysh);
21087     pc = sapex(*parysh);
21088     facenormal(pa, pb, pc, v1, 1, nullptr);
21089     len = sqrt(dot(v1, v1));
21090     assert(len > 0.0);
21091     v1[0] /= len;
21092     v1[1] /= len;
21093     v1[2] /= len;
21094     if (vt == FREESEGVERTEX) {
21095       parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
21096       pd = sapex(*parysh);
21097       facenormal(pb, pa, pd, v2, 1, nullptr);
21098       len = sqrt(dot(v2, v2));
21099       assert(len > 0.0);
21100       v2[0] /= len;
21101       v2[1] /= len;
21102       v2[2] /= len;
21103       // Average the two vectors.
21104       v1[0] = 0.5 * (v1[0] + v2[0]);
21105       v1[1] = 0.5 * (v1[1] + v2[1]);
21106       v1[2] = 0.5 * (v1[2] + v2[2]);
21107     }
21108     // Search the intersection of the ray starting from 'steinerpt' to
21109     //   the search direction 'v1' and the shell of the half-ball.
21110     // - Construct an endpoint.
21111     len = distance(pa, pb);
21112     v2[0] = steinerpt[0] + len * v1[0];
21113     v2[1] = steinerpt[1] + len * v1[1];
21114     v2[2] = steinerpt[2] + len * v1[2];
21115     for (j = 0; j < cavetetlist->objects; j++) {
21116       parytet = (triface *) fastlookup(cavetetlist, j);
21117       pa = org(*parytet);
21118       pb = dest(*parytet);
21119       pc = apex(*parytet);
21120       // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
21121       //   is the apex, and three sides are defined by the triangle
21122       //   [pa, pb, pc].
21123       ori = orient3d(steinerpt, pa, pb, v2);
21124       if (ori >= 0) {
21125         ori = orient3d(steinerpt, pb, pc, v2);
21126         if (ori >= 0) {
21127           ori = orient3d(steinerpt, pc, pa, v2);
21128           if (ori >= 0) {
21129             // Found! Calculate the intersection.
21130             planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
21131             assert(u != 0.0);
21132             break;
21133           }
21134         }
21135       }
21136     } // j
21137     assert(j < cavetetlist->objects); // There must be an intersection.
21138     // Close the ball by adding the subfaces.
21139     for (j = 0; j < caveshlist->objects; j++) {
21140       parysh = (face *) fastlookup(caveshlist, j);
21141       stpivot(*parysh, neightet);
21142       cavetetlist->newindex((void **) &parytet);
21143       *parytet = neightet;
21144     }
21145     // Search a best point inside the segment [startpt, steinerpt].
21146     it = 0;
21147     samplesize = 100;
21148     v1[0] = steinerpt[0] - startpt[0];
21149     v1[1] = steinerpt[1] - startpt[1];
21150     v1[2] = steinerpt[2] - startpt[2];
21151     minvol = -1.0;
21152     while (it < 3) {
21153       for (j = 1; j < samplesize - 1; j++) {
21154         samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
21155         samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
21156         samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
21157         // Find the minimum volume for 'samplept'.
21158         smallvol = -1;
21159         for (k = 0; k < cavetetlist->objects; k++) {
21160           parytet = (triface *) fastlookup(cavetetlist, k);
21161           pa = org(*parytet);
21162           pb = dest(*parytet);
21163           pc = apex(*parytet);
21164           ori = orient3d(pb, pa, pc, samplept);
21165           if (ori <= 0) {
21166             break; // An invalid tet.
21167           }
21168           if (smallvol == -1) {
21169             smallvol = ori;
21170           } else {
21171             if (ori < smallvol) smallvol = ori;
21172           }
21173         } // k
21174         if (k == cavetetlist->objects) {
21175           // Found a valid point. Remember it.
21176           if (minvol == -1.0) {
21177             candpt[0] = samplept[0];
21178             candpt[1] = samplept[1];
21179             candpt[2] = samplept[2];
21180             minvol = smallvol;
21181           } else {
21182             if (minvol < smallvol) {
21183               // It is a better location. Remember it.
21184               candpt[0] = samplept[0];
21185               candpt[1] = samplept[1];
21186               candpt[2] = samplept[2];
21187               minvol = smallvol;
21188             } else {
21189               // No improvement of smallest volume.
21190               // Since we are searching along the line [startpt, steinerpy],
21191               // The smallest volume can only be decreased later.
21192               break;
21193             }
21194           }
21195         }
21196       } // j
21197       if (minvol > 0) break;
21198       samplesize *= 10;
21199       it++;
21200     } // while (it < 3)
21201     if (minvol == -1.0) {
21202       // Failed to find a valid point.
21203       cavetetlist->restart();
21204       caveshlist->restart();
21205       break;
21206     }
21207     // Create a new Steiner point inside this section.
21208     makepoint(&(newsteiners[i]), FREEVOLVERTEX);
21209     newsteiners[i][0] = candpt[0];
21210     newsteiners[i][1] = candpt[1];
21211     newsteiners[i][2] = candpt[2];
21212     cavetetlist->restart();
21213     caveshlist->restart();
21214   } // i
21215 
21216   if (i < cavesegshlist->objects) {
21217     // Failed to suppress the vertex.
21218     for (; i > 0; i--) {
21219       if (newsteiners[i - 1] != nullptr) {
21220         pointdealloc(newsteiners[i - 1]);
21221       }
21222     }
21223     delete [] newsteiners;
21224     cavesegshlist->restart();
21225     return 0;
21226   }
21227 
21228   // Remove p from the segment or the facet.
21229   triface newtet, newface, spintet;
21230   face newsh, neighsh;
21231   face *splitseg, checkseg;
21232   int slawson = 0; // Do not do flip afterword.
21233   int t1ver;
21234 
21235   if (vt == FREESEGVERTEX) {
21236     // Detach 'leftseg' and 'rightseg' from their adjacent tets.
21237     //   These two subsegments will be deleted.
21238     sstpivot1(leftseg, neightet);
21239     spintet = neightet;
21240     while (1) {
21241       tssdissolve1(spintet);
21242       fnextself(spintet);
21243       if (spintet.tet == neightet.tet) break;
21244     }
21245     sstpivot1(rightseg, neightet);
21246     spintet = neightet;
21247     while (1) {
21248       tssdissolve1(spintet);
21249       fnextself(spintet);
21250       if (spintet.tet == neightet.tet) break;
21251     }
21252   }
21253 
21254   // Loop through all sectors bounded by facets at this segment.
21255   //   Within each sector, create a new Steiner point 'np', and replace 'p'
21256   //   by 'np' for all tets in this sector.
21257   for (i = 0; i < cavesegshlist->objects; i++) {
21258     parysh = (face *) fastlookup(cavesegshlist, i);
21259     // 'parysh' is the face [lpt, steinerpt, #].
21260     stpivot(*parysh, neightet);
21261     // Get all tets in this sector.
21262     setpoint2tet(steinerpt, encode(neightet));
21263     getvertexstar(0, steinerpt, cavetetlist, nullptr, caveshlist);
21264     if (!ishulltet(neightet)) {
21265       // Within each tet in the ball, replace 'p' by 'np'.
21266       for (j = 0; j < cavetetlist->objects; j++) {
21267         parytet = (triface *) fastlookup(cavetetlist, j);
21268         setoppo(*parytet, newsteiners[i]);
21269       } // j
21270       // Point to a parent tet.
21271       parytet = (triface *) fastlookup(cavetetlist, 0);
21272       setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
21273       st_volref_count++;
21274       if (steinerleft > 0) steinerleft--;
21275     }
21276     // Disconnect the set of boundary faces. They're temporarily open faces.
21277     //   They will be connected to the new tets after 'p' is removed.
21278     for (j = 0; j < caveshlist->objects; j++) {
21279       // Get a boundary face.
21280       parysh = (face *) fastlookup(caveshlist, j);
21281       stpivot(*parysh, neightet);
21282       //assert(apex(neightet) == newpt);
21283       // Clear the connection at this face.
21284       dissolve(neightet);
21285       tsdissolve(neightet);
21286     }
21287     // Clear the working lists.
21288     cavetetlist->restart();
21289     caveshlist->restart();
21290   } // i
21291   cavesegshlist->restart();
21292 
21293   if (vt == FREESEGVERTEX) {
21294     spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21295     splitseg = &rightseg;
21296   } else {
21297     if (sdest(parentsh) == steinerpt) {
21298       senextself(parentsh);
21299     } else if (sapex(parentsh) == steinerpt) {
21300       senext2self(parentsh);
21301     }
21302     assert(sorg(parentsh) == steinerpt);
21303     splitseg = nullptr;
21304   }
21305   sremovevertex(steinerpt, &parentsh, splitseg, slawson);
21306 
21307   if (vt == FREESEGVERTEX) {
21308     // The original segment is returned in 'rightseg'.
21309     rightseg.shver = 0;
21310   }
21311 
21312   // For each new subface, create two new tets at each side of it.
21313   //   Both of the two new tets have its opposite be dummypoint.
21314   for (i = 0; i < caveshbdlist->objects; i++) {
21315     parysh = (face *) fastlookup(caveshbdlist, i);
21316     sinfect(*parysh); // Mark it for connecting new tets.
21317     newsh = *parysh;
21318     pa = sorg(newsh);
21319     pb = sdest(newsh);
21320     pc = sapex(newsh);
21321     maketetrahedron(&newtet);
21322     maketetrahedron(&neightet);
21323     setvertices(newtet, pa, pb, pc, dummypoint);
21324     setvertices(neightet, pb, pa, pc, dummypoint);
21325     bond(newtet, neightet);
21326     tsbond(newtet, newsh);
21327     sesymself(newsh);
21328     tsbond(neightet, newsh);
21329   }
21330   // Temporarily increase the hullsize.
21331   hullsize += (caveshbdlist->objects * 2l);
21332 
21333   if (vt == FREESEGVERTEX) {
21334     // Connecting new tets at the recovered segment.
21335     spivot(rightseg, parentsh);
21336     assert(parentsh.sh != nullptr);
21337     spinsh = parentsh;
21338     while (1) {
21339       if (sorg(spinsh) != lpt) sesymself(spinsh);
21340       // Get the new tet at this subface.
21341       stpivot(spinsh, newtet);
21342       tssbond1(newtet, rightseg);
21343       // Go to the other face at this segment.
21344       spivot(spinsh, neighsh);
21345       if (sorg(neighsh) != lpt) sesymself(neighsh);
21346       sesymself(neighsh);
21347       stpivot(neighsh, neightet);
21348       tssbond1(neightet, rightseg);
21349       sstbond1(rightseg, neightet);
21350       // Connecting two adjacent tets at this segment.
21351       esymself(newtet);
21352       esymself(neightet);
21353       // Connect the two tets (at rightseg) together.
21354       bond(newtet, neightet);
21355       // Go to the next subface.
21356       spivotself(spinsh);
21357       if (spinsh.sh == parentsh.sh) break;
21358     }
21359   }
21360 
21361   // Connecting new tets at new subfaces together.
21362   for (i = 0; i < caveshbdlist->objects; i++) {
21363     parysh = (face *) fastlookup(caveshbdlist, i);
21364     newsh = *parysh;
21365     //assert(sinfected(newsh));
21366     // Each new subface contains two new tets.
21367     for (k = 0; k < 2; k++) {
21368       stpivot(newsh, newtet);
21369       for (j = 0; j < 3; j++) {
21370         // Check if this side is open.
21371         esym(newtet, newface);
21372         if (newface.tet[newface.ver & 3] == nullptr) {
21373           // An open face. Connect it to its adjacent tet.
21374           sspivot(newsh, checkseg);
21375           if (checkseg.sh != nullptr) {
21376             // A segment. It must not be the recovered segment.
21377             tssbond1(newtet, checkseg);
21378             sstbond1(checkseg, newtet);
21379           }
21380           spivot(newsh, neighsh);
21381           if (neighsh.sh != nullptr) {
21382             // The adjacent subface exists. It's not a dangling segment.
21383             if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
21384             stpivot(neighsh, neightet);
21385             if (sinfected(neighsh)) {
21386               esymself(neightet);
21387               assert(neightet.tet[neightet.ver & 3] == nullptr);
21388             } else {
21389               // Search for an open face at this edge.
21390               spintet = neightet;
21391               while (1) {
21392                 esym(spintet, searchtet);
21393                 fsym(searchtet, spintet);
21394                 if (spintet.tet == nullptr) break;
21395                 assert(spintet.tet != neightet.tet);
21396               }
21397               // Found an open face at 'searchtet'.
21398               neightet = searchtet;
21399             }
21400           } else {
21401             // The edge (at 'newsh') is a dangling segment.
21402             assert(checkseg.sh != nullptr);
21403             // Get an adjacent tet at this segment.
21404             sstpivot1(checkseg, neightet);
21405             assert(!isdeadtet(neightet));
21406             if (org(neightet) != sdest(newsh)) esymself(neightet);
21407             assert((org(neightet) == sdest(newsh)) &&
21408                    (dest(neightet) == sorg(newsh)));
21409             // Search for an open face at this edge.
21410             spintet = neightet;
21411             while (1) {
21412               esym(spintet, searchtet);
21413               fsym(searchtet, spintet);
21414               if (spintet.tet == nullptr) break;
21415               assert(spintet.tet != neightet.tet);
21416             }
21417             // Found an open face at 'searchtet'.
21418             neightet = searchtet;
21419           }
21420           pc = apex(newface);
21421           if (apex(neightet) == steinerpt) {
21422             // Exterior case. The 'neightet' is a hull tet which contain
21423             //   'steinerpt'. It will be deleted after 'steinerpt' is removed.
21424             assert(pc == dummypoint);
21425             caveoldtetlist->newindex((void **) &parytet);
21426             *parytet = neightet;
21427             // Connect newface to the adjacent hull tet of 'neightet', which
21428             //   has the same edge as 'newface', and does not has 'steinerpt'.
21429             fnextself(neightet);
21430           } else {
21431             if (pc == dummypoint) {
21432               if (apex(neightet) != dummypoint) {
21433                 setapex(newface, apex(neightet));
21434                 // A hull tet has turned into an interior tet.
21435                 hullsize--; // Must update the hullsize.
21436               }
21437             }
21438           }
21439           bond(newface, neightet);
21440         } // if (newface.tet[newface.ver & 3] == nullptr)
21441         enextself(newtet);
21442         senextself(newsh);
21443       } // j
21444       sesymself(newsh);
21445     } // k
21446   } // i
21447 
21448   // Unmark all new subfaces.
21449   for (i = 0; i < caveshbdlist->objects; i++) {
21450     parysh = (face *) fastlookup(caveshbdlist, i);
21451     suninfect(*parysh);
21452   }
21453   caveshbdlist->restart();
21454 
21455   if (caveoldtetlist->objects > 0l) {
21456     // Delete hull tets which contain 'steinerpt'.
21457     for (i = 0; i < caveoldtetlist->objects; i++) {
21458       parytet = (triface *) fastlookup(caveoldtetlist, i);
21459       tetrahedrondealloc(parytet->tet);
21460     }
21461     // Must update the hullsize.
21462     hullsize -= caveoldtetlist->objects;
21463     caveoldtetlist->restart();
21464   }
21465 
21466   setpointtype(steinerpt, UNUSEDVERTEX);
21467   unuverts++;
21468   if (vt == FREESEGVERTEX) {
21469     st_segref_count--;
21470   } else { // vt == FREEFACETVERTEX
21471     st_facref_count--;
21472   }
21473   if (steinerleft > 0) steinerleft++;  // We've removed a Steiner points.
21474 
21475 
21476   point *parypt;
21477   int steinercount = 0;
21478 
21479   int bak_fliplinklevel = b->fliplinklevel;
21480   b->fliplinklevel = 100000; // Unlimited flip level.
21481 
21482   // Try to remove newly added Steiner points.
21483   for (i = 0; i < n; i++) {
21484     if (newsteiners[i] != nullptr) {
21485       if (!removevertexbyflips(newsteiners[i])) {
21486         if (b->nobisect_param > 0) { // Not -Y0
21487           // Save it in subvertstack for removal.
21488           subvertstack->newindex((void **) &parypt);
21489           *parypt = newsteiners[i];
21490         }
21491         steinercount++;
21492       }
21493     }
21494   }
21495 
21496   b->fliplinklevel = bak_fliplinklevel;
21497 
21498   if (steinercount > 0) {
21499     if (b->verbose > 2) {
21500       printf("      Added %d interior Steiner points.\n", steinercount);
21501     }
21502   }
21503 
21504   delete [] newsteiners;
21505 
21506   return 1;
21507 }
21508 
21509 
21510 ///////////////////////////////////////////////////////////////////////////////
21511 //                                                                           //
21512 // suppresssteinerpoints()    Suppress Steiner points.                       //
21513 //                                                                           //
21514 // All Steiner points have been saved in 'subvertstack' in the routines      //
21515 // carveholes() and suppresssteinerpoint().                                  //
21516 // Each Steiner point is either removed or shifted into the interior.        //
21517 //                                                                           //
21518 ///////////////////////////////////////////////////////////////////////////////
21519 
suppresssteinerpoints()21520 int tetgenmesh::suppresssteinerpoints()
21521 {
21522 
21523   if (!b->quiet) {
21524     printf("Suppressing Steiner points ...\n");
21525   }
21526 
21527   point rempt, *parypt;
21528 
21529   int bak_fliplinklevel = b->fliplinklevel;
21530   b->fliplinklevel = 100000; // Unlimited flip level.
21531   int suppcount = 0, remcount = 0;
21532   int i;
21533 
21534   // Try to suppress boundary Steiner points.
21535   for (i = 0; i < subvertstack->objects; i++) {
21536     parypt = (point *) fastlookup(subvertstack, i);
21537     rempt = *parypt;
21538     if (pointtype(rempt) != UNUSEDVERTEX) {
21539       if ((pointtype(rempt) == FREESEGVERTEX) ||
21540           (pointtype(rempt) == FREEFACETVERTEX)) {
21541         if (suppressbdrysteinerpoint(rempt)) {
21542           suppcount++;
21543         }
21544       }
21545     }
21546   } // i
21547 
21548   if (suppcount > 0) {
21549     if (b->verbose) {
21550       printf("  Suppressed %d boundary Steiner points.\n", suppcount);
21551     }
21552   }
21553 
21554   if (b->nobisect_param > 0) { // -Y1
21555     for (i = 0; i < subvertstack->objects; i++) {
21556       parypt = (point *) fastlookup(subvertstack, i);
21557       rempt = *parypt;
21558       if (pointtype(rempt) != UNUSEDVERTEX) {
21559         if (pointtype(rempt) == FREEVOLVERTEX) {
21560           if (removevertexbyflips(rempt)) {
21561             remcount++;
21562           }
21563         }
21564       }
21565     }
21566   }
21567 
21568   if (remcount > 0) {
21569     if (b->verbose) {
21570       printf("  Removed %d interior Steiner points.\n", remcount);
21571     }
21572   }
21573 
21574   b->fliplinklevel = bak_fliplinklevel;
21575 
21576   if (b->nobisect_param > 1) { // -Y2
21577     // Smooth interior Steiner points.
21578     optparameters opm;
21579     triface *parytet;
21580     point *ppt;
21581     REAL ori;
21582     int smtcount, count, ivcount;
21583     int nt, j;
21584 
21585     // Point smooth options.
21586     opm.max_min_volume = 1;
21587     opm.numofsearchdirs = 20;
21588     opm.searchstep = 0.001;
21589     opm.maxiter = 30; // Limit the maximum iterations.
21590 
21591     smtcount = 0;
21592 
21593     do {
21594 
21595       nt = 0;
21596 
21597       while (1) {
21598         count = 0;
21599         ivcount = 0; // Clear the inverted count.
21600 
21601         for (i = 0; i < subvertstack->objects; i++) {
21602           parypt = (point *) fastlookup(subvertstack, i);
21603           rempt = *parypt;
21604           if (pointtype(rempt) == FREEVOLVERTEX) {
21605             getvertexstar(1, rempt, cavetetlist, nullptr, nullptr);
21606             // Calculate the initial smallest volume (maybe zero or negative).
21607             for (j = 0; j < cavetetlist->objects; j++) {
21608               parytet = (triface *) fastlookup(cavetetlist, j);
21609               ppt = (point *) &(parytet->tet[4]);
21610               ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
21611               if (j == 0) {
21612                 opm.initval = ori;
21613               } else {
21614                 if (opm.initval > ori) opm.initval = ori;
21615               }
21616             }
21617             if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
21618               count++;
21619             }
21620             if (opm.imprval <= 0.0) {
21621               ivcount++; // The mesh contains inverted elements.
21622             }
21623             cavetetlist->restart();
21624           }
21625         } // i
21626 
21627         smtcount += count;
21628 
21629         if (count == 0) {
21630           // No point has been smoothed.
21631           break;
21632         }
21633 
21634         nt++;
21635         if (nt > 2) {
21636           break; // Already three iterations.
21637         }
21638       } // while
21639 
21640       if (ivcount > 0) {
21641         // There are inverted elements!
21642         if (opm.maxiter > 0) {
21643           // Set unlimited smoothing steps. Try again.
21644           opm.numofsearchdirs = 30;
21645           opm.searchstep = 0.0001;
21646           opm.maxiter = -1;
21647           continue;
21648         }
21649       }
21650 
21651       break;
21652     } while (1); // Additional loop for (ivcount > 0)
21653 
21654     if (ivcount > 0) {
21655       printf("BUG Report!  The mesh contain inverted elements.\n");
21656     }
21657 
21658     if (b->verbose) {
21659       if (smtcount > 0) {
21660         printf("  Smoothed %d Steiner points.\n", smtcount);
21661       }
21662     }
21663   } // -Y2
21664 
21665   subvertstack->restart();
21666 
21667   return 1;
21668 }
21669 
21670 ///////////////////////////////////////////////////////////////////////////////
21671 //                                                                           //
21672 // recoverboundary()    Recover segments and facets.                         //
21673 //                                                                           //
21674 ///////////////////////////////////////////////////////////////////////////////
21675 
recoverboundary(clock_t & tv)21676 void tetgenmesh::recoverboundary(clock_t& tv)
21677 {
21678   arraypool *misseglist, *misshlist;
21679   arraypool *bdrysteinerptlist;
21680   face searchsh, *parysh;
21681   face searchseg, *paryseg;
21682   point rempt, *parypt;
21683   long ms; // The number of missing segments/subfaces.
21684   int nit; // The number of iterations.
21685   int s, i;
21686 
21687   // Counters.
21688   long bak_segref_count, bak_facref_count, bak_volref_count;
21689 
21690   if (!b->quiet) {
21691     printf("Recovering boundaries...\n");
21692   }
21693 
21694 
21695   if (b->verbose) {
21696     printf("  Recovering segments.\n");
21697   }
21698 
21699   // Segments will be introduced.
21700   checksubsegflag = 1;
21701 
21702   misseglist = new arraypool(sizeof(face), 8);
21703   bdrysteinerptlist = new arraypool(sizeof(point), 8);
21704 
21705   // [Bruno] protected all the body of the function in
21706   // a big try/catch block, to make sure that dynamically
21707   // allocated variables are free-ed before leaving the
21708   // function when an exception is triggered (e.g. intersecting
21709   // constrained facets).
21710   // Note: misseglist, misshlist and bdrysteinerptlist can probably
21711   // be declared as local variables (instead of allocated on the heap),
21712   // this will make everything easier (but I do not know enough the
21713   // rest of the code to do that...)
21714 
21715   try {
21716 
21717   // In random order.
21718   subsegs->traversalinit();
21719   for (i = 0; i < subsegs->items; i++) {
21720     s = randomnation(i + 1);
21721     // Move the s-th seg to the i-th.
21722     subsegstack->newindex((void **) &paryseg);
21723     *paryseg = * (face *) fastlookup(subsegstack, s);
21724     // Put i-th seg to be the s-th.
21725     searchseg.sh = shellfacetraverse(subsegs);
21726     paryseg = (face *) fastlookup(subsegstack, s);
21727     *paryseg = searchseg;
21728   }
21729 
21730   // The init number of missing segments.
21731   ms = subsegs->items;
21732   nit = 0;
21733   if (b->fliplinklevel < 0) {
21734     autofliplinklevel = 1; // Init value.
21735   }
21736 
21737   // First, trying to recover segments by only doing flips.
21738   while (1) {
21739     recoversegments(misseglist, 0, 0);
21740 
21741     if (misseglist->objects > 0) {
21742       if (b->fliplinklevel >= 0) {
21743         break;
21744       } else {
21745         if (misseglist->objects >= ms) {
21746           nit++;
21747           if (nit >= 3) {
21748             //break;
21749             // Do the last round with unbounded flip link level.
21750             b->fliplinklevel = 100000;
21751           }
21752         } else {
21753           ms = misseglist->objects;
21754           if (nit > 0) {
21755             nit--;
21756           }
21757         }
21758         for (i = 0; i < misseglist->objects; i++) {
21759           subsegstack->newindex((void **) &paryseg);
21760           *paryseg = * (face *) fastlookup(misseglist, i);
21761         }
21762         misseglist->restart();
21763         autofliplinklevel+=b->fliplinklevelinc;
21764       }
21765     } else {
21766       // All segments are recovered.
21767       break;
21768     }
21769   } // while (1)
21770 
21771   if (b->verbose) {
21772     printf("  %ld (%ld) segments are recovered (missing).\n",
21773            subsegs->items - misseglist->objects, misseglist->objects);
21774   }
21775 
21776   if (misseglist->objects > 0) {
21777     // Second, trying to recover segments by doing more flips (fullsearch).
21778     while (misseglist->objects > 0) {
21779       ms = misseglist->objects;
21780       for (i = 0; i < misseglist->objects; i++) {
21781         subsegstack->newindex((void **) &paryseg);
21782         *paryseg = * (face *) fastlookup(misseglist, i);
21783       }
21784       misseglist->restart();
21785 
21786       recoversegments(misseglist, 1, 0);
21787 
21788       if (misseglist->objects < ms) {
21789         // The number of missing segments is reduced.
21790         continue;
21791       } else {
21792         break;
21793       }
21794     }
21795     if (b->verbose) {
21796       printf("  %ld (%ld) segments are recovered (missing).\n",
21797              subsegs->items - misseglist->objects, misseglist->objects);
21798     }
21799   }
21800 
21801   if (misseglist->objects > 0) {
21802     // Third, trying to recover segments by doing more flips (fullsearch)
21803     //   and adding Steiner points in the volume.
21804     while (misseglist->objects > 0) {
21805       ms = misseglist->objects;
21806       for (i = 0; i < misseglist->objects; i++) {
21807         subsegstack->newindex((void **) &paryseg);
21808         *paryseg = * (face *) fastlookup(misseglist, i);
21809       }
21810       misseglist->restart();
21811 
21812       recoversegments(misseglist, 1, 1);
21813 
21814       if (misseglist->objects < ms) {
21815         // The number of missing segments is reduced.
21816         continue;
21817       } else {
21818         break;
21819       }
21820     }
21821     if (b->verbose) {
21822       printf("  Added %ld Steiner points in volume.\n", st_volref_count);
21823     }
21824   }
21825 
21826   if (misseglist->objects > 0) {
21827     // Last, trying to recover segments by doing more flips (fullsearch),
21828     //   and adding Steiner points in the volume, and splitting segments.
21829     long bak_inpoly_count = st_volref_count; //st_inpoly_count;
21830     for (i = 0; i < misseglist->objects; i++) {
21831       subsegstack->newindex((void **) &paryseg);
21832       *paryseg = * (face *) fastlookup(misseglist, i);
21833     }
21834     misseglist->restart();
21835 
21836     recoversegments(misseglist, 1, 2);
21837 
21838     if (b->verbose) {
21839       printf("  Added %ld Steiner points in segments.\n", st_segref_count);
21840       if (st_volref_count > bak_inpoly_count) {
21841         printf("  Added another %ld Steiner points in volume.\n",
21842                st_volref_count - bak_inpoly_count);
21843       }
21844     }
21845     assert(misseglist->objects == 0l);
21846   }
21847 
21848 
21849   if (st_segref_count > 0) {
21850     // Try to remove the Steiner points added in segments.
21851     bak_segref_count = st_segref_count;
21852     bak_volref_count = st_volref_count;
21853     for (i = 0; i < subvertstack->objects; i++) {
21854       // Get the Steiner point.
21855       parypt = (point *) fastlookup(subvertstack, i);
21856       rempt = *parypt;
21857       if (!removevertexbyflips(rempt)) {
21858         // Save it in list.
21859         bdrysteinerptlist->newindex((void **) &parypt);
21860         *parypt = rempt;
21861       }
21862     }
21863     if (b->verbose) {
21864       if (st_segref_count < bak_segref_count) {
21865         if (bak_volref_count < st_volref_count) {
21866           printf("  Suppressed %ld Steiner points in segments.\n",
21867                  st_volref_count - bak_volref_count);
21868         }
21869         if ((st_segref_count + (st_volref_count - bak_volref_count)) <
21870             bak_segref_count) {
21871           printf("  Removed %ld Steiner points in segments.\n",
21872                  bak_segref_count -
21873                    (st_segref_count + (st_volref_count - bak_volref_count)));
21874         }
21875       }
21876     }
21877     subvertstack->restart();
21878   }
21879 
21880 
21881   tv = clock();
21882 
21883   if (b->verbose) {
21884     printf("  Recovering facets.\n");
21885   }
21886 
21887   // Subfaces will be introduced.
21888   checksubfaceflag = 1;
21889 
21890   misshlist = new arraypool(sizeof(face), 8);
21891 
21892   // Randomly order the subfaces.
21893   subfaces->traversalinit();
21894   for (i = 0; i < subfaces->items; i++) {
21895     s = randomnation(i + 1);
21896     // Move the s-th subface to the i-th.
21897     subfacstack->newindex((void **) &parysh);
21898     *parysh = * (face *) fastlookup(subfacstack, s);
21899     // Put i-th subface to be the s-th.
21900     searchsh.sh = shellfacetraverse(subfaces);
21901     parysh = (face *) fastlookup(subfacstack, s);
21902     *parysh = searchsh;
21903   }
21904 
21905   ms = subfaces->items;
21906   nit = 0;
21907   b->fliplinklevel = -1; // Init.
21908   if (b->fliplinklevel < 0) {
21909     autofliplinklevel = 1; // Init value.
21910   }
21911 
21912   while (1) {
21913     recoversubfaces(misshlist, 0);
21914 
21915     if (misshlist->objects > 0) {
21916       if (b->fliplinklevel >= 0) {
21917         break;
21918       } else {
21919         if (misshlist->objects >= ms) {
21920           nit++;
21921           if (nit >= 3) {
21922             //break;
21923             // Do the last round with unbounded flip link level.
21924             b->fliplinklevel = 100000;
21925           }
21926         } else {
21927           ms = misshlist->objects;
21928           if (nit > 0) {
21929             nit--;
21930           }
21931         }
21932         for (i = 0; i < misshlist->objects; i++) {
21933           subfacstack->newindex((void **) &parysh);
21934           *parysh = * (face *) fastlookup(misshlist, i);
21935         }
21936         misshlist->restart();
21937         autofliplinklevel+=b->fliplinklevelinc;
21938       }
21939     } else {
21940       // All subfaces are recovered.
21941       break;
21942     }
21943   } // while (1)
21944 
21945   if (b->verbose) {
21946     printf("  %ld (%ld) subfaces are recovered (missing).\n",
21947            subfaces->items - misshlist->objects, misshlist->objects);
21948   }
21949 
21950   if (misshlist->objects > 0) {
21951     // There are missing subfaces. Add Steiner points.
21952     for (i = 0; i < misshlist->objects; i++) {
21953       subfacstack->newindex((void **) &parysh);
21954       *parysh = * (face *) fastlookup(misshlist, i);
21955     }
21956     misshlist->restart();
21957 
21958     recoversubfaces(nullptr, 1);
21959 
21960     if (b->verbose) {
21961       printf("  Added %ld Steiner points in facets.\n", st_facref_count);
21962     }
21963   }
21964 
21965 
21966   if (st_facref_count > 0) {
21967     // Try to remove the Steiner points added in facets.
21968     bak_facref_count = st_facref_count;
21969     for (i = 0; i < subvertstack->objects; i++) {
21970       // Get the Steiner point.
21971       parypt = (point *) fastlookup(subvertstack, i);
21972       rempt = *parypt;
21973       if (!removevertexbyflips(*parypt)) {
21974         // Save it in list.
21975         bdrysteinerptlist->newindex((void **) &parypt);
21976         *parypt = rempt;
21977       }
21978     }
21979     if (b->verbose) {
21980       if (st_facref_count < bak_facref_count) {
21981         printf("  Removed %ld Steiner points in facets.\n",
21982                bak_facref_count - st_facref_count);
21983       }
21984     }
21985     subvertstack->restart();
21986   }
21987 
21988 
21989   if (bdrysteinerptlist->objects > 0) {
21990     if (b->verbose) {
21991       printf("  %ld Steiner points remained in boundary.\n",
21992              bdrysteinerptlist->objects);
21993     }
21994   } // if
21995 
21996 
21997   // Accumulate the dynamic memory.
21998   totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
21999                       bdrysteinerptlist->totalmemory);
22000 
22001   // [Bruno] added this catch block to delete dynamically allocated
22002   // variables before "re-throwing" the exception.
22003   } catch(...) {
22004       delete bdrysteinerptlist;
22005       delete misseglist;
22006       delete misshlist;
22007       throw;
22008   }
22009 
22010   delete bdrysteinerptlist;
22011   delete misseglist;
22012   delete misshlist;
22013 }
22014 
22015 ////                                                                       ////
22016 ////                                                                       ////
22017 //// steiner_cxx //////////////////////////////////////////////////////////////
22018 
22019 
22020 //// reconstruct_cxx //////////////////////////////////////////////////////////
22021 ////                                                                       ////
22022 ////                                                                       ////
22023 
22024 ///////////////////////////////////////////////////////////////////////////////
22025 //                                                                           //
22026 // carveholes()    Remove tetrahedra not in the mesh domain.                 //
22027 //                                                                           //
22028 ///////////////////////////////////////////////////////////////////////////////
22029 
22030 
carveholes()22031 void tetgenmesh::carveholes()
22032 {
22033   arraypool *tetarray, *hullarray;
22034   triface tetloop, neightet, *parytet, *parytet1;
22035   triface *regiontets = nullptr;
22036   face checksh, *parysh;
22037   face checkseg;
22038   point ptloop, *parypt;
22039   int t1ver;
22040   int i, j, k;
22041 
22042   if (!b->quiet) {
22043     if (b->convex) {
22044       printf("Marking exterior tetrahedra ...\n");
22045     } else {
22046       printf("Removing exterior tetrahedra ...\n");
22047     }
22048   }
22049 
22050   // Initialize the pool of exterior tets.
22051   tetarray = new arraypool(sizeof(triface), 10);
22052   hullarray = new arraypool(sizeof(triface), 10);
22053 
22054   // Collect unprotected tets and hull tets.
22055   tetrahedrons->traversalinit();
22056   tetloop.ver = 11; // The face opposite to dummypoint.
22057   tetloop.tet = alltetrahedrontraverse();
22058   while (tetloop.tet != (tetrahedron *) nullptr) {
22059     if (ishulltet(tetloop)) {
22060       // Is this side protected by a subface?
22061       if (!issubface(tetloop)) {
22062         // Collect an unprotected hull tet and tet.
22063         infect(tetloop);
22064         hullarray->newindex((void **) &parytet);
22065         *parytet = tetloop;
22066         // tetloop's face number is 11 & 3 = 3.
22067         decode(tetloop.tet[3], neightet);
22068         if (!infected(neightet)) {
22069           infect(neightet);
22070           tetarray->newindex((void **) &parytet);
22071           *parytet = neightet;
22072         }
22073       }
22074     }
22075     tetloop.tet = alltetrahedrontraverse();
22076   }
22077 
22078   if (in->numberofholes > 0) {
22079     // Mark as infected any tets inside volume holes.
22080     for (i = 0; i < 3 * in->numberofholes; i += 3) {
22081       // Search a tet containing the i-th hole point.
22082       neightet.tet = nullptr;
22083       randomsample(&(in->holelist[i]), &neightet);
22084       if (locate(&(in->holelist[i]), &neightet, 0) != OUTSIDE) {
22085         // The tet 'neightet' contain this point.
22086         if (!infected(neightet)) {
22087           infect(neightet);
22088           tetarray->newindex((void **) &parytet);
22089           *parytet = neightet;
22090           // Add its adjacent tet if it is not protected.
22091           if (!issubface(neightet)) {
22092             decode(neightet.tet[neightet.ver & 3], tetloop);
22093             if (!infected(tetloop)) {
22094               infect(tetloop);
22095               if (ishulltet(tetloop)) {
22096                 hullarray->newindex((void **) &parytet);
22097               } else {
22098                 tetarray->newindex((void **) &parytet);
22099               }
22100               *parytet = tetloop;
22101             }
22102           }
22103           else {
22104             // It is protected. Check if its adjacent tet is a hull tet.
22105             decode(neightet.tet[neightet.ver & 3], tetloop);
22106             if (ishulltet(tetloop)) {
22107               // It is hull tet, add it into the list. Moreover, the subface
22108               //   is dead, i.e., both sides are in exterior.
22109               if (!infected(tetloop)) {
22110                 infect(tetloop);
22111                 hullarray->newindex((void **) &parytet);
22112                 *parytet = tetloop;
22113               }
22114             }
22115             if (infected(tetloop)) {
22116               // Both sides of this subface are in exterior.
22117               tspivot(neightet, checksh);
22118               sinfect(checksh); // Only queue it once.
22119               subfacstack->newindex((void **) &parysh);
22120               *parysh = checksh;
22121             }
22122           }
22123         } // if (!infected(neightet))
22124       } else {
22125         // A hole point locates outside of the convex hull.
22126         if (!b->quiet) {
22127           printf("Warning:  The %d-th hole point ", i/3 + 1);
22128           printf("lies outside the convex hull.\n");
22129         }
22130       }
22131     } // i
22132   } // if (in->numberofholes > 0)
22133 
22134   if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
22135     // Record the tetrahedra that contains the region points for assigning
22136     //   region attributes after the holes have been carved.
22137     regiontets = new triface[in->numberofregions];
22138     // Mark as marktested any tetrahedra inside volume regions.
22139     for (i = 0; i < 5 * in->numberofregions; i += 5) {
22140       // Search a tet containing the i-th region point.
22141       neightet.tet = nullptr;
22142       randomsample(&(in->regionlist[i]), &neightet);
22143       if (locate(&(in->regionlist[i]), &neightet, 0) != OUTSIDE) {
22144         regiontets[i/5] = neightet;
22145       } else {
22146         if (!b->quiet) {
22147           printf("Warning:  The %d-th region point ", i/5+1);
22148           printf("lies outside the convex hull.\n");
22149         }
22150         regiontets[i/5].tet = nullptr;
22151       }
22152     }
22153   }
22154 
22155   // Collect all exterior tets (in concave place and in holes).
22156   for (i = 0; i < tetarray->objects; i++) {
22157     parytet = (triface *) fastlookup(tetarray, i);
22158     j = (parytet->ver & 3); // j is the current face number.
22159     // Check the other three adjacent tets.
22160     for (k = 1; k < 4; k++) {
22161       decode(parytet->tet[(j + k) % 4], neightet);
22162       // neightet may be a hull tet.
22163       if (!infected(neightet)) {
22164         // Is neightet protected by a subface.
22165         if (!issubface(neightet)) {
22166           // Not proected. Collect it. (It must not be a hull tet).
22167           infect(neightet);
22168           tetarray->newindex((void **) &parytet1);
22169           *parytet1 = neightet;
22170         } else {
22171           // Protected. Check if it is a hull tet.
22172           if (ishulltet(neightet)) {
22173             // A hull tet. Collect it.
22174             infect(neightet);
22175             hullarray->newindex((void **) &parytet1);
22176             *parytet1 = neightet;
22177             // Both sides of this subface are exterior.
22178             tspivot(neightet, checksh);
22179             // Queue this subface (to be deleted later).
22180             assert(!sinfected(checksh));
22181             sinfect(checksh); // Only queue it once.
22182             subfacstack->newindex((void **) &parysh);
22183             *parysh = checksh;
22184           }
22185         }
22186       } else {
22187         // Both sides of this face are in exterior.
22188         // If there is a subface. It should be collected.
22189         if (issubface(neightet)) {
22190           tspivot(neightet, checksh);
22191           if (!sinfected(checksh)) {
22192             sinfect(checksh);
22193             subfacstack->newindex((void **) &parysh);
22194             *parysh = checksh;
22195           }
22196         }
22197       }
22198     } // j, k
22199   } // i
22200 
22201   if (b->regionattrib && (in->numberofregions > 0)) {
22202     // Re-check saved region tets to see if they lie outside.
22203     for (i = 0; i < in->numberofregions; i++) {
22204       if (infected(regiontets[i])) {
22205         if (b->verbose) {
22206           printf("Warning:  The %d-th region point ", i+1);
22207           printf("lies in the exterior of the domain.\n");
22208         }
22209         regiontets[i].tet = nullptr;
22210       }
22211     }
22212   }
22213 
22214   // Collect vertices which point to infected tets. These vertices
22215   //   may get deleted after the removal of exterier tets.
22216   //   If -Y1 option is used, collect all Steiner points for removal.
22217   //   The lists 'cavetetvertlist' and 'subvertstack' are re-used.
22218   points->traversalinit();
22219   ptloop = pointtraverse();
22220   while (ptloop != nullptr) {
22221     if ((pointtype(ptloop) != UNUSEDVERTEX) &&
22222         (pointtype(ptloop) != DUPLICATEDVERTEX)) {
22223       decode(point2tet(ptloop), neightet);
22224       if (infected(neightet)) {
22225         cavetetvertlist->newindex((void **) &parypt);
22226         *parypt = ptloop;
22227       }
22228       if (b->nobisect && (b->nobisect_param > 0)) { // -Y1
22229         // Queue it if it is a Steiner point.
22230         if (pointmark(ptloop) >
22231               (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22232           subvertstack->newindex((void **) &parypt);
22233           *parypt = ptloop;
22234         }
22235       }
22236     }
22237     ptloop = pointtraverse();
22238   }
22239 
22240   if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
22241     // Remove exterior tets. Hull tets are updated.
22242     arraypool *newhullfacearray;
22243     triface hulltet, casface;
22244     point pa, pb, pc;
22245 
22246     newhullfacearray = new arraypool(sizeof(triface), 10);
22247 
22248     // Create and save new hull tets.
22249     for (i = 0; i < tetarray->objects; i++) {
22250       parytet = (triface *) fastlookup(tetarray, i);
22251       for (j = 0; j < 4; j++) {
22252         decode(parytet->tet[j], tetloop);
22253         if (!infected(tetloop)) {
22254           // Found a new hull face (must be a subface).
22255           tspivot(tetloop, checksh);
22256           maketetrahedron(&hulltet);
22257           pa = org(tetloop);
22258           pb = dest(tetloop);
22259           pc = apex(tetloop);
22260           setvertices(hulltet, pb, pa, pc, dummypoint);
22261           bond(tetloop, hulltet);
22262           // Update the subface-to-tet map.
22263           sesymself(checksh);
22264           tsbond(hulltet, checksh);
22265           // Update the segment-to-tet map.
22266           for (k = 0; k < 3; k++) {
22267             if (issubseg(tetloop)) {
22268               tsspivot1(tetloop, checkseg);
22269               tssbond1(hulltet, checkseg);
22270               sstbond1(checkseg, hulltet);
22271             }
22272             enextself(tetloop);
22273             eprevself(hulltet);
22274           }
22275           // Update the point-to-tet map.
22276           setpoint2tet(pa, (tetrahedron) tetloop.tet);
22277           setpoint2tet(pb, (tetrahedron) tetloop.tet);
22278           setpoint2tet(pc, (tetrahedron) tetloop.tet);
22279           // Save the exterior tet at this hull face. It still holds pointer
22280           //   to the adjacent interior tet. Use it to connect new hull tets.
22281           newhullfacearray->newindex((void **) &parytet1);
22282           parytet1->tet = parytet->tet;
22283           parytet1->ver = j;
22284         } // if (!infected(tetloop))
22285       } // j
22286     } // i
22287 
22288     // Connect new hull tets.
22289     for (i = 0; i < newhullfacearray->objects; i++) {
22290       parytet = (triface *) fastlookup(newhullfacearray, i);
22291       fsym(*parytet, neightet);
22292       // Get the new hull tet.
22293       fsym(neightet, hulltet);
22294       for (j = 0; j < 3; j++) {
22295         esym(hulltet, casface);
22296         if (casface.tet[casface.ver & 3] == nullptr) {
22297           // Since the boundary of the domain may not be a manifold, we
22298           //   find the adjacent hull face by travesing the tets in the
22299           //   exterior (which are all infected tets).
22300           neightet = *parytet;
22301           while (1) {
22302             fnextself(neightet);
22303             if (!infected(neightet)) break;
22304           }
22305           if (!ishulltet(neightet)) {
22306             // An interior tet. Get the new hull tet.
22307             fsymself(neightet);
22308             esymself(neightet);
22309           }
22310           // Bond them together.
22311           bond(casface, neightet);
22312         }
22313         enextself(hulltet);
22314         enextself(*parytet);
22315       } // j
22316     } // i
22317 
22318     if (subfacstack->objects > 0l) {
22319       // Remove all subfaces which do not attach to any tetrahedron.
22320       //   Segments which are not attached to any subfaces and tets
22321       //   are deleted too.
22322       face casingout, casingin;
22323       long delsegcount = 0l;
22324 
22325       for (i = 0; i < subfacstack->objects; i++) {
22326         parysh = (face *) fastlookup(subfacstack, i);
22327         if (i == 0) {
22328           if (b->verbose) {
22329             printf("Warning:  Removing an open face (%d, %d, %d)\n",
22330                    pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
22331                    pointmark(sapex(*parysh)));
22332           }
22333         }
22334         // Dissolve this subface from face links.
22335         for (j = 0; j < 3; j++) {
22336           spivot(*parysh, casingout);
22337           sspivot(*parysh, checkseg);
22338           if (casingout.sh != nullptr) {
22339             casingin = casingout;
22340             while (1) {
22341               spivot(casingin, checksh);
22342               if (checksh.sh == parysh->sh) break;
22343               casingin = checksh;
22344             }
22345             if (casingin.sh != casingout.sh) {
22346               // Update the link: ... -> casingin -> casingout ->...
22347               sbond1(casingin, casingout);
22348             } else {
22349               // Only one subface at this edge is left.
22350               sdissolve(casingout);
22351             }
22352             if (checkseg.sh != nullptr) {
22353               // Make sure the segment does not connect to a dead one.
22354               ssbond(casingout, checkseg);
22355             }
22356           } else {
22357             if (checkseg.sh != nullptr) {
22358               // The segment is also dead.
22359               if (delsegcount == 0) {
22360                 if (b->verbose) {
22361                   printf("Warning:  Removing a dangling segment (%d, %d)\n",
22362                        pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
22363                 }
22364               }
22365               shellfacedealloc(subsegs, checkseg.sh);
22366               delsegcount++;
22367             }
22368           }
22369           senextself(*parysh);
22370         } // j
22371         // Delete this subface.
22372         shellfacedealloc(subfaces, parysh->sh);
22373       } // i
22374       if (b->verbose) {
22375         printf("  Deleted %ld subfaces.\n", subfacstack->objects);
22376         if (delsegcount > 0) {
22377           printf("  Deleted %ld segments.\n", delsegcount);
22378         }
22379       }
22380       subfacstack->restart();
22381     } // if (subfacstack->objects > 0l)
22382 
22383     if (cavetetvertlist->objects > 0l) {
22384       // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
22385       long delvertcount = unuverts;
22386       long delsteinercount = 0l;
22387 
22388       for (i = 0; i < cavetetvertlist->objects; i++) {
22389         parypt = (point *) fastlookup(cavetetvertlist, i);
22390         decode(point2tet(*parypt), neightet);
22391         if (infected(neightet)) {
22392           // Found an exterior vertex.
22393           if (pointmark(*parypt) >
22394                 (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22395             // A Steiner point.
22396             if (pointtype(*parypt) == FREESEGVERTEX) {
22397               st_segref_count--;
22398             } else if (pointtype(*parypt) == FREEFACETVERTEX) {
22399               st_facref_count--;
22400             } else {
22401               assert(pointtype(*parypt) == FREEVOLVERTEX);
22402               st_volref_count--;
22403             }
22404             delsteinercount++;
22405             if (steinerleft > 0) steinerleft++;
22406           }
22407           setpointtype(*parypt, UNUSEDVERTEX);
22408           unuverts++;
22409         }
22410       }
22411 
22412       if (b->verbose) {
22413         if (unuverts > delvertcount) {
22414           if (delsteinercount > 0l) {
22415             if (unuverts > (delvertcount + delsteinercount)) {
22416               printf("  Removed %ld exterior input vertices.\n",
22417                      unuverts - delvertcount - delsteinercount);
22418             }
22419             printf("  Removed %ld exterior Steiner vertices.\n",
22420                    delsteinercount);
22421           } else {
22422             printf("  Removed %ld exterior input vertices.\n",
22423                    unuverts - delvertcount);
22424           }
22425         }
22426       }
22427       cavetetvertlist->restart();
22428       // Comment: 'subvertstack' will be cleaned in routine
22429       //   suppresssteinerpoints().
22430     } // if (cavetetvertlist->objects > 0l)
22431 
22432     // Update the hull size.
22433     hullsize += (newhullfacearray->objects - hullarray->objects);
22434 
22435     // Delete all exterior tets and old hull tets.
22436     for (i = 0; i < tetarray->objects; i++) {
22437       parytet = (triface *) fastlookup(tetarray, i);
22438       tetrahedrondealloc(parytet->tet);
22439     }
22440     tetarray->restart();
22441 
22442     for (i = 0; i < hullarray->objects; i++) {
22443       parytet = (triface *) fastlookup(hullarray, i);
22444       tetrahedrondealloc(parytet->tet);
22445     }
22446     hullarray->restart();
22447 
22448     delete newhullfacearray;
22449   } // if (!b->convex && (tetarray->objects > 0l))
22450 
22451   if (b->convex && (tetarray->objects > 0l)) { // With -c option
22452     // In this case, all exterior tets get a region marker '-1'.
22453     assert(b->regionattrib > 0); // -A option must be enabled.
22454     int attrnum = numelemattrib - 1;
22455 
22456     for (i = 0; i < tetarray->objects; i++) {
22457       parytet = (triface *) fastlookup(tetarray, i);
22458       setelemattribute(parytet->tet, attrnum, -1);
22459     }
22460     tetarray->restart();
22461 
22462     for (i = 0; i < hullarray->objects; i++) {
22463       parytet = (triface *) fastlookup(hullarray, i);
22464       uninfect(*parytet);
22465     }
22466     hullarray->restart();
22467 
22468     if (subfacstack->objects > 0l) {
22469       for (i = 0; i < subfacstack->objects; i++) {
22470         parysh = (face *) fastlookup(subfacstack, i);
22471         suninfect(*parysh);
22472       }
22473       subfacstack->restart();
22474     }
22475 
22476     if (cavetetvertlist->objects > 0l) {
22477       cavetetvertlist->restart();
22478     }
22479   } // if (b->convex && (tetarray->objects > 0l))
22480 
22481   if (b->regionattrib) { // With -A option.
22482     if (!b->quiet) {
22483       printf("Spreading region attributes.\n");
22484     }
22485     REAL volume;
22486     int attr, maxattr = 0; // Choose a small number here.
22487     int attrnum = numelemattrib - 1;
22488     // Comment: The element region marker is at the end of the list of
22489     //   the element attributes.
22490     int regioncount = 0;
22491 
22492     // If has user-defined region attributes.
22493     if (in->numberofregions > 0) {
22494       // Spread region attributes.
22495       for (i = 0; i < 5 * in->numberofregions; i += 5) {
22496         if (regiontets[i/5].tet != nullptr) {
22497           attr = (int) in->regionlist[i + 3];
22498           if (attr > maxattr) {
22499             maxattr = attr;
22500           }
22501           volume = in->regionlist[i + 4];
22502           tetarray->restart(); // Re-use this array.
22503           infect(regiontets[i/5]);
22504           tetarray->newindex((void **) &parytet);
22505           *parytet = regiontets[i/5];
22506           // Collect and set attrs for all tets of this region.
22507           for (j = 0; j < tetarray->objects; j++) {
22508             parytet = (triface *) fastlookup(tetarray, j);
22509             tetloop = *parytet;
22510             setelemattribute(tetloop.tet, attrnum, attr);
22511             if (b->varvolume) { // If has -a option.
22512               setvolumebound(tetloop.tet, volume);
22513             }
22514             for (k = 0; k < 4; k++) {
22515               decode(tetloop.tet[k], neightet);
22516               // Is the adjacent already checked?
22517               if (!infected(neightet)) {
22518                 // Is this side protected by a subface?
22519                 if (!issubface(neightet)) {
22520                   infect(neightet);
22521                   tetarray->newindex((void **) &parytet);
22522                   *parytet = neightet;
22523                 }
22524               }
22525             } // k
22526           } // j
22527           regioncount++;
22528         } // if (regiontets[i/5].tet != nullptr)
22529       } // i
22530     }
22531 
22532     // Set attributes for all tetrahedra.
22533     attr = maxattr + 1;
22534     tetrahedrons->traversalinit();
22535     tetloop.tet = tetrahedrontraverse();
22536     while (tetloop.tet != (tetrahedron *) nullptr) {
22537       if (!infected(tetloop)) {
22538         // An unmarked region.
22539         tetarray->restart(); // Re-use this array.
22540         infect(tetloop);
22541         tetarray->newindex((void **) &parytet);
22542         *parytet = tetloop;
22543         // Find and mark all tets.
22544         for (j = 0; j < tetarray->objects; j++) {
22545           parytet = (triface *) fastlookup(tetarray, j);
22546           tetloop = *parytet;
22547           setelemattribute(tetloop.tet, attrnum, attr);
22548           for (k = 0; k < 4; k++) {
22549             decode(tetloop.tet[k], neightet);
22550             // Is the adjacent tet already checked?
22551             if (!infected(neightet)) {
22552               // Is this side protected by a subface?
22553               if (!issubface(neightet)) {
22554                 infect(neightet);
22555                 tetarray->newindex((void **) &parytet);
22556                 *parytet = neightet;
22557               }
22558             }
22559           } // k
22560         } // j
22561         attr++; // Increase the attribute.
22562         regioncount++;
22563       }
22564       tetloop.tet = tetrahedrontraverse();
22565     }
22566     // Until here, every tet has a region attribute.
22567 
22568     // Uninfect processed tets.
22569     tetrahedrons->traversalinit();
22570     tetloop.tet = tetrahedrontraverse();
22571     while (tetloop.tet != (tetrahedron *) nullptr) {
22572       uninfect(tetloop);
22573       tetloop.tet = tetrahedrontraverse();
22574     }
22575 
22576     if (b->verbose) {
22577       //assert(regioncount > 0);
22578       if (regioncount > 1) {
22579         printf("  Found %d subdomains.\n", regioncount);
22580       } else {
22581         printf("  Found %d domain.\n", regioncount);
22582       }
22583     }
22584   } // if (b->regionattrib)
22585 
22586   if (regiontets != nullptr) {
22587     delete [] regiontets;
22588   }
22589   delete tetarray;
22590   delete hullarray;
22591 
22592   if (!b->convex) { // No -c option
22593     // The mesh is non-convex now.
22594     nonconvex = 1;
22595 
22596     // Push all hull tets into 'flipstack'.
22597     tetrahedrons->traversalinit();
22598     tetloop.ver = 11; // The face opposite to dummypoint.
22599     tetloop.tet = alltetrahedrontraverse();
22600     while (tetloop.tet != (tetrahedron *) nullptr) {
22601       if ((point) tetloop.tet[7] == dummypoint) {
22602         fsym(tetloop, neightet);
22603         flippush(flipstack, &neightet);
22604       }
22605       tetloop.tet = alltetrahedrontraverse();
22606     }
22607 
22608     flipconstraints fc;
22609     fc.enqflag = 2;
22610     long sliver_peel_count = lawsonflip3d(&fc);
22611 
22612     if (sliver_peel_count > 0l) {
22613       if (b->verbose) {
22614         printf("  Removed %ld hull slivers.\n", sliver_peel_count);
22615       }
22616     }
22617     unflipqueue->restart();
22618   } // if (!b->convex)
22619 }
22620 
22621 ///////////////////////////////////////////////////////////////////////////////
22622 //                                                                           //
22623 // reconstructmesh()    Reconstruct a tetrahedral mesh.                      //
22624 //                                                                           //
22625 ///////////////////////////////////////////////////////////////////////////////
22626 
reconstructmesh()22627 void tetgenmesh::reconstructmesh()
22628 {
22629   tetrahedron *ver2tetarray;
22630   point *idx2verlist;
22631   triface tetloop, checktet, prevchktet;
22632   triface hulltet, face1, face2;
22633   tetrahedron tptr;
22634   face subloop, neighsh, nextsh;
22635   face segloop;
22636   shellface sptr;
22637   point p[4], q[3];
22638   REAL ori, attrib, volume;
22639   REAL angtol, ang;
22640   int eextras, marker = 0;
22641   int bondflag;
22642   int t1ver;
22643   int idx, i, j, k;
22644 
22645   if (!b->quiet) {
22646     printf("Reconstructing mesh ...\n");
22647   }
22648 
22649   if (b->convex) { // -c option.
22650     // Assume the mesh is convex. Exterior tets have region attribute -1.
22651     assert(in->numberoftetrahedronattributes > 0);
22652   } else {
22653     // Assume the mesh is non-convex.
22654     nonconvex = 1;
22655   }
22656 
22657   // Create a map from indices to vertices.
22658   makeindex2pointmap(idx2verlist);
22659   // 'idx2verlist' has length 'in->numberofpoints + 1'.
22660   if (in->firstnumber == 1) {
22661     idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
22662   }
22663 
22664   // Allocate an array that maps each vertex to its adjacent tets.
22665   ver2tetarray = new tetrahedron[in->numberofpoints + 1];
22666   //for (i = 0; i < in->numberofpoints + 1; i++) {
22667   for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
22668     setpointtype(idx2verlist[i], VOLVERTEX); // initial type.
22669     ver2tetarray[i] = nullptr;
22670   }
22671 
22672   // Create the tetrahedra and connect those that share a common face.
22673   for (i = 0; i < in->numberoftetrahedra; i++) {
22674     // Get the four vertices.
22675     idx = i * in->numberofcorners;
22676     for (j = 0; j < 4; j++) {
22677       p[j] = idx2verlist[in->tetrahedronlist[idx++]];
22678     }
22679     // Check the orientation.
22680     ori = orient3d(p[0], p[1], p[2], p[3]);
22681     if (ori > 0.0) {
22682       // Swap the first two vertices.
22683       q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
22684     } else if (ori == 0.0) {
22685       if (!b->quiet) {
22686         printf("Warning:  Tet #%d is degenerate.\n", i + in->firstnumber);
22687       }
22688     }
22689     // Create a new tetrahedron.
22690     maketetrahedron(&tetloop); // tetloop.ver = 11.
22691     setvertices(tetloop, p[0], p[1], p[2], p[3]);
22692     // Set element attributes if they exist.
22693     for (j = 0; j < in->numberoftetrahedronattributes; j++) {
22694       idx = i * in->numberoftetrahedronattributes;
22695       attrib = in->tetrahedronattributelist[idx + j];
22696       setelemattribute(tetloop.tet, j, attrib);
22697     }
22698     // If -a switch is used (with no number follows) Set a volume
22699     //   constraint if it exists.
22700     if (b->varvolume) {
22701       if (in->tetrahedronvolumelist != (REAL *) nullptr) {
22702         volume = in->tetrahedronvolumelist[i];
22703       } else {
22704         volume = -1.0;
22705       }
22706       setvolumebound(tetloop.tet, volume);
22707     }
22708     // Try connecting this tet to others that share the common faces.
22709     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22710       p[3] = oppo(tetloop);
22711       // Look for other tets having this vertex.
22712       idx = pointmark(p[3]);
22713       tptr = ver2tetarray[idx];
22714       // Link the current tet to the next one in the stack.
22715       tetloop.tet[8 + tetloop.ver] = tptr;
22716       // Push the current tet onto the stack.
22717       ver2tetarray[idx] = encode(tetloop);
22718       decode(tptr, checktet);
22719       if (checktet.tet != nullptr) {
22720         p[0] =  org(tetloop); // a
22721         p[1] = dest(tetloop); // b
22722         p[2] = apex(tetloop); // c
22723         prevchktet = tetloop;
22724         do {
22725           q[0] =  org(checktet); // a'
22726           q[1] = dest(checktet); // b'
22727           q[2] = apex(checktet); // c'
22728           // Check the three faces at 'd' in 'checktet'.
22729           bondflag = 0;
22730           for (j = 0; j < 3; j++) {
22731             // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
22732             esym(checktet, face2);
22733             if (face2.tet[face2.ver & 3] == nullptr) {
22734               k = ((j + 1) % 3);
22735               if (q[k] == p[0]) {   // b', c', a' = a
22736                 if (q[j] == p[1]) { // a', b', c' = b
22737                   // [#,#,d] is matched to [b,a,d].
22738                   esym(tetloop, face1);
22739                   bond(face1, face2);
22740                   bondflag++;
22741                 }
22742               }
22743               if (q[k] == p[1]) {   // b',c',a' = b
22744                 if (q[j] == p[2]) { // a',b',c' = c
22745                   // [#,#,d] is matched to [c,b,d].
22746                   enext(tetloop, face1);
22747                   esymself(face1);
22748                   bond(face1, face2);
22749                   bondflag++;
22750                 }
22751               }
22752               if (q[k] == p[2]) {   // b',c',a' = c
22753                 if (q[j] == p[0]) { // a',b',c' = a
22754                   // [#,#,d] is matched to [a,c,d].
22755                   eprev(tetloop, face1);
22756                   esymself(face1);
22757                   bond(face1, face2);
22758                   bondflag++;
22759                 }
22760               }
22761             } else {
22762               bondflag++;
22763             }
22764             enextself(checktet);
22765           } // j
22766           // Go to the next tet in the link.
22767           tptr = checktet.tet[8 + checktet.ver];
22768           if (bondflag == 3) {
22769             // All three faces at d in 'checktet' have been connected.
22770             // It can be removed from the link.
22771             prevchktet.tet[8 + prevchktet.ver] = tptr;
22772           } else {
22773             // Bakup the previous tet in the link.
22774             prevchktet = checktet;
22775           }
22776           decode(tptr, checktet);
22777         } while (checktet.tet != nullptr);
22778       } // if (checktet.tet != nullptr)
22779     } // for (tetloop.ver = 0; ...
22780   } // i
22781 
22782   // Remember a tet of the mesh.
22783   recenttet = tetloop;
22784 
22785   // Create hull tets, create the point-to-tet map, and clean up the
22786   //   temporary spaces used in each tet.
22787   hullsize = tetrahedrons->items;
22788 
22789   tetrahedrons->traversalinit();
22790   tetloop.tet = tetrahedrontraverse();
22791   while (tetloop.tet != (tetrahedron *) nullptr) {
22792     tptr = encode(tetloop);
22793     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22794       if (tetloop.tet[tetloop.ver] == nullptr) {
22795         // Create a hull tet.
22796         maketetrahedron(&hulltet);
22797         p[0] =  org(tetloop);
22798         p[1] = dest(tetloop);
22799         p[2] = apex(tetloop);
22800         setvertices(hulltet, p[1], p[0], p[2], dummypoint);
22801         bond(tetloop, hulltet);
22802         // Try connecting this to others that share common hull edges.
22803         for (j = 0; j < 3; j++) {
22804           fsym(hulltet, face2);
22805           while (1) {
22806             if (face2.tet == nullptr) break;
22807             esymself(face2);
22808             if (apex(face2) == dummypoint) break;
22809             fsymself(face2);
22810           }
22811           if (face2.tet != nullptr) {
22812             // Found an adjacent hull tet.
22813             assert(face2.tet[face2.ver & 3] == nullptr);
22814             esym(hulltet, face1);
22815             bond(face1, face2);
22816           }
22817           enextself(hulltet);
22818         }
22819         //hullsize++;
22820       }
22821       // Create the point-to-tet map.
22822       setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
22823       // Clean the temporary used space.
22824       tetloop.tet[8 + tetloop.ver] = nullptr;
22825     }
22826     tetloop.tet = tetrahedrontraverse();
22827   }
22828 
22829   hullsize = tetrahedrons->items - hullsize;
22830 
22831   // Subfaces will be inserted into the mesh.
22832   if (in->trifacelist != nullptr) {
22833     // A .face file is given. It may contain boundary faces. Insert them.
22834     for (i = 0; i < in->numberoftrifaces; i++) {
22835       // Is it a subface?
22836       if (in->trifacemarkerlist != nullptr) {
22837         marker = in->trifacemarkerlist[i];
22838       } else {
22839         // Face markers are not available. Assume all of them are subfaces.
22840         marker = 1;
22841       }
22842       if (marker > 0) {
22843         idx = i * 3;
22844         for (j = 0; j < 3; j++) {
22845           p[j] = idx2verlist[in->trifacelist[idx++]];
22846         }
22847         // Search the subface.
22848         bondflag = 0;
22849         // Make sure all vertices are in the mesh. Avoid crash.
22850         for (j = 0; j < 3; j++) {
22851           decode(point2tet(p[j]), checktet);
22852           if (checktet.tet == nullptr) break;
22853         }
22854         if ((j == 3) && getedge(p[0], p[1], &checktet)) {
22855           tetloop = checktet;
22856           q[2] = apex(checktet);
22857           while (1) {
22858             if (apex(tetloop) == p[2]) {
22859               // Found the face.
22860               // Check if there exist a subface already?
22861               tspivot(tetloop, neighsh);
22862               if (neighsh.sh != nullptr) {
22863                 // Found a duplicated subface.
22864                 // This happens when the mesh was generated by other mesher.
22865                 bondflag = 0;
22866               } else {
22867                 bondflag = 1;
22868               }
22869               break;
22870             }
22871             fnextself(tetloop);
22872             if (apex(tetloop) == q[2]) break;
22873           }
22874         }
22875         if (bondflag) {
22876           // Create a new subface.
22877           makeshellface(subfaces, &subloop);
22878           setshvertices(subloop, p[0], p[1], p[2]);
22879           // Create the point-to-subface map.
22880           sptr = sencode(subloop);
22881           for (j = 0; j < 3; j++) {
22882             setpointtype(p[j], FACETVERTEX); // initial type.
22883             setpoint2sh(p[j], sptr);
22884           }
22885           if (in->trifacemarkerlist != nullptr) {
22886             setshellmark(subloop, in->trifacemarkerlist[i]);
22887           }
22888           // Insert the subface into the mesh.
22889           tsbond(tetloop, subloop);
22890           fsymself(tetloop);
22891           sesymself(subloop);
22892           tsbond(tetloop, subloop);
22893         } else {
22894           if (!b->quiet) {
22895             if (neighsh.sh == nullptr) {
22896               printf("Warning:  Subface #%d [%d,%d,%d] is missing.\n",
22897                      i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22898                      pointmark(p[2]));
22899             } else {
22900               printf("Warning: Ignore a dunplicated subface #%d [%d,%d,%d].\n",
22901                      i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
22902                      pointmark(p[2]));
22903             }
22904           }
22905         } // if (bondflag)
22906       } // if (marker > 0)
22907     } // i
22908   } // if (in->trifacelist)
22909 
22910   if (!b->convex) { // Without -c option.
22911     // Indentify subfaces from the mesh.
22912     // Create subfaces for hull faces (if they're not subface yet) and
22913     //   interior faces which separate two different materials.
22914     eextras = in->numberoftetrahedronattributes;
22915     tetrahedrons->traversalinit();
22916     tetloop.tet = tetrahedrontraverse();
22917     while (tetloop.tet != (tetrahedron *) nullptr) {
22918       for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
22919         tspivot(tetloop, neighsh);
22920         if (neighsh.sh == nullptr) {
22921           bondflag = 0;
22922           fsym(tetloop, checktet);
22923           if (ishulltet(checktet)) {
22924             bondflag = 1;  // A hull face.
22925           } else {
22926             if (eextras > 0) {
22927               if (elemattribute(tetloop.tet, eextras - 1) !=
22928                   elemattribute(checktet.tet, eextras - 1)) {
22929                 bondflag = 1; // An interior interface.
22930               }
22931             }
22932           }
22933           if (bondflag) {
22934             // Create a new subface.
22935             makeshellface(subfaces, &subloop);
22936             p[0] = org(tetloop);
22937             p[1] = dest(tetloop);
22938             p[2] = apex(tetloop);
22939             setshvertices(subloop, p[0], p[1], p[2]);
22940             // Create the point-to-subface map.
22941             sptr = sencode(subloop);
22942             for (j = 0; j < 3; j++) {
22943               setpointtype(p[j], FACETVERTEX); // initial type.
22944               setpoint2sh(p[j], sptr);
22945             }
22946             setshellmark(subloop, 0); // Default marker.
22947             // Insert the subface into the mesh.
22948             tsbond(tetloop, subloop);
22949             sesymself(subloop);
22950             tsbond(checktet, subloop);
22951           } // if (bondflag)
22952         } // if (neighsh.sh == nullptr)
22953       }
22954       tetloop.tet = tetrahedrontraverse();
22955     }
22956   } // if (!b->convex)
22957 
22958   // Connect subfaces together.
22959   subfaces->traversalinit();
22960   subloop.shver = 0;
22961   subloop.sh = shellfacetraverse(subfaces);
22962   while (subloop.sh != (shellface *) nullptr) {
22963     for (i = 0; i < 3; i++) {
22964       spivot(subloop, neighsh);
22965       if (neighsh.sh == nullptr) {
22966         // Form a subface ring by linking all subfaces at this edge.
22967         // Traversing all faces of the tets at this edge.
22968         stpivot(subloop, tetloop);
22969         q[2] = apex(tetloop);
22970         neighsh = subloop;
22971         while (1) {
22972           fnextself(tetloop);
22973           tspivot(tetloop, nextsh);
22974           if (nextsh.sh != nullptr) {
22975             // Link neighsh <= nextsh.
22976             sbond1(neighsh, nextsh);
22977             neighsh = nextsh;
22978           }
22979           if (apex(tetloop) == q[2]) {
22980             assert(nextsh.sh == subloop.sh); // It's a ring.
22981             break;
22982           }
22983         } // while (1)
22984       } // if (neighsh.sh == nullptr)
22985       senextself(subloop);
22986     }
22987     subloop.sh = shellfacetraverse(subfaces);
22988   }
22989 
22990 
22991   // Segments will be introudced.
22992   if (in->edgelist != nullptr) {
22993     // A .edge file is given. It may contain boundary edges. Insert them.
22994     for (i = 0; i < in->numberofedges; i++) {
22995       // Is it a segment?
22996       if (in->edgemarkerlist != nullptr) {
22997         marker = in->edgemarkerlist[i];
22998       } else {
22999         // Edge markers are not available. Assume all of them are segments.
23000         marker = 1;
23001       }
23002       if (marker != 0) {
23003         // Insert a segment.
23004         idx = i * 2;
23005         for (j = 0; j < 2; j++) {
23006           p[j] = idx2verlist[in->edgelist[idx++]];
23007         }
23008         // Make sure all vertices are in the mesh. Avoid crash.
23009         for (j = 0; j < 2; j++) {
23010           decode(point2tet(p[j]), checktet);
23011           if (checktet.tet == nullptr) break;
23012         }
23013         // Search the segment.
23014         if ((j == 2) && getedge(p[0], p[1], &checktet)) {
23015           // Create a new subface.
23016           makeshellface(subsegs, &segloop);
23017           setshvertices(segloop, p[0], p[1], nullptr);
23018           // Create the point-to-segment map.
23019           sptr = sencode(segloop);
23020           for (j = 0; j < 2; j++) {
23021             setpointtype(p[j], RIDGEVERTEX); // initial type.
23022             setpoint2sh(p[j], sptr);
23023           }
23024           if (in->edgemarkerlist != nullptr) {
23025             setshellmark(segloop, marker);
23026           }
23027           // Insert the segment into the mesh.
23028           tetloop = checktet;
23029           q[2] = apex(checktet);
23030           subloop.sh = nullptr;
23031           while (1) {
23032             tssbond1(tetloop, segloop);
23033             tspivot(tetloop, subloop);
23034             if (subloop.sh != nullptr) {
23035               ssbond1(subloop, segloop);
23036               sbond1(segloop, subloop);
23037             }
23038             fnextself(tetloop);
23039             if (apex(tetloop) == q[2]) break;
23040           } // while (1)
23041           // Remember an adjacent tet for this segment.
23042           sstbond1(segloop, tetloop);
23043         } else {
23044           if (!b->quiet) {
23045             printf("Warning:  Segment #%d [%d,%d] is missing.\n",
23046                    i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
23047           }
23048         }
23049       } // if (marker != 0)
23050     } // i
23051   } // if (in->edgelist)
23052 
23053   if (!b->convex) { // Without -c option.
23054     // Identify segments from the mesh.
23055     // Create segments for non-manifold edges (which are shared by more
23056     //   than two subfaces), and for non-coplanar edges, i.e., two subfaces
23057     //   form an dihedral angle > 'b->facet_ang_tol' (degree).
23058     angtol = b->facet_ang_tol / 180.0 * PI;
23059     subfaces->traversalinit();
23060     subloop.shver = 0;
23061     subloop.sh = shellfacetraverse(subfaces);
23062     while (subloop.sh != (shellface *) nullptr) {
23063       for (i = 0; i < 3; i++) {
23064         sspivot(subloop, segloop);
23065         if (segloop.sh == nullptr) {
23066           // Check if this edge is a segment.
23067           bondflag = 0;
23068           // Counter the number of subfaces at this edge.
23069           idx = 0;
23070           nextsh = subloop;
23071           while (1) {
23072             idx++;
23073             spivotself(nextsh);
23074             if (nextsh.sh == subloop.sh) break;
23075           }
23076           if (idx != 2) {
23077             // It's a non-manifold edge. Insert a segment.
23078             p[0] = sorg(subloop);
23079             p[1] = sdest(subloop);
23080             bondflag = 1;
23081           } else {
23082             // Check the dihedral angle formed by the two subfaces.
23083             spivot(subloop, neighsh);
23084             p[0] = sorg(subloop);
23085             p[1] = sdest(subloop);
23086             p[2] = sapex(subloop);
23087             p[3] = sapex(neighsh);
23088             ang = facedihedral(p[0], p[1], p[2], p[3]);
23089             if (ang > PI) ang = 2 * PI - ang;
23090             if (ang < angtol) {
23091               bondflag = 1;
23092             }
23093           }
23094           if (bondflag) {
23095             // Create a new subface.
23096             makeshellface(subsegs, &segloop);
23097             setshvertices(segloop, p[0], p[1], nullptr);
23098             // Create the point-to-segment map.
23099             sptr = sencode(segloop);
23100             for (j = 0; j < 2; j++) {
23101               setpointtype(p[j], RIDGEVERTEX); // initial type.
23102               setpoint2sh(p[j], sptr);
23103             }
23104             setshellmark(segloop, marker);
23105             // Insert the subface into the mesh.
23106             stpivot(subloop, tetloop);
23107             q[2] = apex(tetloop);
23108             while (1) {
23109               tssbond1(tetloop, segloop);
23110               tspivot(tetloop, neighsh);
23111               if (neighsh.sh != nullptr) {
23112                 ssbond1(neighsh, segloop);
23113               }
23114               fnextself(tetloop);
23115               if (apex(tetloop) == q[2]) break;
23116             } // while (1)
23117             // Remember an adjacent tet for this segment.
23118             sstbond1(segloop, tetloop);
23119             sbond1(segloop, subloop);
23120           } // if (bondflag)
23121         } // if (neighsh.sh == nullptr)
23122         senextself(subloop);
23123       }
23124       subloop.sh = shellfacetraverse(subfaces);
23125     }
23126   } // if (!b->convex)
23127 
23128   // Remember the number of input segments.
23129   insegments = subsegs->items;
23130 
23131 
23132   // Set global flags.
23133   checksubsegflag = 1;
23134   checksubfaceflag = 1;
23135 
23136   delete [] idx2verlist;
23137   delete [] ver2tetarray;
23138 }
23139 
23140 ///////////////////////////////////////////////////////////////////////////////
23141 //                                                                           //
23142 // scoutpoint()    Search a point in mesh.                                   //
23143 //                                                                           //
23144 // This function searches the point in a mesh whose domain may be not convex.//
23145 // In case of a convex domain, the locate() function is sufficient.          //
23146 //                                                                           //
23147 // If 'randflag' is used, randomly select a start searching tet.  Otherwise, //
23148 // start searching directly from 'searchtet'.                                //
23149 //                                                                           //
23150 ///////////////////////////////////////////////////////////////////////////////
23151 
scoutpoint(point searchpt,triface * searchtet,int randflag)23152 int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
23153 {
23154   point pa, pb, pc, pd;
23155   enum locateresult loc = OUTSIDE;
23156   REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
23157   int t1ver;
23158 
23159 
23160   // Randonmly select a good starting tet.
23161   if (randflag) {
23162     randomsample(searchpt, searchtet);
23163   } else {
23164     if (searchtet->tet == nullptr) {
23165       *searchtet = recenttet;
23166     }
23167   }
23168   loc = locate(searchpt, searchtet, 0);
23169 
23170   if (loc == OUTSIDE) {
23171     // Test if it lies nearly on the hull face.
23172     // Reuse vol, ori1.
23173     pa = org(*searchtet);
23174     pb = dest(*searchtet);
23175     pc = apex(*searchtet);
23176     vol = triarea(pa, pb, pc);
23177     ori1 = orient3dfast(pa, pb, pc, searchpt);
23178     if (fabs(ori1 / vol) < b->epsilon) {
23179       loc = ONFACE; // On face (or on edge, or on vertex).
23180       fsymself(*searchtet);
23181     }
23182   }
23183 
23184   if (loc != OUTSIDE) {
23185     // Round the result of location.
23186     pa = org(*searchtet);
23187     pb = dest(*searchtet);
23188     pc = apex(*searchtet);
23189     pd = oppo(*searchtet);
23190     vol = orient3dfast(pa, pb, pc, pd);
23191     ori1 = orient3dfast(pa, pb, pc, searchpt);
23192     ori2 = orient3dfast(pb, pa, pd, searchpt);
23193     ori3 = orient3dfast(pc, pb, pd, searchpt);
23194     ori4 = orient3dfast(pa, pc, pd, searchpt);
23195     if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
23196     if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23197     if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23198     if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23199   } else { // if (loc == OUTSIDE) {
23200     // Do a brute force search for the point (with rounding).
23201     tetrahedrons->traversalinit();
23202     searchtet->tet = tetrahedrontraverse();
23203     while (searchtet->tet != nullptr) {
23204       pa = org(*searchtet);
23205       pb = dest(*searchtet);
23206       pc = apex(*searchtet);
23207       pd = oppo(*searchtet);
23208 
23209       vol = orient3dfast(pa, pb, pc, pd);
23210       if (vol < 0) {
23211         ori1 = orient3dfast(pa, pb, pc, searchpt);
23212         if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
23213         if (ori1 <= 0) {
23214           ori2 = orient3dfast(pb, pa, pd, searchpt);
23215           if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
23216           if (ori2 <= 0) {
23217             ori3 = orient3dfast(pc, pb, pd, searchpt);
23218             if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
23219             if (ori3 <= 0) {
23220               ori4 = orient3dfast(pa, pc, pd, searchpt);
23221               if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
23222               if (ori4 <= 0) {
23223                 // Found the tet. Return its location.
23224                 break;
23225               } // ori4
23226             } // ori3
23227           } // ori2
23228         } // ori1
23229       }
23230 
23231       searchtet->tet = tetrahedrontraverse();
23232     } // while (searchtet->tet != nullptr)
23233     nonregularcount++;  // Re-use this counter.
23234   }
23235 
23236   if (searchtet->tet != nullptr) {
23237     // Return the point location.
23238     if (ori1 == 0) { // on face [a,b,c]
23239       if (ori2 == 0) { // on edge [a,b].
23240         if (ori3 == 0) { // on vertex [b].
23241           assert(ori4 != 0);
23242           enextself(*searchtet); // [b,c,a,d]
23243           loc = ONVERTEX;
23244         } else {
23245           if (ori4 == 0) { // on vertex [a]
23246             loc =  ONVERTEX; // [a,b,c,d]
23247           } else {
23248             loc =  ONEDGE; // [a,b,c,d]
23249           }
23250         }
23251       } else { // ori2 != 0
23252         if (ori3 == 0) { // on edge [b,c]
23253           if (ori4 == 0) { // on vertex [c]
23254             eprevself(*searchtet); // [c,a,b,d]
23255             loc =  ONVERTEX;
23256           } else {
23257             enextself(*searchtet); // [b,c,a,d]
23258             loc =  ONEDGE;
23259           }
23260         } else { // ori3 != 0
23261           if (ori4 == 0) { // on edge [c,a]
23262             eprevself(*searchtet); // [c,a,b,d]
23263             loc =  ONEDGE;
23264           } else {
23265             loc =  ONFACE;
23266           }
23267         }
23268       }
23269     } else { // ori1 != 0
23270       if (ori2 == 0) { // on face [b,a,d]
23271         esymself(*searchtet); // [b,a,d,c]
23272         if (ori3 == 0) { // on edge [b,d]
23273           eprevself(*searchtet); // [d,b,a,c]
23274           if (ori4 == 0) { // on vertex [d]
23275             loc =  ONVERTEX;
23276           } else {
23277             loc =  ONEDGE;
23278           }
23279         } else { // ori3 != 0
23280           if (ori4 == 0) { // on edge [a,d]
23281             enextself(*searchtet); // [a,d,b,c]
23282             loc =  ONEDGE;
23283           } else {
23284             loc =  ONFACE;
23285           }
23286         }
23287       } else { // ori2 != 0
23288         if (ori3 == 0) { // on face [c,b,d]
23289           enextself(*searchtet);
23290           esymself(*searchtet);
23291           if (ori4 == 0) { // on edge [c,d]
23292             eprevself(*searchtet);
23293             loc =  ONEDGE;
23294           } else {
23295             loc =  ONFACE;
23296           }
23297         } else {
23298           if (ori4 == 0) { // on face [a,c,d]
23299             eprevself(*searchtet);
23300             esymself(*searchtet);
23301             loc =  ONFACE;
23302           } else { // inside tet [a,b,c,d]
23303             loc =  INTETRAHEDRON;
23304           } // ori4
23305         } // ori3
23306       } // ori2
23307     } // ori1
23308   } else {
23309     loc = OUTSIDE;
23310   }
23311 
23312   return (int) loc;
23313 }
23314 
23315 ///////////////////////////////////////////////////////////////////////////////
23316 //                                                                           //
23317 // getpointmeshsize()    Interpolate the mesh size at given point.           //
23318 //                                                                           //
23319 // 'iloc' indicates the location of the point w.r.t. 'searchtet'.  The size  //
23320 // is obtained by linear interpolation on the vertices of the tet.           //
23321 //                                                                           //
23322 ///////////////////////////////////////////////////////////////////////////////
23323 
getpointmeshsize(point searchpt,triface * searchtet,int iloc)23324 REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
23325 {
23326   point *pts, pa, pb, pc;
23327   REAL volume, vol[4], wei[4];
23328   REAL size;
23329   int i;
23330 
23331   size = 0;
23332 
23333   if (iloc == (int) INTETRAHEDRON) {
23334     pts = (point *) &(searchtet->tet[4]);
23335     assert(pts[3] != dummypoint);
23336     // Only do interpolation if all vertices have non-zero sizes.
23337     if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
23338         (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
23339       // P1 interpolation.
23340       volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
23341       vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
23342       vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
23343       vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
23344       vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
23345       for (i = 0; i < 4; i++) {
23346         wei[i] = fabs(vol[i] / volume);
23347         size += (wei[i] * pts[i][pointmtrindex]);
23348       }
23349     }
23350   } else if (iloc == (int) ONFACE) {
23351     pa = org(*searchtet);
23352     pb = dest(*searchtet);
23353     pc = apex(*searchtet);
23354     if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
23355         (pc[pointmtrindex] > 0)) {
23356       volume = triarea(pa, pb, pc);
23357       vol[0] = triarea(searchpt, pb, pc);
23358       vol[1] = triarea(pa, searchpt, pc);
23359       vol[2] = triarea(pa, pb, searchpt);
23360       size = (vol[0] / volume) * pa[pointmtrindex]
23361            + (vol[1] / volume) * pb[pointmtrindex]
23362            + (vol[2] / volume) * pc[pointmtrindex];
23363     }
23364   } else if (iloc == (int) ONEDGE) {
23365     pa = org(*searchtet);
23366     pb = dest(*searchtet);
23367     if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
23368       volume = distance(pa, pb);
23369       vol[0] = distance(searchpt, pb);
23370       vol[1] = distance(pa, searchpt);
23371       size = (vol[0] / volume) * pa[pointmtrindex]
23372            + (vol[1] / volume) * pb[pointmtrindex];
23373     }
23374   } else if (iloc == (int) ONVERTEX) {
23375     pa = org(*searchtet);
23376     if (pa[pointmtrindex] > 0) {
23377       size = pa[pointmtrindex];
23378     }
23379   }
23380 
23381   return size;
23382 }
23383 
23384 ///////////////////////////////////////////////////////////////////////////////
23385 //                                                                           //
23386 // interpolatemeshsize()    Interpolate the mesh size from a background mesh //
23387 //                          (source) to the current mesh (destination).      //
23388 //                                                                           //
23389 ///////////////////////////////////////////////////////////////////////////////
23390 
interpolatemeshsize()23391 void tetgenmesh::interpolatemeshsize()
23392 {
23393   triface searchtet;
23394   point ploop;
23395   REAL minval = 0.0, maxval = 0.0;
23396   int iloc;
23397   int count;
23398 
23399   if (!b->quiet) {
23400     printf("Interpolating mesh size ...\n");
23401   }
23402 
23403   long bak_nonregularcount = nonregularcount;
23404   nonregularcount = 0l; // Count the number of (slow) global searches.
23405   long baksmaples = bgm->samples;
23406   bgm->samples = 3l;
23407   count = 0; // Count the number of interpolated points.
23408 
23409   // Interpolate sizes for all points in the current mesh.
23410   points->traversalinit();
23411   ploop = pointtraverse();
23412   while (ploop != nullptr) {
23413     // Search a tet in bgm which containing this point.
23414     searchtet.tet = nullptr;
23415     iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
23416     if (iloc != (int) OUTSIDE) {
23417       // Interpolate the mesh size.
23418       ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
23419       setpoint2bgmtet(ploop, bgm->encode(searchtet));
23420       if (count == 0) {
23421         // This is the first interpolated point.
23422         minval = maxval = ploop[pointmtrindex];
23423       } else {
23424         if (ploop[pointmtrindex] < minval) {
23425           minval = ploop[pointmtrindex];
23426         }
23427         if (ploop[pointmtrindex] > maxval) {
23428           maxval = ploop[pointmtrindex];
23429         }
23430       }
23431       count++;
23432     } else {
23433       if (!b->quiet) {
23434         printf("Warnning:  Failed to locate point %d in source mesh.\n",
23435                pointmark(ploop));
23436       }
23437     }
23438     ploop = pointtraverse();
23439   }
23440 
23441   if (b->verbose) {
23442     printf("  Interoplated %d points.\n", count);
23443     if (nonregularcount > 0l) {
23444       printf("  Performed %ld brute-force searches.\n", nonregularcount);
23445     }
23446     printf("  Size rangle [%.17g, %.17g].\n", minval, maxval);
23447   }
23448 
23449   bgm->samples = baksmaples;
23450   nonregularcount = bak_nonregularcount;
23451 }
23452 
23453 ///////////////////////////////////////////////////////////////////////////////
23454 //                                                                           //
23455 // insertconstrainedpoints()    Insert a list of points into the mesh.       //
23456 //                                                                           //
23457 // Assumption:  The bounding box of the insert point set should be no larger //
23458 // than the bounding box of the mesh.  (Required by point sorting).          //
23459 //                                                                           //
23460 ///////////////////////////////////////////////////////////////////////////////
23461 
insertconstrainedpoints(point * insertarray,int arylen)23462 void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen)
23463 {
23464   triface searchtet, spintet;
23465   face splitsh;
23466   face splitseg;
23467   insertvertexflags ivf;
23468   flipconstraints fc;
23469   int randflag = 0;
23470   int t1ver;
23471   int i;
23472 
23473   if (b->verbose) {
23474     printf("  Inserting %d constrained points\n", arylen);
23475   }
23476 
23477   if (b->no_sort) { // -b/1 option.
23478     if (b->verbose) {
23479       printf("  Using the input order.\n");
23480     }
23481   } else {
23482     if (b->verbose) {
23483       printf("  Permuting vertices.\n");
23484     }
23485     point swappoint;
23486     int randindex;
23487     srand(arylen);
23488     for (i = 0; i < arylen; i++) {
23489       randindex = rand() % (i + 1);
23490       swappoint = insertarray[i];
23491       insertarray[i] = insertarray[randindex];
23492       insertarray[randindex] = swappoint;
23493     }
23494     if (b->brio_hilbert) { // -b1 option
23495       if (b->verbose) {
23496         printf("  Sorting vertices.\n");
23497       }
23498       hilbert_init(in->mesh_dim);
23499       int ngroup = 0;
23500       brio_multiscale_sort(insertarray, arylen, b->brio_threshold,
23501                            b->brio_ratio, &ngroup);
23502     } else { // -b0 option.
23503       randflag = 1;
23504     } // if (!b->brio_hilbert)
23505   } // if (!b->no_sort)
23506 
23507   long bak_nonregularcount = nonregularcount;
23508   nonregularcount = 0l;
23509   long baksmaples = samples;
23510   samples = 3l; // Use at least 3 samples. Updated in randomsample().
23511 
23512   long bak_seg_count = st_segref_count;
23513   long bak_fac_count = st_facref_count;
23514   long bak_vol_count = st_volref_count;
23515 
23516   // Initialize the insertion parameters.
23517   if (b->incrflip) { // -l option
23518     // Use incremental flip algorithm.
23519     ivf.bowywat = 0;
23520     ivf.lawson = 1;
23521     ivf.validflag = 0; // No need to validate the cavity.
23522     fc.enqflag = 2;
23523   } else {
23524     // Use Bowyer-Watson algorithm.
23525     ivf.bowywat = 1;
23526     ivf.lawson = 0;
23527     ivf.validflag = 1; // Validate the B-W cavity.
23528   }
23529   ivf.rejflag = 0;  // Do not check encroachment.
23530   if (b->metric) { // -m option.
23531     ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
23532   }
23533   ivf.chkencflag = 0;
23534   ivf.sloc = (int) INSTAR;
23535   ivf.sbowywat = 3;
23536   ivf.splitbdflag = 1;
23537   ivf.respectbdflag = 1;
23538   ivf.assignmeshsize = b->metric;
23539 
23540   // Insert the points.
23541   for (i = 0; i < arylen; i++) {
23542     // Find the location of the inserted point.
23543     // Do not use 'recenttet', since the mesh may be non-convex.
23544     searchtet.tet = nullptr;
23545     ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
23546 
23547     // Decide the right type for this point.
23548     setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
23549     splitsh.sh = nullptr;
23550     splitseg.sh = nullptr;
23551     if (ivf.iloc == (int) ONEDGE) {
23552       if (issubseg(searchtet)) {
23553         tsspivot1(searchtet, splitseg);
23554         setpointtype(insertarray[i], FREESEGVERTEX);
23555         //ivf.rejflag = 0;
23556       } else {
23557         // Check if it is a subface edge.
23558         spintet = searchtet;
23559         while (1) {
23560           if (issubface(spintet)) {
23561             tspivot(spintet, splitsh);
23562             setpointtype(insertarray[i], FREEFACETVERTEX);
23563             //ivf.rejflag |= 1;
23564             break;
23565           }
23566           fnextself(spintet);
23567           if (spintet.tet == searchtet.tet) break;
23568         }
23569       }
23570     } else if (ivf.iloc == (int) ONFACE) {
23571       if (issubface(searchtet)) {
23572         tspivot(searchtet, splitsh);
23573         setpointtype(insertarray[i], FREEFACETVERTEX);
23574         //ivf.rejflag |= 1;
23575       }
23576     }
23577 
23578     // Now insert the point.
23579     if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
23580       if (flipstack != nullptr) {
23581         // There are queued faces. Use flips to recover Delaunayness.
23582         lawsonflip3d(&fc);
23583         // There may be unflippable edges. Ignore them.
23584         unflipqueue->restart();
23585       }
23586       // Update the Steiner counters.
23587       if (pointtype(insertarray[i]) == FREESEGVERTEX) {
23588         st_segref_count++;
23589       } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
23590         st_facref_count++;
23591       } else {
23592         st_volref_count++;
23593       }
23594     } else {
23595       // Point is not inserted.
23596       if (ivf.iloc == (int) OUTSIDE) {
23597         if (!b->quiet) {
23598           printf("Warning:  Point #%d lies outside the domain. Ignored.\n",
23599                  pointmark(insertarray[i]) - in->numberofpoints);
23600         }
23601       } else if (ivf.iloc == (int) ONVERTEX) {
23602         if (!b->quiet) {
23603           printf("Warning:  Point #%d is coincident with Point #%d. Ignored.\n",
23604                  pointmark(insertarray[i]) - in->numberofpoints,
23605                  pointmark(org(searchtet)));
23606         }
23607       } else if (ivf.iloc == (int) NEARVERTEX) {
23608         if (!b->quiet) {
23609           printf("Warning:  Point #%d is too close to Point #%d. Rejected.\n",
23610                  pointmark(insertarray[i]) - in->numberofpoints,
23611                  pointmark(point2ppt(insertarray[i])));
23612         }
23613       } else if (ivf.iloc == (int) ENCVERTEX) {
23614         if (!b->quiet) {
23615           printf("Warning:  Point #%d encroaches upon Point #%d. Rejected.\n",
23616                  pointmark(insertarray[i]) - in->numberofpoints,
23617                  pointmark(point2ppt(insertarray[i])));
23618         }
23619       } else {
23620         if (!b->quiet) {
23621             printf("Warning:  Failed to insert Point #%d (%g,%g,%g).Ignored.\n",
23622                    i, insertarray[i][0], insertarray[i][1], insertarray[i][2]);
23623         }
23624       }
23625       //pointdealloc(insertarray[i]);
23626       setpointtype(insertarray[i], UNUSEDVERTEX);
23627       unuverts++;
23628     }
23629   } // i
23630 
23631   if (b->verbose) {
23632     printf("  Inserted %ld (%ld, %ld, %ld) vertices.\n",
23633            st_segref_count + st_facref_count + st_volref_count -
23634            (bak_seg_count + bak_fac_count + bak_vol_count),
23635            st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
23636            st_volref_count - bak_vol_count);
23637     if (nonregularcount > 0l) {
23638       printf("  Performed %ld brute-force searches.\n", nonregularcount);
23639     }
23640   }
23641 
23642   nonregularcount = bak_nonregularcount;
23643   samples = baksmaples;
23644 }
23645 
insertconstrainedpoints(tetgenio * addio)23646 void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
23647 {
23648   point *insertarray, newpt;
23649   REAL x, y, z, w;
23650   int index, attribindex, mtrindex;
23651   int arylen, i, j;
23652 
23653   if (!b->quiet) {
23654     printf("Inserting constrained points ...\n");
23655   }
23656 
23657   insertarray = new point[addio->numberofpoints];
23658   arylen = 0;
23659   index = 0;
23660   attribindex = 0;
23661   mtrindex = 0;
23662 
23663   for (i = 0; i < addio->numberofpoints; i++) {
23664     x = addio->pointlist[index++];
23665     y = addio->pointlist[index++];
23666     z = addio->pointlist[index++];
23667     // Test if this point lies inside the bounding box.
23668     if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
23669         (z < zmin) || (z > zmax)) {
23670       if (b->verbose) {
23671         printf("Warning:  Point #%d lies outside the bounding box. Ignored\n",
23672                i + in->firstnumber);
23673       }
23674       continue;
23675     }
23676     makepoint(&newpt, UNUSEDVERTEX);
23677     newpt[0] = x;
23678     newpt[1] = y;
23679     newpt[2] = z;
23680     // Read the point attributes. (Including point weights.)
23681     for (j = 0; j < addio->numberofpointattributes; j++) {
23682       newpt[3 + j] = addio->pointattributelist[attribindex++];
23683     }
23684     // Read the point metric tensor.
23685     for (j = 0; j < addio->numberofpointmtrs; j++) {
23686       newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
23687     }
23688     if (b->weighted) { // -w option
23689       if (addio->numberofpointattributes > 0) {
23690         // The first point attribute is its weight.
23691         w = newpt[3];
23692       } else {
23693         // No given weight available. Default choose the maximum
23694         //   absolute value among its coordinates.
23695         w = fabs(x);
23696         if (w < fabs(y)) w = fabs(y);
23697         if (w < fabs(z)) w = fabs(z);
23698       }
23699       if (b->weighted_param == 0) {
23700         newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
23701       } else { // -w1 option
23702         newpt[3] = w;  // Regular tetrahedralization.
23703       }
23704     }
23705     insertarray[arylen] = newpt;
23706     arylen++;
23707   } // i
23708 
23709   // Insert the points.
23710   insertconstrainedpoints(insertarray, arylen);
23711 
23712   delete [] insertarray;
23713 }
23714 
23715 ////                                                                       ////
23716 ////                                                                       ////
23717 //// reconstruct_cxx //////////////////////////////////////////////////////////
23718 
23719 //// refine_cxx ///////////////////////////////////////////////////////////////
23720 ////                                                                       ////
23721 ////                                                                       ////
23722 
23723 ///////////////////////////////////////////////////////////////////////////////
23724 //                                                                           //
23725 // marksharpsegments()    Mark sharp segments.                               //
23726 //                                                                           //
23727 // A segment is SHARP if there are two facets intersecting at it with an     //
23728 // internal dihedral angle (*) less than an angle \theta.                    //
23729 //                                                                           //
23730 // A theoretical value of \theta is arccos(1/3) \approx 70.54 degree.  It is //
23731 // possible to relax it in practice. Here we choose \theta = 65 degree.      //
23732 //                                                                           //
23733 // The minimum dihedral angle between facets (minfacetdihed) is calulcated.  //
23734 //                                                                           //
23735 ///////////////////////////////////////////////////////////////////////////////
23736 
marksharpsegments()23737 void tetgenmesh::marksharpsegments()
23738 {
23739   triface starttet, spintet, adjtet;
23740   face startsh, spinsh, neighsh;
23741   face segloop, nextseg, prevseg;
23742   point eorg, edest;
23743   REAL ang, smallang;
23744   bool issharp;
23745   int interiorflag;
23746   int t1ver;
23747   int sharpcount;
23748 
23749   // For storing extremely small dihedral angle.
23750   face *parysh;
23751   REAL exsmallang;
23752   int exsharpcount;
23753 
23754   if (b->verbose > 0) {
23755     printf("  Marking sharp segments.\n");
23756   }
23757 
23758   minfacetdihed = PI;
23759   smallang = 65.0 * PI / 180.0; // 65 degree.
23760   exsmallang = 5.0 * PI / 180.0; // 5 degree.
23761   sharpcount = exsharpcount = 0;
23762 
23763   // A segment s may have been split into many subsegments. Operate the one
23764   //   which contains the origin of s. Then mark the rest of subsegments.
23765   subsegs->traversalinit();
23766   segloop.sh = shellfacetraverse(subsegs);
23767   while (segloop.sh != (shellface *) nullptr) {
23768     segloop.shver = 0;
23769     senext2(segloop, prevseg);
23770     spivotself(prevseg);
23771     if (prevseg.sh == nullptr) {
23772       // Operate on this seg s.
23773       issharp = false;
23774       spivot(segloop, startsh);
23775       if (startsh.sh != nullptr) {
23776         eorg = sorg(segloop);
23777         edest = sdest(segloop);
23778         if (sorg(startsh) != eorg) sesymself(startsh);
23779         stpivot(startsh, starttet);
23780         if (starttet.tet != nullptr) {
23781           spinsh = startsh;
23782           spintet = starttet;
23783           while (1) {
23784             fnextself(spintet);
23785             if (issubface(spintet)) {
23786               tspivot(spintet, neighsh);
23787               if (neighsh.sh != spinsh.sh) {
23788                 // Only do test when the adjacent tet lies in the interior.
23789                 interiorflag = 0;
23790                 stpivot(spinsh, adjtet);
23791                 if (!ishulltet(adjtet)) {
23792                   if (b->convex) { // -c option.
23793                     if (elemattribute(adjtet.tet, numelemattrib - 1) != -1.0) {
23794                       interiorflag = 1;
23795                     }
23796                   } else {
23797                     interiorflag = 1;
23798                   }
23799                 }
23800                 if (interiorflag) {
23801                   ang = facedihedral(eorg,edest,sapex(spinsh),sapex(neighsh));
23802                   // Only do check if a sharp angle has not been found.
23803                   if (!issharp) issharp = (ang < smallang);
23804                   // Remember the smallest facet dihedral angle.
23805                   minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang;
23806                   if (ang < exsmallang) {
23807                     // It's an extremely small dihedral angle.
23808                     // Mark the two facets.
23809                     // To avoid too many Steiner points, do not refine them.
23810                     if (shelltype(spinsh) != SHARP) {
23811                       setshelltype(spinsh, SHARP);
23812                       cavesegshlist->newindex((void **) &parysh);
23813                       *parysh = spinsh;
23814                     }
23815                     if (shelltype(neighsh) != SHARP) {
23816                       setshelltype(neighsh, SHARP);
23817                       cavesegshlist->newindex((void **) &parysh);
23818                       *parysh = neighsh;
23819                     }
23820                     exsharpcount++;
23821                   }
23822                 } // if (interiorflag)
23823                 spinsh = neighsh;
23824                 if (sorg(spinsh) != eorg) sesymself(spinsh);
23825               } // if (neighsh.sh != spinsh.sh)
23826             }
23827             if (spintet.tet == starttet.tet) break;
23828           } // while (1)
23829         } // if (starttet.tet != nullptr)
23830       } // if (startsh.sh != nullptr)
23831       if (issharp) {
23832         if (b->verbose > 2) {
23833           printf("      Mark a sharp segment (%d, %d).\n",
23834                  pointmark(eorg), pointmark(edest));
23835         }
23836         setshelltype(segloop, SHARP);
23837         // The endpoint of this segment is acute.
23838         if (pointtype(eorg) == RIDGEVERTEX) {
23839           setpointtype(eorg, ACUTEVERTEX);
23840         } else {
23841           assert(pointtype(eorg) == ACUTEVERTEX); // SELF_CHECK
23842         }
23843         // Set the type for all subsegments at forwards.
23844         edest = sdest(segloop);
23845         senext(segloop, nextseg);
23846         spivotself(nextseg);
23847         while (nextseg.sh != nullptr) {
23848           setshelltype(nextseg, SHARP);
23849           // Adjust the direction of nextseg.
23850           nextseg.shver = 0;
23851           if (sorg(nextseg) != edest) {
23852             sesymself(nextseg);
23853           }
23854           assert(sorg(nextseg) == edest);
23855           edest = sdest(nextseg);
23856           // Go the next connected subsegment at edest.
23857           senextself(nextseg);
23858           spivotself(nextseg);
23859         }
23860         // The endpoint of this segment is acute.
23861         if (pointtype(edest) == RIDGEVERTEX) {
23862           setpointtype(edest, ACUTEVERTEX);
23863         } else {
23864           assert(pointtype(edest) == ACUTEVERTEX); // SELF_CHECK
23865         }
23866         sharpcount++;
23867       } // if (issharp)
23868     } // if (prevseg.sh == nullptr)
23869     segloop.sh = shellfacetraverse(subsegs);
23870   }
23871 
23872   // Mark all facets at extremely small dihedral angles.
23873   if (cavesegshlist->objects > 0) {
23874     face *parysh1;
23875     int i, j, k;
23876 
23877     for (i = 0; i < cavesegshlist->objects; i++) {
23878       parysh = (face *) fastlookup(cavesegshlist, i);
23879       caveshlist->newindex((void **) &parysh1);
23880       *parysh1 = *parysh;
23881       for (j = 0; j < caveshlist->objects; j++) {
23882         parysh1 = (face *) fastlookup(caveshlist, j);
23883         spinsh = *parysh1;
23884         for (k = 0; k < 3; k++) {
23885           sspivot(spinsh, nextseg);
23886           if (nextseg.sh == nullptr) {
23887             spivot(spinsh, neighsh);
23888             if (shelltype(neighsh) != SHARP) {
23889               setshelltype(neighsh, SHARP);
23890               caveshlist->newindex((void **) &parysh1);
23891               *parysh1 = neighsh;
23892             }
23893           }
23894           senextself(spinsh);
23895         } // k
23896       } // j
23897       caveshlist->restart();
23898     } // i
23899     cavesegshlist->restart();
23900   } // if (cavesegshlist->objects > 0)
23901 
23902   if (b->verbose) {
23903     if (sharpcount > 0) {
23904       printf("  Found %d (%d) sharp segments.\n", sharpcount, exsharpcount);
23905     }
23906     printf("  Minimum fac-fac angle = %g.\n", minfacetdihed / PI * 180.0);
23907   }
23908 }
23909 
23910 ///////////////////////////////////////////////////////////////////////////////
23911 //                                                                           //
23912 // decidefeaturepointsizes()    Calculate sizes for all feature points.      //
23913 //                                                                           //
23914 // A feature point is either an acute vertex or a Steiner point on a sharp   //
23915 // segment.  Each feature point p will be protected by a ball whose radius   //
23916 // is called its "feature size".                                             //
23917 //                                                                           //
23918 // NOTE: we should have already marked all features points in the two func-  //
23919 // tions: markacutevertices() and marksharpsegments().  Each feature point   //
23920 // has the type ACUTEVERTEX or FREESEGVERTEX.                                //
23921 //                                                                           //
23922 // The feature size of a vertex is the minimum of the following sizes:       //
23923 //   (0) the (approximated) local feature size (the distance to the second   //
23924 //       nearest boundary) of the vertex;
23925 //   (1) the value specified in .mtr file (-m option);                       //
23926 //   (2) the cubic root of a fixed maximal volume constraint ('-a__');       //
23927 //   (3) the cubic root of a maximal volume constraint in a region ('-a');   //
23928 //   (4) the square root of a maximal area constraint in a .var file;        //
23929 //   (5) a maximal length constraint in a .var file;                         //
23930 //                                                                           //
23931 // If 'b->nobisect' ('-Y' option) is set, every input vertex has a size. It  //
23932 // is used to prevent creating too close Steiner points.                     //
23933 //                                                                           //
23934 // The feature size of a Steiner point is linearly interpolated from its adj-//
23935 // acent vertices which belong to the "carrier" (the boundary of the lowrest //
23936 // dimension) of this Steiner point.  For example, a Steiner point on a seg- //
23937 // ment gets its size from the two endpoints of the segment.                 //
23938 //                                                                           //
23939 ///////////////////////////////////////////////////////////////////////////////
23940 
decidefeaturepointsizes()23941 void tetgenmesh::decidefeaturepointsizes()
23942 {
23943   arraypool *tetlist, *verlist;
23944   triface starttet, *parytet;
23945   face checksh, parentsh, shloop;
23946   face checkseg, prevseg, nextseg, testseg;
23947   point ploop, adjpt, e1, e2, *parypt;
23948   REAL lfs_0, lfs_1, lfs_2;
23949   REAL len, vol, maxlen = 0.0, varlen;
23950   REAL ang, a, a1, a2, a3, prjpt[3], n[3];
23951   int featureflag, featurecount;
23952   int i, j;
23953 
23954   if (b->verbose > 0) {
23955     printf("  Deciding feature-point sizes.\n");
23956   }
23957 
23958   // Initialize working lists.
23959   tetlist = cavetetlist;
23960   verlist = cavetetvertlist;
23961 
23962   if (b->fixedvolume) {
23963     // A fixed volume constraint is imposed. This gives an upper bound of
23964     //   the maximal radius of the protect ball of a vertex.
23965     maxlen = pow(6.0 * b->maxvolume, 1.0 / 3.0);
23966   }
23967 
23968   // First, assign a size of p if p is a feature point or an input point and
23969   //   the -Y option is used.
23970   featurecount = 0;
23971   points->traversalinit();
23972   ploop = pointtraverse();
23973   while (ploop != (point) nullptr) {
23974     // Check if it is a feature point.
23975     featureflag = 0;
23976     // Only calculate the size if it has a size zero.
23977     // The point may already has a positive size (-m option).
23978     if (ploop[pointmtrindex] == 0) {
23979       if (pointtype(ploop) == ACUTEVERTEX) {
23980         featureflag = 1;
23981       } else {
23982         if (b->nobisect) { // '-Y' option
23983           if ((pointtype(ploop) == RIDGEVERTEX) ||
23984               (pointtype(ploop) == FACETVERTEX) ||
23985               (pointtype(ploop) == VOLVERTEX)) {
23986             featureflag = 1;  // It is an input vertex.
23987           }
23988         }
23989       }
23990     }
23991     if (featureflag) {
23992       // Form star(p).
23993       getvertexstar(1, ploop, tetlist, verlist, nullptr);
23994       // Calculate lfs_0(p), i.e., the smallest distance from p to a vertex.
23995       // We approximate it by taking the distance of p to its nearest
23996       //   vertex in Link(p).
23997       lfs_0 = longest;
23998       for (i = 0; i < verlist->objects; i++) {
23999         parypt = (point *) fastlookup(verlist, i);
24000         adjpt = * parypt;
24001         if (adjpt == dummypoint) {
24002           continue; // Skip a dummypoint.
24003         }
24004         if (pointtype(adjpt) == FREESEGVERTEX) {
24005           // A Steiner point. Get the subsegment.
24006           sdecode(point2sh(adjpt), checkseg);
24007           assert(checkseg.sh != nullptr);
24008           checkseg.shver = 0;
24009           if (sdest(checkseg) != adjpt) sesymself(checkseg);
24010           assert(sdest(checkseg) == adjpt);
24011           // It is possible that the original segment of 'adjpt' does not
24012           //   have 'ploop' as an endpoint.
24013           if (sorg(checkseg) == ploop) {
24014             // Find the other end point of the original segment.
24015             nextseg = checkseg;
24016             while (1) {
24017               senext(nextseg, testseg);
24018               spivotself(testseg);
24019               if (testseg.sh == nullptr) break;
24020               // Go to the next subseg.
24021               nextseg = testseg;
24022               // Adjust the direction of the nextseg.
24023               nextseg.shver = 0;
24024               if (sorg(nextseg) != adjpt) sesymself(nextseg);
24025               assert(sorg(nextseg) == adjpt);
24026               adjpt = sdest(nextseg);
24027             }
24028           }
24029             } else if (pointtype(adjpt) == FREEFACETVERTEX) {
24030           // Ignore a Steiner point on facet.
24031           continue;
24032         } else if (pointtype(adjpt) == FREEVOLVERTEX) {
24033           // Ignore a Steiner point in volume.
24034           continue;
24035         }
24036         len = distance(ploop, adjpt);
24037         if (lfs_0 > len) lfs_0 = len;
24038       } // i
24039       assert(lfs_0 < longest); // SELF_CHECK
24040       ploop[pointmtrindex] = lfs_0;
24041       // Calculate lfs_1(p), i.e., the smallest distance from p to a segment.
24042       //   We approximate it by restricting the segments in Link(p).
24043       lfs_1 = lfs_0;
24044       for (i = 0; i < tetlist->objects; i++) {
24045         parytet = (triface *) fastlookup(tetlist, i);
24046         for (j = 0; j < 3; j++) {
24047           if (issubseg(*parytet)) {
24048             tsspivot1(*parytet, checkseg);
24049             e1 = sorg(checkseg);
24050             e2 = sdest(checkseg);
24051             // Only do calculation if the projeciton of 'p' lies inside the
24052             //   segment [e1, e2].
24053             ang = interiorangle(ploop, e1, e2, nullptr);
24054             ang *= 2.0;
24055             if (ang > PI) {
24056               len = shortdistance(ploop, e1, e2);
24057               if (lfs_1 > len) {
24058                 lfs_1 = len;
24059               }
24060             }
24061           }
24062           enextself(*parytet);
24063         } // j
24064       } // i
24065       if (ploop[pointmtrindex] > lfs_1) {
24066         ploop[pointmtrindex] = lfs_1;
24067       }
24068       // Calculate lfs_2(p), i.e., the smallest distance from p to a facet.
24069       //   We approximate it by restricting the facets in Link(p).
24070       lfs_2 = lfs_0;
24071       for (i = 0; i < tetlist->objects; i++) {
24072         parytet = (triface *) fastlookup(tetlist, i);
24073         if (issubface(*parytet)) {
24074           tspivot(*parytet, checksh);
24075           adjpt = sorg(checksh);
24076           e1 = sdest(checksh);
24077           e2 = sapex(checksh);
24078           // Only do calculation if the projeciton of 'p' lies inside the
24079           //   subface [adjpt, e1, e2].
24080           projpt2face(ploop, adjpt, e1, e2, prjpt);
24081           facenormal(adjpt, e1, e2, n, 1, nullptr);
24082           a = sqrt(dot(n, n)); // area of [adjpt, e1, e2].
24083           if (a > 0) {
24084             facenormal(adjpt, e1, prjpt, n, 1, nullptr);
24085             a1 = sqrt(dot(n, n));
24086             facenormal(e1, e2, prjpt, n, 1, nullptr);
24087             a2 = sqrt(dot(n, n));
24088             facenormal(e2, adjpt, prjpt, n, 1, nullptr);
24089             a3 = sqrt(dot(n, n));
24090             if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
24091               len = distance(ploop, prjpt);
24092               if (lfs_2 > len) {
24093                 lfs_2 = len;
24094               }
24095             }
24096           } else {
24097             assert(0); // a degenerate triangle.
24098           } // if (a > 0)
24099         }
24100       }
24101       if (ploop[pointmtrindex] > lfs_2) {
24102         ploop[pointmtrindex] = lfs_2;
24103       }
24104       if (b->fixedvolume) {
24105         // A fixed volume constraint is imposed. Adjust H(p) <= maxlen.
24106         if (ploop[pointmtrindex] > maxlen) {
24107           ploop[pointmtrindex] = maxlen;
24108         }
24109       }
24110       if (b->varvolume) {
24111         // Variant volume constraints are imposed. Adjust H(p) <= varlen.
24112         for (i = 0; i < tetlist->objects; i++) {
24113           parytet = (triface *) fastlookup(tetlist, i);
24114           starttet = *parytet;
24115           vol = volumebound(starttet.tet);
24116           if (vol > 0.0) {
24117             varlen = pow(6 * vol, 1.0 / 3.0);
24118             if (ploop[pointmtrindex] > varlen) {
24119               ploop[pointmtrindex] = varlen;
24120             }
24121           }
24122         }
24123       }
24124       // The size is calculated.
24125       assert(ploop[pointmtrindex] > 0); // SELF_CHECK
24126       // Clear working lists.
24127       tetlist->restart();
24128       verlist->restart();
24129       featurecount++;
24130     } // if (featureflag)
24131     ploop = pointtraverse();
24132   }
24133 
24134   if (b->verbose) {
24135     printf("  %d feature points.\n", featurecount);
24136   }
24137 
24138   // Second only assign sizes for all Steiner points which were inserted on
24139   //   sharp segments. The sizes are interpolated from the endpoints of
24140   //   the segments.
24141   featurecount = 0;
24142   points->traversalinit();
24143   ploop = pointtraverse();
24144   while (ploop != (point) nullptr) {
24145     if (ploop[pointmtrindex] == 0.0) {
24146       if (pointtype(ploop) == FREESEGVERTEX) {
24147         // A Steiner point on segment.
24148         featureflag = 0;
24149         sdecode(point2sh(ploop), checkseg);
24150         assert(checkseg.sh != nullptr);
24151         checkseg.shver = 0;
24152         e1 = farsorg(checkseg);  // The origin of this seg.
24153         e2 = farsdest(checkseg); // The dest of this seg.
24154         if (b->nobisect) { // '-Y' option.
24155           featureflag = 1;
24156         } else {
24157           if ((e1[pointmtrindex] > 0) && (e2[pointmtrindex] > 0)) {
24158             featureflag = 1;
24159           }
24160         }
24161         if (featureflag) {
24162           len = distance(e1, e2);
24163           lfs_0 = distance(e1, ploop); // Re-use lfs_0.
24164           ploop[pointmtrindex] = e1[pointmtrindex]
24165             + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]);
24166           featurecount++;
24167         } // if (featureflag)
24168       }
24169     } // if (ploop[pointmtrindex] == 0.0)
24170     ploop = pointtraverse();
24171   }
24172 
24173   if (b->verbose && (featurecount > 0)) {
24174     printf("  %d Steiner feature points.\n", featurecount);
24175   }
24176 
24177   if (checkconstraints) {
24178     // A .var file exists. Adjust feature sizes. And make sure that every
24179     //   corner of a constraining facet get a size.
24180     if (in->facetconstraintlist) {
24181       // Have facet area constrains.
24182       subfaces->traversalinit();
24183       shloop.sh = shellfacetraverse(subfaces);
24184       while (shloop.sh != (shellface *) nullptr) {
24185         varlen = areabound(shloop);
24186         if (varlen > 0.0) {
24187           // Check if the three corners are feature points.
24188           varlen = sqrt(varlen);
24189           for (j = 0; j < 3; j++) {
24190             ploop = (point) shloop.sh[3 + j];
24191             if (ploop[pointmtrindex] > 0) {
24192               if (ploop[pointmtrindex] > varlen) {
24193                 ploop[pointmtrindex] = varlen;
24194               }
24195             } else {
24196               // This corner has no size yet. Set it.
24197               ploop[pointmtrindex] = varlen;
24198             }
24199           } // j
24200         }
24201         shloop.sh = shellfacetraverse(subfaces);
24202       }
24203     }
24204     if (in->segmentconstraintlist) {
24205       // Have facet area constrains.
24206       subsegs->traversalinit();
24207       shloop.sh = shellfacetraverse(subsegs);
24208       while (shloop.sh != (shellface *) nullptr) {
24209         varlen = areabound(shloop);
24210         if (varlen > 0.0) {
24211           // Check if the two endpoints are feature points.
24212           for (j = 0; j < 2; j++) {
24213             ploop = (point) shloop.sh[3 + j];
24214             if (ploop[pointmtrindex] > 0.0) {
24215               if (ploop[pointmtrindex] > varlen) {
24216                 ploop[pointmtrindex] = varlen;
24217               }
24218             } else {
24219               ploop[pointmtrindex] = varlen;
24220             }
24221           } // j
24222         }
24223         shloop.sh = shellfacetraverse(subsegs);
24224       }
24225     }
24226   } // if (checkconstraints)
24227 }
24228 
24229 ///////////////////////////////////////////////////////////////////////////////
24230 //                                                                           //
24231 // checkseg4encroach()    Check if an edge is encroached upon by a point.    //
24232 //                                                                           //
24233 ///////////////////////////////////////////////////////////////////////////////
24234 
checkseg4encroach(point pa,point pb,point checkpt)24235 int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
24236 {
24237   // Check if the point lies inside the diametrical sphere of this seg.
24238   REAL v1[3], v2[3];
24239 
24240   v1[0] = pa[0] - checkpt[0];
24241   v1[1] = pa[1] - checkpt[1];
24242   v1[2] = pa[2] - checkpt[2];
24243   v2[0] = pb[0] - checkpt[0];
24244   v2[1] = pb[1] - checkpt[1];
24245   v2[2] = pb[2] - checkpt[2];
24246 
24247   if (dot(v1, v2) < 0) {
24248     // Inside.
24249     if (b->metric || b->nobisect) { // -m or -Y option.
24250       if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
24251         // The projection of 'checkpt' lies inside the segment [a,b].
24252         REAL prjpt[3], u, v, t;
24253         projpt2edge(checkpt, pa, pb, prjpt);
24254         // Interoplate the mesh size at the location 'prjpt'.
24255         u = distance(pa, pb);
24256         v = distance(pa, prjpt);
24257         t = v / u;
24258         // 'u' is the mesh size at 'prjpt'
24259         u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
24260         v = distance(checkpt, prjpt);
24261         if (v < u) {
24262           return 1; // Encroached prot-ball!
24263         }
24264       } else {
24265         return 1; // NO protecting ball. Encroached.
24266       }
24267     } else {
24268       return 1; // Inside! Encroached.
24269     }
24270   }
24271 
24272   return 0;
24273 }
24274 
24275 ///////////////////////////////////////////////////////////////////////////////
24276 //                                                                           //
24277 // checkseg4split()    Check if we need to split a segment.                  //
24278 //                                                                           //
24279 // A segment needs to be split if it is in the following case:               //
24280 //  (1) It is encroached by an existing vertex.                              //
24281 //  (2) It has bad quality (too long).                                       //
24282 //  (3) Its length is larger than the mesh sizes at its endpoints.           //
24283 //                                                                           //
24284 // Return 1 if it needs to be split, otherwise, return 0.  'pencpt' returns  //
24285 // an encroaching point if there exists. 'qflag' returns '1' if the segment  //
24286 // has a length larger than the desired edge length.                         //
24287 //                                                                           //
24288 ///////////////////////////////////////////////////////////////////////////////
24289 
checkseg4split(face * chkseg,point & encpt,int & qflag)24290 int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
24291 {
24292   REAL ccent[3], len, r;
24293   int i;
24294 
24295   point forg = sorg(*chkseg);
24296   point fdest = sdest(*chkseg);
24297 
24298   // Initialize the return values.
24299   encpt = nullptr;
24300   qflag = 0;
24301 
24302   len = distance(forg, fdest);
24303   r = 0.5 * len;
24304   for (i = 0; i < 3; i++) {
24305     ccent[i] = 0.5 * (forg[i] + fdest[i]);
24306   }
24307 
24308   // First check its quality.
24309   if (checkconstraints && (areabound(*chkseg) > 0.0)) {
24310     if (len > areabound(*chkseg)) {
24311       qflag = 1;
24312       return 1;
24313     }
24314   }
24315 
24316   if (b->fixedvolume) {
24317     if ((len * len * len) > b->maxvolume) {
24318       qflag = 1;
24319       return 1;
24320     }
24321   }
24322 
24323   if (b->metric) { // -m option. Check mesh size.
24324     // Check if the ccent lies outside one of the prot.balls at vertices.
24325     if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
24326         ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
24327       qflag = 1; // Enforce mesh size.
24328       return 1;
24329     }
24330   }
24331 
24332 
24333   // Second check if it is encroached.
24334   triface searchtet, spintet;
24335   point eapex;
24336   REAL d, diff;
24337   int t1ver;
24338 
24339   sstpivot1(*chkseg, searchtet);
24340   spintet = searchtet;
24341   while (1) {
24342     eapex = apex(spintet);
24343     if (eapex != dummypoint) {
24344       d = distance(ccent, eapex);
24345       diff = d - r;
24346       if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
24347       if (diff < 0) {
24348         // This segment is encroached by eapex.
24349         encpt = eapex;
24350         break;
24351       }
24352     }
24353     fnextself(spintet);
24354     if (spintet.tet == searchtet.tet) break;
24355   } // while (1)
24356 
24357   if (encpt != nullptr) {
24358     return 1;
24359   }
24360 
24361   return 0; // No need to split it.
24362 }
24363 
24364 ///////////////////////////////////////////////////////////////////////////////
24365 //                                                                           //
24366 // splitsegment()    Split a segment.                                        //
24367 //                                                                           //
24368 // The segment 'splitseg' is intended to be split. It will be split if it    //
24369 // is in one of the following cases:                                         //
24370 //   (1) It is encroached by an existing vertex 'encpt != nullptr'; or          //
24371 //   (2) It is in bad quality 'qflag == 1'; or                               //
24372 //   (3) Its length is larger than the mesh sizes at its endpoints.          //
24373 //                                                                           //
24374 ///////////////////////////////////////////////////////////////////////////////
24375 
splitsegment(face * splitseg,point encpt,int qflag,int chkencflag)24376 int tetgenmesh::splitsegment(face *splitseg, point encpt, int qflag,
24377                              int chkencflag)
24378 {
24379   point pa = sorg(*splitseg);
24380   point pb = sdest(*splitseg);
24381 
24382 
24383   if (qflag == 0) {
24384     // Quickly check if we CAN split this segment.
24385     //if (encpt == nullptr) {
24386       // Do not split this segment if the length is smaller than the mesh
24387       //   size at one of its endpoints.
24388       REAL len = distance(pa, pb);
24389       if ((len < pa[pointmtrindex]) || (len < pb[pointmtrindex])) {
24390         return 0;
24391       }
24392     //}
24393   }
24394 
24395   if (b->nobisect) { // With -Y option.
24396     // Only split this segment if it is allowed to be split.
24397     if (checkconstraints) {
24398       // Check if it has a non-zero length bound.
24399       if (areabound(*splitseg) == 0) {
24400         // It is not allowed.  However, if all facets containing this seg
24401         //   are allowed to be split, we still split it.
24402         face parentsh, spinsh;
24403         //splitseg.shver = 0;
24404         spivot(*splitseg, parentsh);
24405         if (parentsh.sh == nullptr) {
24406           return 0; // A dangling segment. Do not split it.
24407         }
24408         spinsh = parentsh;
24409         while (1) {
24410           if (areabound(spinsh) == 0) break;
24411           spivotself(spinsh);
24412           if (spinsh.sh == parentsh.sh) break;
24413         }
24414         if (areabound(spinsh) == 0) {
24415           // Not all facets at this seg are allowed to be split.
24416           return 0;  // Do not split it.
24417         }
24418       }
24419     } else {
24420       return 0; // Do not split this segment.
24421     }
24422   } // if (b->nobisect)
24423 
24424   triface searchtet;
24425   face searchsh;
24426   point newpt;
24427   insertvertexflags ivf;
24428 
24429   makepoint(&newpt, FREESEGVERTEX);
24430   getsteinerptonsegment(splitseg, encpt, newpt);
24431 
24432   // Split the segment by the Bowyer-Watson algorithm.
24433   sstpivot1(*splitseg, searchtet);
24434   ivf.iloc = (int) ONEDGE;
24435   // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24436   ivf.bowywat = 3;
24437   ivf.validflag = 1; // Validate the B-W cavity.
24438   ivf.lawson = 2; // Do flips to recover Delaunayness.
24439   ivf.rejflag = 0;     // Do not check encroachment of new segments/facets.
24440   if ((encpt == nullptr) && (qflag == 0)) {
24441     ivf.rejflag |= 4;  // Do check encroachment of protecting balls.
24442   }
24443   ivf.chkencflag = chkencflag;
24444   ivf.sloc = (int) INSTAR; // ivf.iloc;
24445   ivf.sbowywat = 3; // ivf.bowywat;  // Surface mesh options.
24446   ivf.splitbdflag = 1;
24447   ivf.respectbdflag = 1;
24448   ivf.assignmeshsize = 1;
24449 
24450 
24451   if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
24452     st_segref_count++;
24453     if (steinerleft > 0) steinerleft--;
24454     if (flipstack != nullptr) {
24455       flipconstraints fc;
24456       fc.chkencflag = chkencflag;
24457       fc.enqflag = 2;
24458       lawsonflip3d(&fc);
24459       unflipqueue->restart();
24460     }
24461     return 1;
24462   } else {
24463     // Point is not inserted.
24464     pointdealloc(newpt);
24465     return 0;
24466   }
24467 }
24468 
24469 ///////////////////////////////////////////////////////////////////////////////
24470 //                                                                           //
24471 // repairencsegs()    Repair encroached (sub) segments.                      //
24472 //                                                                           //
24473 ///////////////////////////////////////////////////////////////////////////////
24474 
repairencsegs(int chkencflag)24475 void tetgenmesh::repairencsegs(int chkencflag)
24476 {
24477   face *bface;
24478   point encpt = nullptr;
24479   int qflag = 0;
24480 
24481   // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
24482   //   if an unlimited number of Steiner points is allowed.
24483   while ((badsubsegs->items > 0) && (steinerleft != 0)) {
24484     badsubsegs->traversalinit();
24485     bface = (face *) badsubsegs->traverse();
24486     while ((bface != nullptr) && (steinerleft != 0)) {
24487       // Skip a deleleted element.
24488       if (bface->shver >= 0) {
24489         // A queued segment may have been deleted (split).
24490         if ((bface->sh != nullptr) && (bface->sh[3] != nullptr)) {
24491           // A queued segment may have been processed.
24492           if (smarktest2ed(*bface)) {
24493             sunmarktest2(*bface);
24494             if (checkseg4split(bface, encpt, qflag)) {
24495               splitsegment(bface, encpt, qflag, chkencflag);
24496             }
24497           }
24498         }
24499         // Remove this entry from list.
24500         bface->shver = -1; // Signal it as a deleted element.
24501         badsubsegs->dealloc((void *) bface);
24502       }
24503       bface = (face *) badsubsegs->traverse();
24504     }
24505   }
24506 
24507   if (badsubsegs->items > 0) {
24508     if (steinerleft == 0) {
24509       if (b->verbose) {
24510         printf("The desired number of Steiner points is reached.\n");
24511       }
24512     } else {
24513       assert(0); // Unknown case.
24514     }
24515     badsubsegs->traversalinit();
24516     bface = (face *) badsubsegs->traverse();
24517     while (bface  != nullptr) {
24518       // Skip a deleleted element.
24519       if (bface->shver >= 0) {
24520         if ((bface->sh != nullptr) && (bface->sh[3] != nullptr)) {
24521           if (smarktest2ed(*bface)) {
24522             sunmarktest2(*bface);
24523           }
24524         }
24525       }
24526       bface = (face *) badsubsegs->traverse();
24527     }
24528     badsubsegs->restart();
24529   }
24530 }
24531 
24532 ///////////////////////////////////////////////////////////////////////////////
24533 //                                                                           //
24534 // enqueuesubface()    Queue a subface or a subsegment for encroachment chk. //
24535 //                                                                           //
24536 ///////////////////////////////////////////////////////////////////////////////
24537 
enqueuesubface(memorypool * pool,face * chkface)24538 void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
24539 {
24540   if (!smarktest2ed(*chkface)) {
24541     smarktest2(*chkface); // Only queue it once.
24542     face *queface = (face *) pool->alloc();
24543     *queface = *chkface;
24544   }
24545 }
24546 
24547 ///////////////////////////////////////////////////////////////////////////////
24548 //                                                                           //
24549 // checkfac4encroach()    Check if a subface is encroached by a point.       //
24550 //                                                                           //
24551 ///////////////////////////////////////////////////////////////////////////////
24552 
checkfac4encroach(point pa,point pb,point pc,point checkpt,REAL * cent,REAL * r)24553 int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
24554                                   REAL* cent, REAL* r)
24555 {
24556   REAL rd, len;
24557 
24558   circumsphere(pa, pb, pc, nullptr, cent, &rd);
24559   assert(rd != 0);
24560   len = distance(cent, checkpt);
24561   if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
24562 
24563   if (len < rd) {
24564     // The point lies inside the circumsphere of this face.
24565     if (b->metric || b->nobisect) { // -m or -Y option.
24566       if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
24567           (pc[pointmtrindex] > 0)) {
24568         // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
24569         REAL prjpt[3], n[3];
24570         REAL a, a1, a2, a3;
24571         projpt2face(checkpt, pa, pb, pc, prjpt);
24572         // Get the face area of [a,b,c].
24573         facenormal(pa, pb, pc, n, 1, nullptr);
24574         a = sqrt(dot(n,n));
24575         // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
24576         facenormal(pa, pb, prjpt, n, 1, nullptr);
24577         a1 = sqrt(dot(n,n));
24578         facenormal(pb, pc, prjpt, n, 1, nullptr);
24579         a2 = sqrt(dot(n,n));
24580         facenormal(pc, pa, prjpt, n, 1, nullptr);
24581         a3 = sqrt(dot(n,n));
24582         if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
24583           // This face contains the projection.
24584           // Get the mesh size at the location of the projection point.
24585           rd = a1 / a * pc[pointmtrindex]
24586              + a2 / a * pa[pointmtrindex]
24587              + a3 / a * pb[pointmtrindex];
24588           len = distance(prjpt, checkpt);
24589           if (len < rd) {
24590             return 1; // Encroached.
24591           }
24592         }
24593       } else {
24594         return 1;  // No protecting ball. Encroached.
24595       }
24596     } else {
24597       *r = rd;
24598       return 1;  // Encroached.
24599     }
24600   }
24601 
24602   return 0;
24603 }
24604 
24605 ///////////////////////////////////////////////////////////////////////////////
24606 //                                                                           //
24607 // checkfac4split()    Check if a subface needs to be split.                 //
24608 //                                                                           //
24609 // A subface needs to be split if it is in the following case:               //
24610 //  (1) It is encroached by an existing vertex.                              //
24611 //  (2) It has bad quality (has a small angle, -q).                          //
24612 //  (3) It's area is larger than a prescribed value (.var).                  //
24613 //                                                                           //
24614 // Return 1 if it needs to be split, otherwise, return 0.                    //
24615 // 'chkfac' represents its longest edge.                                     //
24616 //                                                                           //
24617 ///////////////////////////////////////////////////////////////////////////////
24618 
checkfac4split(face * chkfac,point & encpt,int & qflag,REAL * cent)24619 int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
24620                                REAL *cent)
24621 {
24622   point pa, pb, pc;
24623   REAL area, rd, len;
24624   REAL A[4][4], rhs[4], D;
24625   int indx[4];
24626   int i;
24627 
24628   encpt = nullptr;
24629   qflag = 0;
24630 
24631   pa = sorg(*chkfac);
24632   pb = sdest(*chkfac);
24633   pc = sapex(*chkfac);
24634 
24635   // Compute the coefficient matrix A (3x3).
24636   A[0][0] = pb[0] - pa[0];
24637   A[0][1] = pb[1] - pa[1];
24638   A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
24639   A[1][0] = pc[0] - pa[0];
24640   A[1][1] = pc[1] - pa[1];
24641   A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
24642   cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
24643 
24644   area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
24645 
24646   // Compute the right hand side vector b (3x1).
24647   rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
24648   rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
24649   rhs[2] = 0.0;
24650 
24651   // Solve the 3 by 3 equations use LU decomposition with partial
24652   //   pivoting and backward and forward substitute.
24653   if (!lu_decmp(A, 3, indx, &D, 0)) {
24654     // A degenerate triangle.
24655     return 0;
24656   }
24657 
24658   lu_solve(A, 3, indx, rhs, 0);
24659   cent[0] = pa[0] + rhs[0];
24660   cent[1] = pa[1] + rhs[1];
24661   cent[2] = pa[2] + rhs[2];
24662   rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
24663 
24664   if (checkconstraints && (areabound(*chkfac) > 0.0)) {
24665     // Check if the subface has too big area.
24666     if (area > areabound(*chkfac)) {
24667       qflag = 1;
24668       return 1;
24669     }
24670   }
24671 
24672   if (b->metric) { // -m option. Check mesh size.
24673     // Check if the ccent lies outside one of the prot.balls at vertices.
24674     if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
24675         ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
24676         ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
24677       qflag = 1; // Enforce mesh size.
24678       return 1;
24679     }
24680   }
24681 
24682   triface searchtet;
24683 
24684   // Check if this subface is locally encroached.
24685   for (i = 0; i < 2; i++) {
24686     stpivot(*chkfac, searchtet);
24687     if (!ishulltet(searchtet)) {
24688       len = distance(oppo(searchtet), cent);
24689       if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
24690       if (len < rd) {
24691         encpt = oppo(searchtet);
24692         return 1;
24693       }
24694     }
24695     sesymself(*chkfac);
24696   }
24697 
24698   return 0;
24699 }
24700 
24701 ///////////////////////////////////////////////////////////////////////////////
24702 //                                                                           //
24703 // splitsubface()    Split a subface.                                        //
24704 //                                                                           //
24705 // The subface may be encroached, or in bad-quality. It is split at its cir- //
24706 // cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg-  //
24707 // ments. Instead, one of the encroached segments is split.  It is possible  //
24708 // that none of the encorached segments can be split.                        //
24709 //                                                                           //
24710 // The return value indicates whether a new point is inserted (> 0) or not   //
24711 // (= 0). Furthermore, it is inserted on an encorached segment (= 1) or in-  //
24712 // side the facet (= 2).                                                     //
24713 //                                                                           //
24714 ///////////////////////////////////////////////////////////////////////////////
24715 
splitsubface(face * splitfac,point encpt,int qflag,REAL * ccent,int chkencflag)24716 int tetgenmesh::splitsubface(face *splitfac, point encpt, int qflag,
24717                              REAL *ccent, int chkencflag)
24718 {
24719   point pa = sorg(*splitfac);
24720   point pb = sdest(*splitfac);
24721   point pc = sapex(*splitfac);
24722 
24723 
24724   // Quickly check if we CAN split this subface.
24725   if (qflag == 0) {
24726     // Do not split this subface if it forms a very small dihedral with
24727     //   another facet. Avoid creating too many Steiner points.
24728     if (shelltype(*splitfac) == SHARP) {
24729       return 0;
24730     }
24731     // Do not split this subface if the 'ccent' lies inside the protect balls
24732     //   of one of its vertices.
24733     REAL rd = distance(ccent, pa);
24734     if ((rd <= pa[pointmtrindex]) || (rd <= pb[pointmtrindex]) ||
24735         (rd <= pc[pointmtrindex])) {
24736       return 0;
24737     }
24738   }
24739 
24740   if (b->nobisect) { // With -Y option.
24741     if (checkconstraints) {
24742       // Only split if it is allowed to be split.
24743       // Check if this facet has a non-zero constraint.
24744       if (areabound(*splitfac) == 0) {
24745         return 0; // Do not split it.
24746       }
24747     } else {
24748       return 0;
24749     }
24750   } // if (b->nobisect)
24751 
24752   face searchsh;
24753   insertvertexflags ivf;
24754   point newpt;
24755   int i;
24756 
24757   // Initialize the inserting point.
24758   makepoint(&newpt, FREEFACETVERTEX);
24759   // Split the subface at its circumcenter.
24760   for (i = 0; i < 3; i++) newpt[i] = ccent[i];
24761 
24762   // Search a subface which contains 'newpt'.
24763   searchsh = *splitfac;
24764   // Calculate an above point. It lies above the plane containing
24765   //   the subface [a,b,c], and save it in dummypoint. Moreover,
24766   //   the vector cent->dummypoint is the normal of the plane.
24767   calculateabovepoint4(newpt, pa, pb, pc);
24768   //   Parameters: 'aflag' = 1, - above point exists.
24769   //   'cflag' = 0, - non-convex, check co-planarity of the result.
24770   //   'rflag' = 0, - no need to round the locating result.
24771   ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
24772 
24773   if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
24774     pointdealloc(newpt);
24775     return 0;
24776   }
24777 
24778 
24779   triface searchtet;
24780   face *paryseg;
24781   int splitflag;
24782 
24783   // Insert the point.
24784   stpivot(searchsh, searchtet);
24785   //assert((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE));
24786   // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
24787   ivf.bowywat = 3;
24788   ivf.lawson = 2;
24789   ivf.rejflag = 1; // Do check the encroachment of segments.
24790   if (qflag == 0) {
24791     ivf.rejflag |= 4; // Reject it if it encroached upon any vertex.
24792   }
24793   ivf.chkencflag = chkencflag;
24794   ivf.sloc = (int) INSTAR; // ivf.iloc;
24795   ivf.sbowywat = 3; // ivf.bowywat;
24796   ivf.splitbdflag = 1;
24797   ivf.validflag = 1;
24798   ivf.respectbdflag = 1;
24799   ivf.assignmeshsize = 1;
24800 
24801   ivf.refineflag = 2;
24802   ivf.refinesh = searchsh;
24803 
24804 
24805   if (insertpoint(newpt, &searchtet, &searchsh, nullptr, &ivf)) {
24806     st_facref_count++;
24807     if (steinerleft > 0) steinerleft--;
24808     if (flipstack != nullptr) {
24809       flipconstraints fc;
24810       fc.chkencflag = chkencflag;
24811       fc.enqflag = 2;
24812       lawsonflip3d(&fc);
24813       unflipqueue->restart();
24814     }
24815     return 1;
24816   } else {
24817     // Point was not inserted.
24818     pointdealloc(newpt);
24819     if (ivf.iloc == (int) ENCSEGMENT) {
24820       // Select an encroached segment and split it.
24821       splitflag = 0;
24822       for (i = 0; i < encseglist->objects; i++) {
24823         paryseg = (face *) fastlookup(encseglist, i);
24824         if (splitsegment(paryseg, nullptr, qflag, chkencflag | 1)) {
24825           splitflag = 1; // A point is inserted on a segment.
24826           break;
24827         }
24828       }
24829       encseglist->restart();
24830       if (splitflag) {
24831         // Some segments may need to be repaired.
24832         repairencsegs(chkencflag | 1);
24833         // Queue this subface if it is still alive and not queued.
24834         //if ((splitfac->sh != nullptr) && (splitfac->sh[3] != nullptr)) {
24835         //  // Only queue it if 'qflag' is set.
24836         //  if (qflag) {
24837         //    enqueuesubface(badsubfacs, splitfac);
24838         //  }
24839         //}
24840       }
24841       return splitflag;
24842     } else {
24843       return 0;
24844     }
24845   }
24846 }
24847 
24848 ///////////////////////////////////////////////////////////////////////////////
24849 //                                                                           //
24850 // repairencfacs()    Repair encroached subfaces.                            //
24851 //                                                                           //
24852 ///////////////////////////////////////////////////////////////////////////////
24853 
repairencfacs(int chkencflag)24854 void tetgenmesh::repairencfacs(int chkencflag)
24855 {
24856   face *bface;
24857   point encpt = nullptr;
24858   int qflag = 0;
24859   REAL ccent[3];
24860 
24861   // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
24862   //   if an unlimited number of Steiner points is allowed.
24863   while ((badsubfacs->items > 0) && (steinerleft != 0)) {
24864     badsubfacs->traversalinit();
24865     bface = (face *) badsubfacs->traverse();
24866     while ((bface != nullptr) && (steinerleft != 0)) {
24867       // Skip a deleted element.
24868       if (bface->shver >= 0) {
24869         // A queued subface may have been deleted (split).
24870         if ((bface->sh != nullptr) && (bface->sh[3] != nullptr)) {
24871           // A queued subface may have been processed.
24872           if (smarktest2ed(*bface)) {
24873             sunmarktest2(*bface);
24874             if (checkfac4split(bface, encpt, qflag, ccent)) {
24875               splitsubface(bface, encpt, qflag, ccent, chkencflag);
24876             }
24877           }
24878         }
24879         bface->shver = -1; // Signal it as a deleted element.
24880         badsubfacs->dealloc((void *) bface); // Remove this entry from list.
24881       }
24882       bface = (face *) badsubfacs->traverse();
24883     }
24884   }
24885 
24886   if (badsubfacs->items > 0) {
24887     if (steinerleft == 0) {
24888       if (b->verbose) {
24889         printf("The desired number of Steiner points is reached.\n");
24890       }
24891     } else {
24892       assert(0); // Unknown case.
24893     }
24894     badsubfacs->traversalinit();
24895     bface = (face *) badsubfacs->traverse();
24896     while (bface  != nullptr) {
24897       // Skip a deleted element.
24898       if (bface->shver >= 0) {
24899         if ((bface->sh != nullptr) && (bface->sh[3] != nullptr)) {
24900           if (smarktest2ed(*bface)) {
24901             sunmarktest2(*bface);
24902           }
24903         }
24904       }
24905       bface = (face *) badsubfacs->traverse();
24906     }
24907     badsubfacs->restart();
24908   }
24909 }
24910 
24911 ///////////////////////////////////////////////////////////////////////////////
24912 //                                                                           //
24913 // enqueuetetrahedron()    Queue a tetrahedron for quality check.            //
24914 //                                                                           //
24915 ///////////////////////////////////////////////////////////////////////////////
24916 
enqueuetetrahedron(triface * chktet)24917 void tetgenmesh::enqueuetetrahedron(triface *chktet)
24918 {
24919   if (!marktest2ed(*chktet)) {
24920     marktest2(*chktet); // Only queue it once.
24921     triface *quetet = (triface *) badtetrahedrons->alloc();
24922     *quetet = *chktet;
24923   }
24924 }
24925 
24926 ///////////////////////////////////////////////////////////////////////////////
24927 //                                                                           //
24928 // checktet4split()    Check if the tet needs to be split.                   //
24929 //                                                                           //
24930 ///////////////////////////////////////////////////////////////////////////////
24931 
checktet4split(triface * chktet,int & qflag,REAL * ccent)24932 int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
24933 {
24934   point pa, pb, pc, pd, *ppt;
24935   REAL vda[3], vdb[3], vdc[3];
24936   REAL vab[3], vbc[3], vca[3];
24937   REAL N[4][3], L[4], cosd[6], elen[6];
24938   REAL maxcosd, vol, volbnd, smlen, rd;
24939   REAL A[4][4], rhs[4], D;
24940   int indx[4];
24941   int i, j;
24942 
24943   qflag = 0;
24944 
24945   pd = (point) chktet->tet[7];
24946   if (pd == dummypoint) {
24947     return 0; // Do not split a hull tet.
24948   }
24949 
24950   pa = (point) chktet->tet[4];
24951   pb = (point) chktet->tet[5];
24952   pc = (point) chktet->tet[6];
24953 
24954   // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
24955   // Set the matrix A = [vda, vdb, vdc]^T.
24956   for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
24957   for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
24958   for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
24959 
24960   // Get the other edge vectors.
24961   for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
24962   for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
24963   for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
24964 
24965   if (!lu_decmp(A, 3, indx, &D, 0)) {
24966     // A degenerated tet (vol = 0).
24967     // Return its barycenter.
24968     for (i = 0; i < 3; i++) {
24969       ccent[i] = 0.25 * (pa[i] + pb[i] + pc[i] + pd[i]);
24970     }
24971     return 1;
24972   }
24973 
24974   // Check volume if '-a#' and '-a' options are used.
24975   if (b->varvolume || b->fixedvolume) {
24976     vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
24977     if (b->fixedvolume) {
24978       if (vol > b->maxvolume) {
24979         qflag = 1;
24980       }
24981     }
24982     if (!qflag && b->varvolume) {
24983       volbnd = volumebound(chktet->tet);
24984       if ((volbnd > 0.0) && (vol > volbnd)) {
24985         qflag = 1;
24986       }
24987     }
24988     if (qflag == 1) {
24989       // Calculate the circumcenter of this tet.
24990       rhs[0] = 0.5 * dot(vda, vda);
24991       rhs[1] = 0.5 * dot(vdb, vdb);
24992       rhs[2] = 0.5 * dot(vdc, vdc);
24993       lu_solve(A, 3, indx, rhs, 0);
24994       for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
24995       return 1;
24996     }
24997   }
24998 
24999   if (in->tetunsuitable != nullptr) {
25000     // Execute the user-defined meshing sizing evaluation.
25001     if ((*(in->tetunsuitable))(pa, pb, pc, pd, nullptr, 0)) {
25002       // Calculate the circumcenter of this tet.
25003       rhs[0] = 0.5 * dot(vda, vda);
25004       rhs[1] = 0.5 * dot(vdb, vdb);
25005       rhs[2] = 0.5 * dot(vdc, vdc);
25006       lu_solve(A, 3, indx, rhs, 0);
25007       for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25008       return 1;
25009     } else {
25010       return 0; // Do not split this tet.
25011     }
25012   }
25013 
25014   // Check the radius-edge ratio. Set by -q#.
25015   if (b->minratio > 0) {
25016     // Calculate the circumcenter and radius of this tet.
25017     rhs[0] = 0.5 * dot(vda, vda);
25018     rhs[1] = 0.5 * dot(vdb, vdb);
25019     rhs[2] = 0.5 * dot(vdc, vdc);
25020     lu_solve(A, 3, indx, rhs, 0);
25021     for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25022     rd = sqrt(dot(rhs, rhs));
25023     // Calculate the shortest edge length.
25024     elen[0] = dot(vda, vda);
25025     elen[1] = dot(vdb, vdb);
25026     elen[2] = dot(vdc, vdc);
25027     elen[3] = dot(vab, vab);
25028     elen[4] = dot(vbc, vbc);
25029     elen[5] = dot(vca, vca);
25030     smlen = elen[0]; //sidx = 0;
25031     for (i = 1; i < 6; i++) {
25032       if (smlen > elen[i]) {
25033         smlen = elen[i]; //sidx = i;
25034       }
25035     }
25036     smlen = sqrt(smlen);
25037     D = rd / smlen;
25038     if (D > b->minratio) {
25039       // A bad radius-edge ratio.
25040       return 1;
25041     }
25042   }
25043 
25044   // Check the minimum dihedral angle. Set by -qq#.
25045   if (b->mindihedral > 0) {
25046     // Compute the 4 face normals (N[0], ..., N[3]).
25047     for (j = 0; j < 3; j++) {
25048       for (i = 0; i < 3; i++) N[j][i] = 0.0;
25049       N[j][j] = 1.0;  // Positive means the inside direction
25050       lu_solve(A, 3, indx, N[j], 0);
25051     }
25052     for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
25053     // Normalize the normals.
25054     for (i = 0; i < 4; i++) {
25055       L[i] = sqrt(dot(N[i], N[i]));
25056       assert(L[i] > 0);
25057       //if (L[i] > 0.0) {
25058         for (j = 0; j < 3; j++) N[i][j] /= L[i];
25059       //}
25060     }
25061     // Calculate the six dihedral angles.
25062     cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
25063     cosd[1] = -dot(N[0], N[2]);
25064     cosd[2] = -dot(N[0], N[3]);
25065     cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
25066     cosd[4] = -dot(N[1], N[3]);
25067     cosd[5] = -dot(N[2], N[3]); // Edge ab
25068     // Get the smallest diehedral angle.
25069     //maxcosd = mincosd = cosd[0];
25070     maxcosd = cosd[0];
25071     for (i = 1; i < 6; i++) {
25072       //if (cosd[i] > maxcosd) maxcosd = cosd[i];
25073       maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
25074       //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
25075     }
25076     if (maxcosd > cosmindihed) {
25077       // Calculate the circumcenter of this tet.
25078       // A bad dihedral angle.
25079       //if ((b->quality & 1) == 0) {
25080         rhs[0] = 0.5 * dot(vda, vda);
25081         rhs[1] = 0.5 * dot(vdb, vdb);
25082         rhs[2] = 0.5 * dot(vdc, vdc);
25083         lu_solve(A, 3, indx, rhs, 0);
25084         for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25085         //*rd = sqrt(dot(rhs, rhs));
25086       //}
25087       return 1;
25088     }
25089   }
25090 
25091   if (b->metric) { // -m option. Check mesh size.
25092     // Calculate the circumradius of this tet.
25093     rhs[0] = 0.5 * dot(vda, vda);
25094     rhs[1] = 0.5 * dot(vdb, vdb);
25095     rhs[2] = 0.5 * dot(vdc, vdc);
25096     lu_solve(A, 3, indx, rhs, 0);
25097     for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25098     rd = sqrt(dot(rhs, rhs));
25099     // Check if the ccent lies outside one of the prot.balls at vertices.
25100     ppt = (point *) &(chktet->tet[4]);
25101     for (i = 0; i < 4; i++) {
25102       if (ppt[i][pointmtrindex] > 0) {
25103         if (rd > ppt[i][pointmtrindex]) {
25104           qflag = 1; // Enforce mesh size.
25105           return 1;
25106         }
25107       }
25108     }
25109   }
25110 
25111   return 0;
25112 }
25113 
25114 ///////////////////////////////////////////////////////////////////////////////
25115 //                                                                           //
25116 // splittetrahedron()    Split a tetrahedron.                                //
25117 //                                                                           //
25118 ///////////////////////////////////////////////////////////////////////////////
25119 
splittetrahedron(triface * splittet,int qflag,REAL * ccent,int chkencflag)25120 int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
25121                                  int chkencflag)
25122 {
25123   triface searchtet;
25124   face *paryseg;
25125   point newpt, *ppt;
25126   badface *bface;
25127   insertvertexflags ivf;
25128   int splitflag;
25129   int i;
25130 
25131 
25132   if (qflag == 0) {
25133     // It is a bad quality tet (not due to mesh size).
25134     // It can be split if 'ccent' does not encroach upon any prot. balls.
25135     //   Do a quick check if the 'ccent' lies inside the protect balls
25136     //   of one of the vertices of this tet.
25137     ppt = (point *) &(splittet->tet[4]);
25138     REAL rd = distance(ccent, ppt[0]);
25139     if ((rd <= ppt[0][pointmtrindex]) || (rd <= ppt[1][pointmtrindex]) ||
25140         (rd <= ppt[2][pointmtrindex]) || (rd <= ppt[3][pointmtrindex])) {
25141       return 0;
25142     }
25143   }
25144 
25145   makepoint(&newpt, FREEVOLVERTEX);
25146   for (i = 0; i < 3; i++) newpt[i] = ccent[i];
25147 
25148   searchtet = *splittet;
25149   ivf.iloc = (int) OUTSIDE;
25150   // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
25151   ivf.bowywat = 3;
25152   ivf.lawson = 2;
25153   ivf.rejflag = 3;  // Do check for encroached segments and subfaces.
25154   if (qflag == 0) {
25155     ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
25156   }
25157   ivf.chkencflag = chkencflag;
25158   ivf.sloc = ivf.sbowywat = 0; // No use.
25159   ivf.splitbdflag = 0; // No use.
25160   ivf.validflag = 1;
25161   ivf.respectbdflag = 1;
25162   ivf.assignmeshsize = 1;
25163 
25164   ivf.refineflag = 1;
25165   ivf.refinetet = *splittet;
25166 
25167 
25168   if (insertpoint(newpt, &searchtet, nullptr, nullptr, &ivf)) {
25169     // Vertex is inserted.
25170     st_volref_count++;
25171     if (steinerleft > 0) steinerleft--;
25172     if (flipstack != nullptr) {
25173       flipconstraints fc;
25174       fc.chkencflag = chkencflag;
25175       fc.enqflag = 2;
25176       lawsonflip3d(&fc);
25177       unflipqueue->restart();
25178     }
25179     return 1;
25180   } else {
25181     // Point is not inserted.
25182     pointdealloc(newpt);
25183     // Check if there are encroached segments/subfaces.
25184     if (ivf.iloc == (int) ENCSEGMENT) {
25185       splitflag = 0;
25186       //if (!b->nobisect) { // not -Y option
25187       if (!b->nobisect || checkconstraints) {
25188         // Select an encroached segment and split it.
25189         for (i = 0; i < encseglist->objects; i++) {
25190           paryseg = (face *) fastlookup(encseglist, i);
25191           if (splitsegment(paryseg, nullptr, qflag, chkencflag | 3)) {
25192             splitflag = 1; // A point is inserted on a segment.
25193             break;
25194           }
25195         }
25196       } // if (!b->nobisect)
25197       encseglist->restart();
25198       if (splitflag) {
25199         // Some segments may need to be repaired.
25200         repairencsegs(chkencflag | 3);
25201         // Some subfaces may need to be repaired.
25202         repairencfacs(chkencflag | 2);
25203         // Queue the tet if it is still alive and not queued.
25204         if ((splittet->tet != nullptr) && (splittet->tet[4] != nullptr)) {
25205           enqueuetetrahedron(splittet);
25206         }
25207       }
25208       return splitflag;
25209     } else if (ivf.iloc == (int) ENCSUBFACE) {
25210       splitflag = 0;
25211       //if (!b->nobisect) { // not -Y option
25212       if (!b->nobisect || checkconstraints) {
25213         // Select an encroached subface and split it.
25214         for (i = 0; i < encshlist->objects; i++) {
25215           bface = (badface *) fastlookup(encshlist, i);
25216           if (splitsubface(&(bface->ss),nullptr,qflag,bface->cent,chkencflag|2)){
25217             splitflag = 1; // A point is inserted on a subface or a segment.
25218             break;
25219           }
25220         }
25221       } // if (!b->nobisect)
25222       encshlist->restart();
25223       if (splitflag) {
25224         assert(badsubsegs->items == 0l);
25225         // Some subfaces may need to be repaired.
25226         repairencfacs(chkencflag | 2);
25227         // Queue the tet if it is still alive.
25228         if ((splittet->tet != nullptr) && (splittet->tet[4] != nullptr)) {
25229           enqueuetetrahedron(splittet);
25230         }
25231       }
25232       return splitflag;
25233     }
25234     return 0;
25235   }
25236 }
25237 
25238 ///////////////////////////////////////////////////////////////////////////////
25239 //                                                                           //
25240 // repairbadtets()    Repair bad quality tetrahedra.                         //
25241 //                                                                           //
25242 ///////////////////////////////////////////////////////////////////////////////
25243 
repairbadtets(int chkencflag)25244 void tetgenmesh::repairbadtets(int chkencflag)
25245 {
25246   triface *bface;
25247   REAL ccent[3];
25248   int qflag = 0;
25249 
25250   int attrnum = numelemattrib - 1;
25251 
25252   // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
25253   //   if an unlimited number of Steiner points is allowed.
25254   while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
25255     badtetrahedrons->traversalinit();
25256     bface = (triface *) badtetrahedrons->traverse();
25257     while ((bface != nullptr) && (steinerleft != 0)) {
25258       // Skip a deleted element.
25259       if (bface->ver >= 0) {
25260         // A queued tet may have been deleted.
25261         if (!isdeadtet(*bface)) {
25262           // A queued tet may have been processed.
25263           if (marktest2ed(*bface)) {
25264             unmarktest2(*bface);
25265             if (b->convex) { // -c
25266               // Skip this tet if it lies in the exterior.
25267               if (elemattribute(bface->tet, attrnum) != -1.0) {
25268                 if (checktet4split(bface, qflag, ccent)) {
25269                   splittetrahedron(bface, qflag, ccent, chkencflag);
25270                 }
25271               }
25272             } else {
25273               if (checktet4split(bface, qflag, ccent)) {
25274                 splittetrahedron(bface, qflag, ccent, chkencflag);
25275               }
25276             }
25277           }
25278         }
25279         bface->ver = -1; // Signal it as a deleted element.
25280         badtetrahedrons->dealloc((void *) bface);
25281       }
25282       bface = (triface *) badtetrahedrons->traverse();
25283     }
25284   }
25285 
25286   if (badtetrahedrons->items > 0) {
25287     if (steinerleft == 0) {
25288       if (b->verbose) {
25289         printf("The desired number of Steiner points is reached.\n");
25290       }
25291     } else {
25292       assert(0); // Unknown case.
25293     }
25294     // Unmark all queued tet.
25295     badtetrahedrons->traversalinit();
25296     bface = (triface *) badtetrahedrons->traverse();
25297     while (bface != nullptr) {
25298       // Skip a deleted element.
25299       if (bface->ver >= 0) {
25300         if (!isdeadtet(*bface)) {
25301           if (marktest2ed(*bface)) {
25302             unmarktest2(*bface);
25303           }
25304         }
25305       }
25306       bface = (triface *) badtetrahedrons->traverse();
25307     }
25308     // Clear the pool.
25309     badtetrahedrons->restart();
25310   }
25311 }
25312 
25313 ///////////////////////////////////////////////////////////////////////////////
25314 //                                                                           //
25315 // enforcequality()    Refine the mesh.                                      //
25316 //                                                                           //
25317 ///////////////////////////////////////////////////////////////////////////////
25318 
delaunayrefinement()25319 void tetgenmesh::delaunayrefinement()
25320 {
25321   triface checktet;
25322   face checksh;
25323   face checkseg;
25324   long steinercount;
25325   int chkencflag;
25326 
25327   long bak_segref_count, bak_facref_count, bak_volref_count;
25328   long bak_flipcount = flip23count + flip32count + flip44count;
25329 
25330   if (!b->quiet) {
25331     printf("Refining mesh...\n");
25332   }
25333 
25334   if (b->verbose) {
25335     printf("  Min radiu-edge ratio = %g.\n", b->minratio);
25336     printf("  Min dihedral   angle = %g.\n", b->mindihedral);
25337     //printf("  Min Edge length = %g.\n", b->minedgelength);
25338   }
25339 
25340   steinerleft = b->steinerleft;  // Upperbound of # Steiner points (by -S#).
25341   if (steinerleft > 0) {
25342     // Check if we've already used up the given number of Steiner points.
25343     steinercount = st_segref_count + st_facref_count + st_volref_count;
25344     if (steinercount < steinerleft) {
25345       steinerleft -= steinercount;
25346     } else {
25347       if (!b->quiet) {
25348         printf("\nWarning:  ");
25349         printf("The desired number of Steiner points (%d) has reached.\n\n",
25350                b->steinerleft);
25351       }
25352       return; // No more Steiner points.
25353     }
25354   }
25355 
25356   if (b->refine || b->nobisect) { // '-r' or '-Y' option.
25357     markacutevertices();
25358   }
25359 
25360   marksharpsegments();
25361 
25362   decidefeaturepointsizes();
25363 
25364   encseglist = new arraypool(sizeof(face), 8);
25365   encshlist = new arraypool(sizeof(badface), 8);
25366 
25367 
25368   //if (!b->nobisect) { // if no '-Y' option
25369   if (!b->nobisect || checkconstraints) {
25370     if (b->verbose) {
25371       printf("  Splitting encroached subsegments.\n");
25372     }
25373 
25374     chkencflag = 1; // Only check encroaching subsegments.
25375     steinercount = points->items;
25376 
25377     // Initialize the pool of encroached subsegments.
25378     badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock,
25379                                 sizeof(void *), 0);
25380 
25381     // Add all segments into the pool.
25382     subsegs->traversalinit();
25383     checkseg.sh = shellfacetraverse(subsegs);
25384     while (checkseg.sh != (shellface *) nullptr) {
25385       enqueuesubface(badsubsegs, &checkseg);
25386       checkseg.sh = shellfacetraverse(subsegs);
25387     }
25388 
25389     // Split all encroached segments.
25390     repairencsegs(chkencflag);
25391 
25392     if (b->verbose) {
25393       printf("  Added %ld Steiner points.\n", points->items - steinercount);
25394     }
25395 
25396 
25397     if (b->reflevel > 1) { // '-D2' option
25398       if (b->verbose) {
25399         printf("  Splitting encroached subfaces.\n");
25400       }
25401 
25402       chkencflag = 2; // Only check encroaching subfaces.
25403       steinercount = points->items;
25404       bak_segref_count = st_segref_count;
25405       bak_facref_count = st_facref_count;
25406 
25407       // Initialize the pool of encroached subfaces.
25408       badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock,
25409                                   sizeof(void *), 0);
25410 
25411       // Add all subfaces into the pool.
25412       subfaces->traversalinit();
25413       checksh.sh = shellfacetraverse(subfaces);
25414       while (checksh.sh != (shellface *) nullptr) {
25415         enqueuesubface(badsubfacs, &checksh);
25416         checksh.sh = shellfacetraverse(subfaces);
25417       }
25418 
25419       // Split all encroached subfaces.
25420       repairencfacs(chkencflag);
25421 
25422       if (b->verbose) {
25423         printf("  Added %ld (%ld,%ld) Steiner points.\n",
25424                points->items-steinercount, st_segref_count-bak_segref_count,
25425                st_facref_count-bak_facref_count);
25426       }
25427 
25428     } // if (b->reflevel > 1)
25429   } // if (!b->nobisect)
25430 
25431   if (b->reflevel > 2) { // '-D3' option (The default option)
25432     if (b->verbose) {
25433       printf("  Splitting bad quality tets.\n");
25434     }
25435 
25436     chkencflag = 4; // Only check tetrahedra.
25437     steinercount = points->items;
25438     bak_segref_count = st_segref_count;
25439     bak_facref_count = st_facref_count;
25440     bak_volref_count = st_volref_count;
25441 
25442     // The cosine value of the min dihedral angle (-qq) for tetrahedra.
25443     cosmindihed = cos(b->mindihedral / 180.0 * PI);
25444 
25445     // Initialize the pool of bad quality tetrahedra.
25446     badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
25447                                      sizeof(void *), 0);
25448     // Add all tetrahedra (no hull tets) into the pool.
25449     tetrahedrons->traversalinit();
25450     checktet.tet = tetrahedrontraverse();
25451     while (checktet.tet != nullptr) {
25452       enqueuetetrahedron(&checktet);
25453       checktet.tet = tetrahedrontraverse();
25454     }
25455 
25456     // Split all bad quality tetrahedra.
25457     repairbadtets(chkencflag);
25458 
25459     if (b->verbose) {
25460       printf("  Added %ld (%ld,%ld,%ld) Steiner points.\n",
25461              points->items - steinercount,
25462              st_segref_count - bak_segref_count,
25463              st_facref_count - bak_facref_count,
25464              st_volref_count - bak_volref_count);
25465     }
25466   } // if (b->reflevel > 2)
25467 
25468   if (b->verbose) {
25469     if (flip23count + flip32count + flip44count > bak_flipcount) {
25470       printf("  Performed %ld flips.\n", flip23count + flip32count +
25471              flip44count - bak_flipcount);
25472     }
25473   }
25474 
25475   if (steinerleft == 0) {
25476     if (!b->quiet) {
25477       printf("\nWarnning:  ");
25478       printf("The desired number of Steiner points (%d) is reached.\n\n",
25479              b->steinerleft);
25480     }
25481   }
25482 
25483 
25484   delete encseglist;
25485   delete encshlist;
25486 
25487   //if (!b->nobisect) {
25488   if (!b->nobisect || checkconstraints) {
25489     totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
25490     delete badsubsegs;
25491     if (b->reflevel > 1) {
25492       totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
25493       delete badsubfacs;
25494     }
25495   }
25496   if (b->reflevel > 2) {
25497     totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
25498     delete badtetrahedrons;
25499   }
25500 }
25501 
25502 ////                                                                       ////
25503 ////                                                                       ////
25504 //// refine_cxx ///////////////////////////////////////////////////////////////
25505 
25506 //// optimize_cxx /////////////////////////////////////////////////////////////
25507 ////                                                                       ////
25508 ////                                                                       ////
25509 
25510 ///////////////////////////////////////////////////////////////////////////////
25511 //                                                                           //
25512 // lawsonflip3d()    A three-dimensional Lawson's algorithm.                 //
25513 //                                                                           //
25514 ///////////////////////////////////////////////////////////////////////////////
25515 
lawsonflip3d(flipconstraints * fc)25516 long tetgenmesh::lawsonflip3d(flipconstraints *fc)
25517 {
25518   triface fliptets[5], neightet, hulltet;
25519   face checksh, casingout;
25520   badface *popface, *bface;
25521   point pd, pe, *pts;
25522   REAL sign, ori;
25523   long flipcount, totalcount = 0l;
25524   long sliver_peels = 0l;
25525   int t1ver;
25526   int i;
25527 
25528 
25529   while (1) {
25530 
25531     if (b->verbose > 2) {
25532       printf("      Lawson flip %ld faces.\n", flippool->items);
25533     }
25534     flipcount = 0l;
25535 
25536     while (flipstack != (badface *) nullptr) {
25537       // Pop a face from the stack.
25538       popface = flipstack;
25539       fliptets[0] = popface->tt;
25540       flipstack = flipstack->nextitem; // The next top item in stack.
25541       flippool->dealloc((void *) popface);
25542 
25543       // Skip it if it is a dead tet (destroyed by previous flips).
25544       if (isdeadtet(fliptets[0])) continue;
25545       // Skip it if it is not the same tet as we saved.
25546       if (!facemarked(fliptets[0])) continue;
25547 
25548       unmarkface(fliptets[0]);
25549 
25550       if (ishulltet(fliptets[0])) continue;
25551 
25552       fsym(fliptets[0], fliptets[1]);
25553       if (ishulltet(fliptets[1])) {
25554         if (nonconvex) {
25555           // Check if 'fliptets[0]' it is a hull sliver.
25556           tspivot(fliptets[0], checksh);
25557           for (i = 0; i < 3; i++) {
25558             if (!isshsubseg(checksh)) {
25559               spivot(checksh, casingout);
25560               //assert(casingout.sh != nullptr);
25561               if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
25562               stpivot(casingout, neightet);
25563               if (neightet.tet == fliptets[0].tet) {
25564                 // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
25565                 //   [e,d,a] and [d,e,b] are hull faces.
25566                 edestoppo(neightet, hulltet); // [a,b,e,d]
25567                 fsymself(hulltet); // [b,a,e,#]
25568                 if (oppo(hulltet) == dummypoint) {
25569                   pe = org(neightet);
25570                   if ((pointtype(pe) == FREEFACETVERTEX) ||
25571                       (pointtype(pe) == FREESEGVERTEX)) {
25572                     removevertexbyflips(pe);
25573                   }
25574                 } else {
25575                   eorgoppo(neightet, hulltet); // [b,a,d,e]
25576                   fsymself(hulltet); // [a,b,d,#]
25577                   if (oppo(hulltet) == dummypoint) {
25578                     pd = dest(neightet);
25579                     if ((pointtype(pd) == FREEFACETVERTEX) ||
25580                         (pointtype(pd) == FREESEGVERTEX)) {
25581                       removevertexbyflips(pd);
25582                     }
25583                   } else {
25584                     // Perform a 3-to-2 flip to remove the sliver.
25585                     fliptets[0] = neightet;          // [e,d,a,b]
25586                     fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
25587                     fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
25588                     flip32(fliptets, 1, fc);
25589                     // Update counters.
25590                     flip32count--;
25591                     flip22count--;
25592                     sliver_peels++;
25593                     if (fc->remove_ndelaunay_edge) {
25594                       // Update the volume (must be decreased).
25595                       //assert(fc->tetprism_vol_sum <= 0);
25596                       tetprism_vol_sum += fc->tetprism_vol_sum;
25597                       fc->tetprism_vol_sum = 0.0; // Clear it.
25598                     }
25599                   }
25600                 }
25601                 break;
25602               } // if (neightet.tet == fliptets[0].tet)
25603             } // if (!isshsubseg(checksh))
25604             senextself(checksh);
25605           } // i
25606         } // if (nonconvex)
25607         continue;
25608       }
25609 
25610       if (checksubfaceflag) {
25611         // Do not flip if it is a subface.
25612         if (issubface(fliptets[0])) continue;
25613       }
25614 
25615       // Test whether the face is locally Delaunay or not.
25616       pts = (point *) fliptets[1].tet;
25617       sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
25618 
25619       if (sign < 0) {
25620         // A non-Delaunay face. Try to flip it.
25621         pd = oppo(fliptets[0]);
25622         pe = oppo(fliptets[1]);
25623 
25624         // Check the convexity of its three edges. Stop checking either a
25625         //   locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
25626         //   encountered, and 'fliptet' represents that edge.
25627         for (i = 0; i < 3; i++) {
25628           ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
25629           if (ori <= 0) break;
25630           enextself(fliptets[0]);
25631         }
25632 
25633         if (ori > 0) {
25634           // A 2-to-3 flip is found.
25635           //   [0] [a,b,c,d],
25636           //   [1] [b,a,c,e]. no dummypoint.
25637           flip23(fliptets, 0, fc);
25638           flipcount++;
25639           if (fc->remove_ndelaunay_edge) {
25640             // Update the volume (must be decreased).
25641             //assert(fc->tetprism_vol_sum <= 0);
25642             tetprism_vol_sum += fc->tetprism_vol_sum;
25643             fc->tetprism_vol_sum = 0.0; // Clear it.
25644           }
25645           continue;
25646         } else { // ori <= 0
25647           // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
25648           //   where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
25649           if (checksubsegflag) {
25650             // Do not flip if it is a segment.
25651             if (issubseg(fliptets[0])) continue;
25652           }
25653           // Check if there are three or four tets sharing at this edge.
25654           esymself(fliptets[0]); // [b,a,d,c]
25655           for (i = 0; i < 3; i++) {
25656             fnext(fliptets[i], fliptets[i+1]);
25657           }
25658           if (fliptets[3].tet == fliptets[0].tet) {
25659             // A 3-to-2 flip is found. (No hull tet.)
25660             flip32(fliptets, 0, fc);
25661             flipcount++;
25662             if (fc->remove_ndelaunay_edge) {
25663               // Update the volume (must be decreased).
25664               //assert(fc->tetprism_vol_sum <= 0);
25665               tetprism_vol_sum += fc->tetprism_vol_sum;
25666               fc->tetprism_vol_sum = 0.0; // Clear it.
25667             }
25668             continue;
25669           } else {
25670             // There are more than 3 tets at this edge.
25671             fnext(fliptets[3], fliptets[4]);
25672             if (fliptets[4].tet == fliptets[0].tet) {
25673               // There are exactly 4 tets at this edge.
25674               if (nonconvex) {
25675                 if (apex(fliptets[3]) == dummypoint) {
25676                   // This edge is locally non-convex on the hull.
25677                   // It can be removed by a 4-to-4 flip.
25678                   ori = 0;
25679                 }
25680               } // if (nonconvex)
25681               if (ori == 0) {
25682                 // A 4-to-4 flip is found. (Two hull tets may be involved.)
25683                 // Current tets in 'fliptets':
25684                 //   [0] [b,a,d,c] (d may be newpt)
25685                 //   [1] [b,a,c,e]
25686                 //   [2] [b,a,e,f] (f may be dummypoint)
25687                 //   [3] [b,a,f,d]
25688                 esymself(fliptets[0]); // [a,b,c,d]
25689                 // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
25690                 //   This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
25691                 //   It will be removed by the followed 3-to-2 flip.
25692                 flip23(fliptets, 0, fc); // No hull tet.
25693                 fnext(fliptets[3], fliptets[1]);
25694                 fnext(fliptets[1], fliptets[2]);
25695                 // Current tets in 'fliptets':
25696                 //   [0] [...]
25697                 //   [1] [b,a,d,e] (degenerated, d may be new point).
25698                 //   [2] [b,a,e,f] (f may be dummypoint)
25699                 //   [3] [b,a,f,d]
25700                 // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
25701                 //   Hull tets may be involved (f may be dummypoint).
25702                 flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
25703                 flipcount++;
25704                 flip23count--;
25705                 flip32count--;
25706                 flip44count++;
25707                 if (fc->remove_ndelaunay_edge) {
25708                   // Update the volume (must be decreased).
25709                   //assert(fc->tetprism_vol_sum <= 0);
25710                   tetprism_vol_sum += fc->tetprism_vol_sum;
25711                   fc->tetprism_vol_sum = 0.0; // Clear it.
25712                 }
25713                 continue;
25714               } // if (ori == 0)
25715             }
25716           }
25717         } // if (ori <= 0)
25718 
25719         // This non-Delaunay face is unflippable. Save it.
25720         unflipqueue->newindex((void **) &bface);
25721         bface->tt = fliptets[0];
25722         bface->forg  = org(fliptets[0]);
25723         bface->fdest = dest(fliptets[0]);
25724         bface->fapex = apex(fliptets[0]);
25725       } // if (sign < 0)
25726     } // while (flipstack)
25727 
25728     if (b->verbose > 2) {
25729       if (flipcount > 0) {
25730         printf("      Performed %ld flips.\n", flipcount);
25731       }
25732     }
25733     // Accumulate the counter of flips.
25734     totalcount += flipcount;
25735 
25736     assert(flippool->items == 0l);
25737     // Return if no unflippable faces left.
25738     if (unflipqueue->objects == 0l) break;
25739     // Return if no flip has been performed.
25740     if (flipcount == 0l) break;
25741 
25742     // Try to flip the unflippable faces.
25743     for (i = 0; i < unflipqueue->objects; i++) {
25744       bface = (badface *) fastlookup(unflipqueue, i);
25745       if (!isdeadtet(bface->tt) &&
25746           (org(bface->tt) == bface->forg) &&
25747           (dest(bface->tt) == bface->fdest) &&
25748           (apex(bface->tt) == bface->fapex)) {
25749         flippush(flipstack, &(bface->tt));
25750       }
25751     }
25752     unflipqueue->restart();
25753 
25754   } // while (1)
25755 
25756   if (b->verbose > 2) {
25757     if (totalcount > 0) {
25758       printf("      Performed %ld flips.\n", totalcount);
25759     }
25760     if (sliver_peels > 0) {
25761       printf("      Removed %ld hull slivers.\n", sliver_peels);
25762     }
25763     if (unflipqueue->objects > 0l) {
25764       printf("      %ld unflippable edges remained.\n", unflipqueue->objects);
25765     }
25766   }
25767 
25768   return totalcount + sliver_peels;
25769 }
25770 
25771 ///////////////////////////////////////////////////////////////////////////////
25772 //                                                                           //
25773 // recoverdelaunay()    Recovery the locally Delaunay property.              //
25774 //                                                                           //
25775 ///////////////////////////////////////////////////////////////////////////////
25776 
recoverdelaunay()25777 void tetgenmesh::recoverdelaunay()
25778 {
25779   arraypool *flipqueue, *nextflipqueue, *swapqueue;
25780   triface tetloop, neightet, *parytet;
25781   badface *bface, *parybface;
25782   point *ppt;
25783   flipconstraints fc;
25784   int i, j;
25785 
25786   if (!b->quiet) {
25787     printf("Recovering Delaunayness...\n");
25788   }
25789 
25790   tetprism_vol_sum = 0.0; // Initialize it.
25791 
25792   // Put all interior faces of the mesh into 'flipstack'.
25793   tetrahedrons->traversalinit();
25794   tetloop.tet = tetrahedrontraverse();
25795   while (tetloop.tet != nullptr) {
25796     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
25797       decode(tetloop.tet[tetloop.ver], neightet);
25798       if (!facemarked(neightet)) {
25799         flippush(flipstack, &tetloop);
25800       }
25801     }
25802     ppt = (point *) &(tetloop.tet[4]);
25803     tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
25804     tetloop.tet = tetrahedrontraverse();
25805   }
25806 
25807   // Calulate a relatively lower bound for small improvement.
25808   //   Used to avoid rounding error in volume calculation.
25809   fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
25810 
25811   if (b->verbose) {
25812     printf("  Initial obj = %.17g\n", tetprism_vol_sum);
25813   }
25814 
25815   if (b->verbose > 1) {
25816     printf("    Recover Delaunay [Lawson] : %ld\n", flippool->items);
25817   }
25818 
25819   // First only use the basic Lawson's flip.
25820   fc.remove_ndelaunay_edge = 1;
25821   fc.enqflag = 2;
25822 
25823   lawsonflip3d(&fc);
25824 
25825   if (b->verbose > 1) {
25826     printf("    obj (after Lawson) = %.17g\n", tetprism_vol_sum);
25827   }
25828 
25829   if (unflipqueue->objects == 0l) {
25830     return; // The mesh is Delaunay.
25831   }
25832 
25833   fc.unflip = 1; // Unflip if the edge is not flipped.
25834   fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
25835   fc.enqflag = 0;
25836 
25837   autofliplinklevel = 1; // Init level.
25838   b->fliplinklevel = -1; // No fixed level.
25839 
25840   // For efficiency reason, we limit the maximium size of the edge star.
25841   int bakmaxflipstarsize = b->flipstarsize;
25842   b->flipstarsize = 10; // default
25843 
25844   flipqueue = new arraypool(sizeof(badface), 10);
25845   nextflipqueue = new arraypool(sizeof(badface), 10);
25846 
25847   // Swap the two flip queues.
25848   swapqueue = flipqueue;
25849   flipqueue = unflipqueue;
25850   unflipqueue = swapqueue;
25851 
25852   while (flipqueue->objects > 0l) {
25853 
25854     if (b->verbose > 1) {
25855       printf("    Recover Delaunay [level = %2d] #:  %ld.\n",
25856              autofliplinklevel, flipqueue->objects);
25857     }
25858 
25859     for (i = 0; i < flipqueue->objects; i++) {
25860       bface  = (badface *) fastlookup(flipqueue, i);
25861       if (getedge(bface->forg, bface->fdest, &bface->tt)) {
25862         if (removeedgebyflips(&(bface->tt), &fc) == 2) {
25863           tetprism_vol_sum += fc.tetprism_vol_sum;
25864           fc.tetprism_vol_sum = 0.0; // Clear it.
25865           // Queue new faces for flips.
25866           for (j = 0; j < cavetetlist->objects; j++) {
25867             parytet = (triface *) fastlookup(cavetetlist, j);
25868             // A queued new tet may be dead.
25869             if (!isdeadtet(*parytet)) {
25870               for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
25871                 // Avoid queue a face twice.
25872                 decode(parytet->tet[parytet->ver], neightet);
25873                 if (!facemarked(neightet)) {
25874                   flippush(flipstack, parytet);
25875                 }
25876               } // parytet->ver
25877             }
25878           } // j
25879           cavetetlist->restart();
25880           // Remove locally non-Delaunay faces. New non-Delaunay edges
25881           //   may be found. They are saved in 'unflipqueue'.
25882           fc.enqflag = 2;
25883           lawsonflip3d(&fc);
25884           fc.enqflag = 0;
25885           // There may be unflipable faces. Add them in flipqueue.
25886           for (j = 0; j < unflipqueue->objects; j++) {
25887             bface  = (badface *) fastlookup(unflipqueue, j);
25888             flipqueue->newindex((void **) &parybface);
25889             *parybface = *bface;
25890           }
25891           unflipqueue->restart();
25892         } else {
25893           // Unable to remove this edge. Save it.
25894           nextflipqueue->newindex((void **) &parybface);
25895           *parybface = *bface;
25896           // Normally, it should be zero.
25897           //assert(fc.tetprism_vol_sum == 0.0);
25898           // However, due to rounding errors, a tiny value may appear.
25899           fc.tetprism_vol_sum = 0.0;
25900         }
25901       }
25902     } // i
25903 
25904     if (b->verbose > 1) {
25905       printf("    obj (after level %d) = %.17g.\n", autofliplinklevel,
25906              tetprism_vol_sum);
25907     }
25908     flipqueue->restart();
25909 
25910     // Swap the two flip queues.
25911     swapqueue = flipqueue;
25912     flipqueue = nextflipqueue;
25913     nextflipqueue = swapqueue;
25914 
25915     if (flipqueue->objects > 0l) {
25916       // default 'b->delmaxfliplevel' is 1.
25917       if (autofliplinklevel >= b->delmaxfliplevel) {
25918         // For efficiency reason, we do not search too far.
25919         break;
25920       }
25921       autofliplinklevel+=b->fliplinklevelinc;
25922     }
25923   } // while (flipqueue->objects > 0l)
25924 
25925   if (flipqueue->objects > 0l) {
25926     if (b->verbose > 1) {
25927       printf("    %ld non-Delaunay edges remained.\n", flipqueue->objects);
25928     }
25929   }
25930 
25931   if (b->verbose) {
25932     printf("  Final obj  = %.17g\n", tetprism_vol_sum);
25933   }
25934 
25935   b->flipstarsize = bakmaxflipstarsize;
25936   delete flipqueue;
25937   delete nextflipqueue;
25938 }
25939 
25940 ///////////////////////////////////////////////////////////////////////////////
25941 //                                                                           //
25942 // gettetrahedron()    Get a tetrahedron which have the given vertices.      //
25943 //                                                                           //
25944 ///////////////////////////////////////////////////////////////////////////////
25945 
gettetrahedron(point pa,point pb,point pc,point pd,triface * searchtet)25946 int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd,
25947                                triface *searchtet)
25948 {
25949   triface spintet;
25950   int t1ver;
25951 
25952   if (getedge(pa, pb, searchtet)) {
25953     spintet = *searchtet;
25954     while (1) {
25955       if (apex(spintet) == pc) {
25956         *searchtet = spintet;
25957         break;
25958       }
25959       fnextself(spintet);
25960       if (spintet.tet == searchtet->tet) break;
25961     }
25962     if (apex(*searchtet) == pc) {
25963       if (oppo(*searchtet) == pd) {
25964         return 1;
25965       } else {
25966         fsymself(*searchtet);
25967         if (oppo(*searchtet) == pd) {
25968           return 1;
25969         }
25970       }
25971     }
25972   }
25973 
25974   return 0;
25975 }
25976 
25977 ///////////////////////////////////////////////////////////////////////////////
25978 //                                                                           //
25979 // improvequalitybyflips()    Improve the mesh quality by flips.             //
25980 //                                                                           //
25981 ///////////////////////////////////////////////////////////////////////////////
25982 
improvequalitybyflips()25983 long tetgenmesh::improvequalitybyflips()
25984 {
25985   arraypool *flipqueue, *nextflipqueue, *swapqueue;
25986   badface *bface, *parybface;
25987   triface *parytet;
25988   point *ppt;
25989   flipconstraints fc;
25990   REAL *cosdd, ncosdd[6], maxdd;
25991   long totalremcount, remcount;
25992   int remflag;
25993   int n, i, j, k;
25994 
25995   //assert(unflipqueue->objects > 0l);
25996   flipqueue = new arraypool(sizeof(badface), 10);
25997   nextflipqueue = new arraypool(sizeof(badface), 10);
25998 
25999   // Backup flip edge options.
26000   int bakautofliplinklevel = autofliplinklevel;
26001   int bakfliplinklevel = b->fliplinklevel;
26002   int bakmaxflipstarsize = b->flipstarsize;
26003 
26004   // Set flip edge options.
26005   autofliplinklevel = 1;
26006   b->fliplinklevel = -1;
26007   b->flipstarsize = 10; // b->optmaxflipstarsize;
26008 
26009   fc.remove_large_angle = 1;
26010   fc.unflip = 1;
26011   fc.collectnewtets = 1;
26012   fc.checkflipeligibility = 1;
26013 
26014   totalremcount = 0l;
26015 
26016   // Swap the two flip queues.
26017   swapqueue = flipqueue;
26018   flipqueue = unflipqueue;
26019   unflipqueue = swapqueue;
26020 
26021   while (flipqueue->objects > 0l) {
26022 
26023     remcount = 0l;
26024 
26025     while (flipqueue->objects > 0l) {
26026       if (b->verbose > 1) {
26027         printf("    Improving mesh qualiy by flips [%d]#:  %ld.\n",
26028                autofliplinklevel, flipqueue->objects);
26029       }
26030 
26031       for (k = 0; k < flipqueue->objects; k++) {
26032         bface  = (badface *) fastlookup(flipqueue, k);
26033         if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26034                            bface->foppo, &bface->tt)) {
26035           //assert(!ishulltet(bface->tt));
26036           // There are bad dihedral angles in this tet.
26037           if (bface->tt.ver != 11) {
26038             // The dihedral angles are permuted.
26039             // Here we simply re-compute them. Slow!!.
26040             ppt = (point *) & (bface->tt.tet[4]);
26041             tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26042                            &bface->key, nullptr);
26043             bface->forg = ppt[0];
26044             bface->fdest = ppt[1];
26045             bface->fapex = ppt[2];
26046             bface->foppo = ppt[3];
26047             bface->tt.ver = 11;
26048           }
26049           if (bface->key == 0) {
26050             // Re-comput the quality values. Due to smoothing operations.
26051             ppt = (point *) & (bface->tt.tet[4]);
26052             tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26053                            &bface->key, nullptr);
26054           }
26055           cosdd = bface->cent;
26056           remflag = 0;
26057           for (i = 0; (i < 6) && !remflag; i++) {
26058             if (cosdd[i] < cosmaxdihed) {
26059               // Found a large dihedral angle.
26060               bface->tt.ver = edge2ver[i]; // Go to the edge.
26061               fc.cosdihed_in = cosdd[i];
26062               fc.cosdihed_out = 0.0; // 90 degree.
26063               n = removeedgebyflips(&(bface->tt), &fc);
26064               if (n == 2) {
26065                 // Edge is flipped.
26066                 remflag = 1;
26067                 if (fc.cosdihed_out < cosmaxdihed) {
26068                   // Queue new bad tets for further improvements.
26069                   for (j = 0; j < cavetetlist->objects; j++) {
26070                     parytet = (triface *) fastlookup(cavetetlist, j);
26071                     if (!isdeadtet(*parytet)) {
26072                       ppt = (point *) & (parytet->tet[4]);
26073                       // Do not test a hull tet.
26074                       if (ppt[3] != dummypoint) {
26075                         tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
26076                                        &maxdd, nullptr);
26077                         if (maxdd < cosmaxdihed) {
26078                           // There are bad dihedral angles in this tet.
26079                           nextflipqueue->newindex((void **) &parybface);
26080                           parybface->tt.tet = parytet->tet;
26081                           parybface->tt.ver = 11;
26082                           parybface->forg = ppt[0];
26083                           parybface->fdest = ppt[1];
26084                           parybface->fapex = ppt[2];
26085                           parybface->foppo = ppt[3];
26086                           parybface->key = maxdd;
26087                           for (n = 0; n < 6; n++) {
26088                             parybface->cent[n] = ncosdd[n];
26089                           }
26090                         }
26091                       } // if (ppt[3] != dummypoint)
26092                     }
26093                   } // j
26094                 } // if (fc.cosdihed_out < cosmaxdihed)
26095                 cavetetlist->restart();
26096                 remcount++;
26097               }
26098             }
26099           } // i
26100           if (!remflag) {
26101             // An unremoved bad tet. Queue it again.
26102             unflipqueue->newindex((void **) &parybface);
26103             *parybface = *bface;
26104           }
26105         } // if (gettetrahedron(...))
26106       } // k
26107 
26108       flipqueue->restart();
26109 
26110       // Swap the two flip queues.
26111       swapqueue = flipqueue;
26112       flipqueue = nextflipqueue;
26113       nextflipqueue = swapqueue;
26114     } // while (flipqueues->objects > 0)
26115 
26116     if (b->verbose > 1) {
26117       printf("    Removed %ld bad tets.\n", remcount);
26118     }
26119     totalremcount += remcount;
26120 
26121     if (unflipqueue->objects > 0l) {
26122       //if (autofliplinklevel >= b->optmaxfliplevel) {
26123       if (autofliplinklevel >= b->optlevel) {
26124         break;
26125       }
26126       autofliplinklevel+=b->fliplinklevelinc;
26127       //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
26128     }
26129 
26130     // Swap the two flip queues.
26131     swapqueue = flipqueue;
26132     flipqueue = unflipqueue;
26133     unflipqueue = swapqueue;
26134   } // while (flipqueues->objects > 0)
26135 
26136   // Restore original flip edge options.
26137   autofliplinklevel = bakautofliplinklevel;
26138   b->fliplinklevel = bakfliplinklevel;
26139   b->flipstarsize = bakmaxflipstarsize;
26140 
26141   delete flipqueue;
26142   delete nextflipqueue;
26143 
26144   return totalremcount;
26145 }
26146 
26147 ///////////////////////////////////////////////////////////////////////////////
26148 //                                                                           //
26149 // smoothpoint()    Moving a vertex to improve the mesh quality.             //
26150 //                                                                           //
26151 // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point.  //
26152 // It may be not a vertex of the mesh.                                       //
26153 //                                                                           //
26154 // This routine tries to move 'p' inside its star until a selected objective //
26155 // function over all tetrahedra in the star is improved. The function may be //
26156 // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
26157 // simply the volume of the tetrahedra.                                      //
26158 //                                                                           //
26159 // 'linkfacelist' contains the list of link faces of 'p'.  Since a link face //
26160 // has two orientations, ccw or cw, with respect to 'p'.  'ccw' indicates    //
26161 // the orientation is ccw (1) or not (0).                                    //
26162 //                                                                           //
26163 // 'opm' is a structure contains the parameters of the objective function.   //
26164 // It is needed by the evaluation of the function value.                     //
26165 //                                                                           //
26166 // The return value indicates weather the point is smoothed or not.          //
26167 //                                                                           //
26168 // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
26169 // no face has 'dummypoint' as its vertex.                                   //
26170 //                                                                           //
26171 ///////////////////////////////////////////////////////////////////////////////
26172 
smoothpoint(point smtpt,arraypool * linkfacelist,int ccw,optparameters * opm)26173 int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
26174                             optparameters *opm)
26175 {
26176   triface *parytet, *parytet1, swaptet;
26177   point pa, pb, pc;
26178   REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
26179   REAL oldval, minval = 0.0, val;
26180   REAL maxcosd; // oldang, newang;
26181   REAL ori, diff;
26182   int numdirs, iter;
26183   int i, j, k;
26184 
26185   // Decide the number of moving directions.
26186   numdirs = (int) linkfacelist->objects;
26187   if (numdirs > opm->numofsearchdirs) {
26188     numdirs = opm->numofsearchdirs; // Maximum search directions.
26189   }
26190 
26191   // Set the initial value.
26192   if (!opm->max_min_volume) {
26193     assert(opm->initval >= 0.0);
26194   }
26195   opm->imprval = opm->initval;
26196   iter = 0;
26197 
26198   for (i = 0; i < 3; i++) {
26199     bestpt[i] = startpt[i] = smtpt[i];
26200   }
26201 
26202   // Iterate until the obj function is not improved.
26203   while (1) {
26204 
26205     // Find the best next location.
26206     oldval = opm->imprval;
26207 
26208     for (i = 0; i < numdirs; i++) {
26209       // Randomly pick a link face (0 <= k <= objects - i - 1).
26210       k = (int) randomnation(linkfacelist->objects - i);
26211       parytet = (triface *) fastlookup(linkfacelist, k);
26212       // Calculate a new position from 'p' to the center of this face.
26213       pa = org(*parytet);
26214       pb = dest(*parytet);
26215       pc = apex(*parytet);
26216       for (j = 0; j < 3; j++) {
26217         fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
26218       }
26219       for (j = 0; j < 3; j++) {
26220         nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
26221       }
26222       // Calculate the largest minimum function value for the new location.
26223       for (j = 0; j < linkfacelist->objects; j++) {
26224         parytet = (triface *) fastlookup(linkfacelist, j);
26225         if (ccw) {
26226           pa = org(*parytet);
26227           pb = dest(*parytet);
26228         } else {
26229           pb = org(*parytet);
26230           pa = dest(*parytet);
26231         }
26232         pc = apex(*parytet);
26233         ori = orient3d(pa, pb, pc, nextpt);
26234         if (ori < 0.0) {
26235           // Calcuate the objective function value.
26236           if (opm->max_min_volume) {
26237             //val = -ori;
26238             val = - orient3dfast(pa, pb, pc, nextpt);
26239           } else if (opm->max_min_aspectratio) {
26240             val = tetaspectratio(pa, pb, pc, nextpt);
26241           } else if (opm->min_max_dihedangle) {
26242             tetalldihedral(pa, pb, pc, nextpt, nullptr, &maxcosd, nullptr);
26243             if (maxcosd < -1) maxcosd = -1.0; // Rounding.
26244             val = maxcosd + 1.0; // Make it be positive.
26245           } else {
26246             // Unknown objective function.
26247             val = 0.0;
26248           }
26249         } else { // ori >= 0.0;
26250           // An invalid new tet.
26251           // This may happen if the mesh contains inverted elements.
26252           if (opm->max_min_volume) {
26253             //val = -ori;
26254             val = - orient3dfast(pa, pb, pc, nextpt);
26255           } else {
26256             // Discard this point.
26257             break; // j
26258           }
26259         } // if (ori >= 0.0)
26260         // Stop looping when the object value is not improved.
26261         if (val <= opm->imprval) {
26262           break; // j
26263         } else {
26264           // Remember the smallest improved value.
26265           if (j == 0) {
26266             minval = val;
26267           } else {
26268             minval = (val < minval) ? val : minval;
26269           }
26270         }
26271       } // j
26272       if (j == linkfacelist->objects) {
26273         // The function value has been improved.
26274         opm->imprval = minval;
26275         // Save the new location of the point.
26276         for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
26277       }
26278       // Swap k-th and (object-i-1)-th entries.
26279       j = linkfacelist->objects - i - 1;
26280       parytet  = (triface *) fastlookup(linkfacelist, k);
26281       parytet1 = (triface *) fastlookup(linkfacelist, j);
26282       swaptet = *parytet1;
26283       *parytet1 = *parytet;
26284       *parytet = swaptet;
26285     } // i
26286 
26287     diff = opm->imprval - oldval;
26288     if (diff > 0.0) {
26289       // Is the function value improved effectively?
26290       if (opm->max_min_volume) {
26291         //if ((diff / oldval) < b->epsilon) diff = 0.0;
26292       } else if (opm->max_min_aspectratio) {
26293         if ((diff / oldval) < 1e-3) diff = 0.0;
26294       } else if (opm->min_max_dihedangle) {
26295         //oldang = acos(oldval - 1.0);
26296         //newang = acos(opm->imprval - 1.0);
26297         //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
26298       } else {
26299         // Unknown objective function.
26300         assert(0); // Not possible.
26301       }
26302     }
26303 
26304     if (diff > 0.0) {
26305       // Yes, move p to the new location and continue.
26306       for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
26307       iter++;
26308       if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
26309         // Maximum smoothing iterations reached.
26310         break;
26311       }
26312     } else {
26313       break;
26314     }
26315 
26316   } // while (1)
26317 
26318   if (iter > 0) {
26319     // The point has been smooothed.
26320     opm->smthiter = iter; // Remember the number of iterations.
26321     // The point has been smoothed. Update it to its new position.
26322     for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
26323   }
26324 
26325   return iter;
26326 }
26327 
26328 
26329 ///////////////////////////////////////////////////////////////////////////////
26330 //                                                                           //
26331 // improvequalitysmoothing()    Improve mesh quality by smoothing.           //
26332 //                                                                           //
26333 ///////////////////////////////////////////////////////////////////////////////
26334 
improvequalitybysmoothing(optparameters * opm)26335 long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
26336 {
26337   arraypool *flipqueue, *swapqueue;
26338   triface *parytet;
26339   badface *bface, *parybface;
26340   point *ppt;
26341   long totalsmtcount, smtcount;
26342   int smtflag;
26343   int iter, i, j, k;
26344 
26345   //assert(unflipqueue->objects > 0l);
26346   flipqueue = new arraypool(sizeof(badface), 10);
26347 
26348   // Swap the two flip queues.
26349   swapqueue = flipqueue;
26350   flipqueue = unflipqueue;
26351   unflipqueue = swapqueue;
26352 
26353   totalsmtcount = 0l;
26354   iter = 0;
26355 
26356   while (flipqueue->objects > 0l) {
26357 
26358     smtcount = 0l;
26359 
26360     if (b->verbose > 1) {
26361       printf("    Improving mesh qualiy by smoothing [%d]#:  %ld.\n",
26362              iter, flipqueue->objects);
26363     }
26364 
26365     for (k = 0; k < flipqueue->objects; k++) {
26366       bface  = (badface *) fastlookup(flipqueue, k);
26367       if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26368                          bface->foppo, &bface->tt)) {
26369         // Operate on it if it is not in 'unflipqueue'.
26370         if (!marktested(bface->tt)) {
26371           // Here we simply re-compute the quality. Since other smoothing
26372           //   operation may have moved the vertices of this tet.
26373           ppt = (point *) & (bface->tt.tet[4]);
26374           tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26375                          &bface->key, nullptr);
26376           if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
26377             // It is a sliver. Try to smooth its vertices.
26378             smtflag = 0;
26379             opm->initval = bface->key + 1.0;
26380             for (i = 0; (i < 4) && !smtflag; i++) {
26381               if (pointtype(ppt[i]) == FREEVOLVERTEX) {
26382                 getvertexstar(1, ppt[i], cavetetlist, nullptr, nullptr);
26383                 opm->searchstep = 0.001; // Search step size
26384                 smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
26385                 if (smtflag) {
26386                   while (opm->smthiter == opm->maxiter) {
26387                     opm->searchstep *= 10.0; // Increase the step size.
26388                     opm->initval = opm->imprval;
26389                     opm->smthiter = 0; // reset
26390                     smoothpoint(ppt[i], cavetetlist, 1, opm);
26391                   }
26392                   // This tet is modifed.
26393                   smtcount++;
26394                   if ((opm->imprval - 1.0) < cossmtdihed) {
26395                     // There are slivers in new tets. Queue them.
26396                     for (j = 0; j < cavetetlist->objects; j++) {
26397                       parytet = (triface *) fastlookup(cavetetlist, j);
26398                       assert(!isdeadtet(*parytet));
26399                       // Operate it if it is not in 'unflipqueue'.
26400                       if (!marktested(*parytet)) {
26401                         // Evaluate its quality.
26402                         // Re-use ppt, bface->key, bface->cent.
26403                         ppt = (point *) & (parytet->tet[4]);
26404                         tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
26405                                        bface->cent, &bface->key, nullptr);
26406                         if (bface->key < cossmtdihed) {
26407                           // A new sliver. Queue it.
26408                           marktest(*parytet); // It is in unflipqueue.
26409                           unflipqueue->newindex((void **) &parybface);
26410                           parybface->tt = *parytet;
26411                           parybface->forg = ppt[0];
26412                           parybface->fdest = ppt[1];
26413                           parybface->fapex = ppt[2];
26414                           parybface->foppo = ppt[3];
26415                           parybface->tt.ver = 11;
26416                           parybface->key = 0.0;
26417                         }
26418                       }
26419                     } // j
26420                   } // if ((opm->imprval - 1.0) < cossmtdihed)
26421                 } // if (smtflag)
26422                 cavetetlist->restart();
26423               } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
26424             } // i
26425             if (!smtflag) {
26426               // Didn't smooth. Queue it again.
26427               marktest(bface->tt); // It is in unflipqueue.
26428               unflipqueue->newindex((void **) &parybface);
26429               parybface->tt = bface->tt;
26430               parybface->forg = ppt[0];
26431               parybface->fdest = ppt[1];
26432               parybface->fapex = ppt[2];
26433               parybface->foppo = ppt[3];
26434               parybface->tt.ver = 11;
26435               parybface->key = 0.0;
26436             }
26437               } // if (maxdd < cosslidihed)
26438         } // if (!marktested(...))
26439       } // if (gettetrahedron(...))
26440     } // k
26441 
26442     flipqueue->restart();
26443 
26444     // Unmark the tets in unflipqueue.
26445     for (i = 0; i < unflipqueue->objects; i++) {
26446       bface  = (badface *) fastlookup(unflipqueue, i);
26447       unmarktest(bface->tt);
26448     }
26449 
26450     if (b->verbose > 1) {
26451       printf("    Smooth %ld points.\n", smtcount);
26452     }
26453     totalsmtcount += smtcount;
26454 
26455     if (smtcount == 0l) {
26456       // No point has been smoothed.
26457       break;
26458     } else {
26459       iter++;
26460       if (iter == 2) { //if (iter >= b->optpasses) {
26461         break;
26462       }
26463     }
26464 
26465     // Swap the two flip queues.
26466     swapqueue = flipqueue;
26467     flipqueue = unflipqueue;
26468     unflipqueue = swapqueue;
26469   } // while
26470 
26471   delete flipqueue;
26472 
26473   return totalsmtcount;
26474 }
26475 
26476 ///////////////////////////////////////////////////////////////////////////////
26477 //                                                                           //
26478 // splitsliver()    Split a sliver.                                          //
26479 //                                                                           //
26480 ///////////////////////////////////////////////////////////////////////////////
26481 
splitsliver(triface * slitet,REAL cosd,int chkencflag)26482 int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
26483 {
26484   triface *abtets;
26485   triface searchtet, spintet, *parytet;
26486   point pa, pb, steinerpt;
26487   optparameters opm;
26488   insertvertexflags ivf;
26489   REAL smtpt[3], midpt[3];
26490   int success;
26491   int t1ver;
26492   int n, i;
26493 
26494   // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
26495   // Go to the opposite edge [a,b].
26496   edestoppo(*slitet, searchtet); // [a,b,c,d].
26497 
26498   // Do not split a segment.
26499   if (issubseg(searchtet)) {
26500     return 0;
26501   }
26502 
26503   // Count the number of tets shared at [a,b].
26504   // Do not split it if it is a hull edge.
26505   spintet = searchtet;
26506   n = 0;
26507   while (1) {
26508     if (ishulltet(spintet)) break;
26509     n++;
26510     fnextself(spintet);
26511     if (spintet.tet == searchtet.tet) break;
26512   }
26513   if (ishulltet(spintet)) {
26514     return 0; // It is a hull edge.
26515   }
26516   assert(n >= 3);
26517 
26518   // Get all tets at edge [a,b].
26519   abtets = new triface[n];
26520   spintet = searchtet;
26521   for (i = 0; i < n; i++) {
26522     abtets[i] = spintet;
26523     fnextself(spintet);
26524   }
26525 
26526   // Initialize the list of 2n boundary faces.
26527   for (i = 0; i < n; i++) {
26528     eprev(abtets[i], searchtet);
26529     esymself(searchtet); // [a,p_i,p_i+1].
26530     cavetetlist->newindex((void **) &parytet);
26531     *parytet = searchtet;
26532     enext(abtets[i], searchtet);
26533     esymself(searchtet); // [p_i,b,p_i+1].
26534     cavetetlist->newindex((void **) &parytet);
26535     *parytet = searchtet;
26536   }
26537 
26538   // Init the Steiner point at the midpoint of edge [a,b].
26539   pa = org(abtets[0]);
26540   pb = dest(abtets[0]);
26541   for (i = 0; i < 3; i++) {
26542     smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
26543   }
26544 
26545   // Point smooth options.
26546   opm.min_max_dihedangle = 1;
26547   opm.initval = cosd + 1.0; // Initial volume is zero.
26548   opm.numofsearchdirs = 20;
26549   opm.searchstep = 0.001;
26550   opm.maxiter = 100; // Limit the maximum iterations.
26551 
26552   success = smoothpoint(smtpt, cavetetlist, 1, &opm);
26553 
26554   if (success) {
26555     while (opm.smthiter == opm.maxiter) {
26556       // It was relocated and the prescribed maximum iteration reached.
26557       // Try to increase the search stepsize.
26558       opm.searchstep *= 10.0;
26559       //opm.maxiter = 100; // Limit the maximum iterations.
26560       opm.initval = opm.imprval;
26561       opm.smthiter = 0; // Init.
26562       smoothpoint(smtpt, cavetetlist, 1, &opm);
26563     }
26564   } // if (success)
26565 
26566   cavetetlist->restart();
26567 
26568   if (!success) {
26569     delete [] abtets;
26570     return 0;
26571   }
26572 
26573 
26574   // Insert the Steiner point.
26575   makepoint(&steinerpt, FREEVOLVERTEX);
26576   for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
26577 
26578   // Insert the created Steiner point.
26579   for (i = 0; i < n; i++) {
26580     infect(abtets[i]);
26581     caveoldtetlist->newindex((void **) &parytet);
26582     *parytet = abtets[i];
26583   }
26584 
26585   searchtet = abtets[0]; // No need point location.
26586   if (b->metric) {
26587     locate(steinerpt, &searchtet, 0); // For size interpolation.
26588   }
26589 
26590   delete [] abtets;
26591 
26592   ivf.iloc = (int) INSTAR;
26593   ivf.chkencflag = chkencflag;
26594   ivf.assignmeshsize = b->metric;
26595 
26596 
26597   if (insertpoint(steinerpt, &searchtet, nullptr, nullptr, &ivf)) {
26598     // The vertex has been inserted.
26599     st_volref_count++;
26600     if (steinerleft > 0) steinerleft--;
26601     return 1;
26602   } else {
26603     // The Steiner point is too close to an existing vertex. Reject it.
26604     pointdealloc(steinerpt);
26605     return 0;
26606   }
26607 }
26608 
26609 ///////////////////////////////////////////////////////////////////////////////
26610 //                                                                           //
26611 // removeslivers()    Remove slivers by adding Steiner points.               //
26612 //                                                                           //
26613 ///////////////////////////////////////////////////////////////////////////////
26614 
removeslivers(int chkencflag)26615 long tetgenmesh::removeslivers(int chkencflag)
26616 {
26617   arraypool *flipqueue, *swapqueue;
26618   badface *bface, *parybface;
26619   triface slitet, *parytet;
26620   point *ppt;
26621   REAL cosdd[6], maxcosd;
26622   long totalsptcount, sptcount;
26623   int iter, i, j, k;
26624 
26625   //assert(unflipqueue->objects > 0l);
26626   flipqueue = new arraypool(sizeof(badface), 10);
26627 
26628   // Swap the two flip queues.
26629   swapqueue = flipqueue;
26630   flipqueue = unflipqueue;
26631   unflipqueue = swapqueue;
26632 
26633   totalsptcount = 0l;
26634   iter = 0;
26635 
26636   while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
26637 
26638     sptcount = 0l;
26639 
26640     if (b->verbose > 1) {
26641       printf("    Splitting bad quality tets [%d]#:  %ld.\n",
26642              iter, flipqueue->objects);
26643     }
26644 
26645     for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
26646       bface  = (badface *) fastlookup(flipqueue, k);
26647       if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
26648                          bface->foppo, &bface->tt)) {
26649         if ((bface->key == 0) || (bface->tt.ver != 11)) {
26650           // Here we need to re-compute the quality. Since other smoothing
26651           //   operation may have moved the vertices of this tet.
26652           ppt = (point *) & (bface->tt.tet[4]);
26653           tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
26654                          &bface->key, nullptr);
26655         }
26656         if (bface->key < cosslidihed) {
26657           // It is a sliver. Try to split it.
26658           slitet.tet = bface->tt.tet;
26659           //cosdd = bface->cent;
26660           for (j = 0; j < 6; j++) {
26661             if (bface->cent[j] < cosslidihed) {
26662               // Found a large dihedral angle.
26663               slitet.ver = edge2ver[j]; // Go to the edge.
26664               if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
26665                 sptcount++;
26666                 break;
26667               }
26668             }
26669           } // j
26670           if (j < 6) {
26671             // A sliver is split. Queue new slivers.
26672             badtetrahedrons->traversalinit();
26673             parytet = (triface *) badtetrahedrons->traverse();
26674             while (parytet != nullptr) {
26675               unmarktest2(*parytet);
26676               ppt = (point *) & (parytet->tet[4]);
26677               tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
26678                              &maxcosd, nullptr);
26679               if (maxcosd < cosslidihed) {
26680                 // A new sliver. Queue it.
26681                 unflipqueue->newindex((void **) &parybface);
26682                 parybface->forg = ppt[0];
26683                 parybface->fdest = ppt[1];
26684                 parybface->fapex = ppt[2];
26685                 parybface->foppo = ppt[3];
26686                 parybface->tt.tet = parytet->tet;
26687                 parybface->tt.ver = 11;
26688                 parybface->key = maxcosd;
26689                 for (i = 0; i < 6; i++) {
26690                   parybface->cent[i] = cosdd[i];
26691                 }
26692               }
26693               parytet = (triface *) badtetrahedrons->traverse();
26694             }
26695             badtetrahedrons->restart();
26696           } else {
26697             // Didn't split. Queue it again.
26698             unflipqueue->newindex((void **) &parybface);
26699             *parybface = *bface;
26700           } // if (j == 6)
26701         } // if (bface->key < cosslidihed)
26702       } // if (gettetrahedron(...))
26703     } // k
26704 
26705     flipqueue->restart();
26706 
26707     if (b->verbose > 1) {
26708       printf("    Split %ld tets.\n", sptcount);
26709     }
26710     totalsptcount += sptcount;
26711 
26712     if (sptcount == 0l) {
26713       // No point has been smoothed.
26714       break;
26715     } else {
26716       iter++;
26717       if (iter == 2) { //if (iter >= b->optpasses) {
26718         break;
26719       }
26720     }
26721 
26722     // Swap the two flip queues.
26723     swapqueue = flipqueue;
26724     flipqueue = unflipqueue;
26725     unflipqueue = swapqueue;
26726   } // while
26727 
26728   delete flipqueue;
26729 
26730   return totalsptcount;
26731 }
26732 
26733 ///////////////////////////////////////////////////////////////////////////////
26734 //                                                                           //
26735 // optimizemesh()    Optimize mesh for specified objective functions.        //
26736 //                                                                           //
26737 ///////////////////////////////////////////////////////////////////////////////
26738 
optimizemesh()26739 void tetgenmesh::optimizemesh()
26740 {
26741   badface *parybface;
26742   triface checktet;
26743   point *ppt;
26744   int optpasses;
26745   optparameters opm;
26746   REAL ncosdd[6], maxdd;
26747   long totalremcount, remcount;
26748   long totalsmtcount, smtcount;
26749   long totalsptcount, sptcount;
26750   int chkencflag;
26751   int iter;
26752   int n;
26753 
26754   if (!b->quiet) {
26755     printf("Optimizing mesh...\n");
26756   }
26757 
26758   optpasses = ((1 << b->optlevel) - 1);
26759 
26760   if (b->verbose) {
26761     printf("  Optimization level  = %d.\n", b->optlevel);
26762     printf("  Optimization scheme = %d.\n", b->optscheme);
26763     printf("  Min_Max dihed angle = %g.\n", b->optmaxdihedral);
26764   }
26765 
26766   totalsmtcount = totalsptcount = totalremcount = 0l;
26767 
26768   cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
26769   cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
26770   cosslidihed = cos(b->optminslidihed / 180.0 * PI);
26771 
26772   int attrnum = numelemattrib - 1;
26773 
26774   // Put all bad tetrahedra into array.
26775   tetrahedrons->traversalinit();
26776   checktet.tet = tetrahedrontraverse();
26777   while (checktet.tet != nullptr) {
26778     if (b->convex) { // -c
26779       // Skip this tet if it lies in the exterior.
26780       if (elemattribute(checktet.tet, attrnum) == -1.0) {
26781         checktet.tet = tetrahedrontraverse();
26782         continue;
26783       }
26784     }
26785     ppt = (point *) & (checktet.tet[4]);
26786     tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, nullptr);
26787     if (maxdd < cosmaxdihed) {
26788       // There are bad dihedral angles in this tet.
26789       unflipqueue->newindex((void **) &parybface);
26790       parybface->tt.tet = checktet.tet;
26791       parybface->tt.ver = 11;
26792       parybface->forg = ppt[0];
26793       parybface->fdest = ppt[1];
26794       parybface->fapex = ppt[2];
26795       parybface->foppo = ppt[3];
26796       parybface->key = maxdd;
26797       for (n = 0; n < 6; n++) {
26798         parybface->cent[n] = ncosdd[n];
26799       }
26800     }
26801     checktet.tet = tetrahedrontraverse();
26802   }
26803 
26804   totalremcount = improvequalitybyflips();
26805 
26806   if ((unflipqueue->objects > 0l) &&
26807       ((b->optscheme & 2) || (b->optscheme & 4))) {
26808     // The pool is only used by removeslivers().
26809     badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
26810                                      sizeof(void *), 0);
26811 
26812     // Smoothing options.
26813     opm.min_max_dihedangle = 1;
26814     opm.numofsearchdirs = 10;
26815     // opm.searchstep = 0.001;
26816     opm.maxiter = 30; // Limit the maximum iterations.
26817     //opm.checkencflag = 4; // Queue affected tets after smoothing.
26818     chkencflag = 4; // Queue affected tets after splitting a sliver.
26819     iter = 0;
26820 
26821     while (iter < optpasses) {
26822       smtcount = sptcount = remcount = 0l;
26823       if (b->optscheme & 2) {
26824         smtcount += improvequalitybysmoothing(&opm);
26825         totalsmtcount += smtcount;
26826         if (smtcount > 0l) {
26827           remcount = improvequalitybyflips();
26828           totalremcount += remcount;
26829         }
26830       }
26831       if (unflipqueue->objects > 0l) {
26832         if (b->optscheme & 4) {
26833           sptcount += removeslivers(chkencflag);
26834           totalsptcount += sptcount;
26835           if (sptcount > 0l) {
26836             remcount = improvequalitybyflips();
26837             totalremcount += remcount;
26838           }
26839         }
26840       }
26841       if (unflipqueue->objects > 0l) {
26842         if (remcount > 0l) {
26843           iter++;
26844         } else {
26845           break;
26846         }
26847       } else {
26848         break;
26849       }
26850     } // while (iter)
26851 
26852     delete badtetrahedrons;
26853 
26854   }
26855 
26856   if (unflipqueue->objects > 0l) {
26857     if (b->verbose > 1) {
26858       printf("    %ld bad tets remained.\n", unflipqueue->objects);
26859     }
26860     unflipqueue->restart();
26861   }
26862 
26863   if (b->verbose) {
26864     if (totalremcount > 0l) {
26865       printf("  Removed %ld edges.\n", totalremcount);
26866     }
26867     if (totalsmtcount > 0l) {
26868       printf("  Smoothed %ld points.\n", totalsmtcount);
26869     }
26870     if (totalsptcount > 0l) {
26871       printf("  Split %ld slivers.\n", totalsptcount);
26872     }
26873   }
26874 }
26875 
26876 ////                                                                       ////
26877 ////                                                                       ////
26878 //// optimize_cxx /////////////////////////////////////////////////////////////
26879 
26880 //// meshstat_cxx /////////////////////////////////////////////////////////////
26881 ////                                                                       ////
26882 ////                                                                       ////
26883 
26884 ///////////////////////////////////////////////////////////////////////////////
26885 //                                                                           //
26886 // printfcomma()    Print a (large) number with the 'thousands separator'.   //
26887 //                                                                           //
26888 // The following code was simply copied from "stackoverflow".                //
26889 //                                                                           //
26890 ///////////////////////////////////////////////////////////////////////////////
26891 
printfcomma(unsigned long n)26892 void tetgenmesh::printfcomma(unsigned long n)
26893 {
26894   unsigned long n2 = 0;
26895   int scale = 1;
26896   while (n >= 1000) {
26897     n2 = n2 + scale * (n % 1000);
26898     n /= 1000;
26899     scale *= 1000;
26900   }
26901   printf ("%ld", n);
26902   while (scale != 1) {
26903     scale /= 1000;
26904     n = n2 / scale;
26905     n2 = n2  % scale;
26906     printf (",%03ld", n);
26907   }
26908 }
26909 
26910 ///////////////////////////////////////////////////////////////////////////////
26911 //                                                                           //
26912 // checkmesh()    Test the mesh for topological consistency.                 //
26913 //                                                                           //
26914 // If 'topoflag' is set, only check the topological connection of the mesh,  //
26915 // i.e., do not report degenerated or inverted elements.                     //
26916 //                                                                           //
26917 ///////////////////////////////////////////////////////////////////////////////
26918 
checkmesh(int topoflag)26919 int tetgenmesh::checkmesh(int topoflag)
26920 {
26921   triface tetloop, neightet, symtet;
26922   point pa, pb, pc, pd;
26923   REAL ori;
26924   int horrors, i;
26925 
26926   if (!b->quiet) {
26927     printf("  Checking consistency of mesh...\n");
26928   }
26929 
26930   horrors = 0;
26931   tetloop.ver = 0;
26932   // Run through the list of tetrahedra, checking each one.
26933   tetrahedrons->traversalinit();
26934   tetloop.tet = alltetrahedrontraverse();
26935   while (tetloop.tet != (tetrahedron *) nullptr) {
26936     // Check all four faces of the tetrahedron.
26937     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
26938       pa = org(tetloop);
26939       pb = dest(tetloop);
26940       pc = apex(tetloop);
26941       pd = oppo(tetloop);
26942       if (tetloop.ver == 0) {  // Only test for inversion once.
26943         if (!ishulltet(tetloop)) {  // Only do test if it is not a hull tet.
26944           if (!topoflag) {
26945             ori = orient3d(pa, pb, pc, pd);
26946             if (ori >= 0.0) {
26947               printf("  !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
26948               printf("  (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
26949                      pointmark(pb), pointmark(pc), pointmark(pd), ori);
26950               horrors++;
26951             }
26952           }
26953         }
26954         if (infected(tetloop)) {
26955           // This may be a bug. Report it.
26956           printf("  !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
26957                  pointmark(pb), pointmark(pc), pointmark(pd));
26958           horrors++;
26959         }
26960         if (marktested(tetloop)) {
26961           // This may be a bug. Report it.
26962           printf("  !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
26963                  pointmark(pb), pointmark(pc), pointmark(pd));
26964           horrors++;
26965         }
26966       }
26967       if (tetloop.tet[tetloop.ver] == nullptr) {
26968         printf("  !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
26969                pointmark(pb), pointmark(pc));
26970         horrors++;
26971       } else {
26972         // Find the neighboring tetrahedron on this face.
26973         fsym(tetloop, neightet);
26974         // Check that the tetrahedron's neighbor knows it's a neighbor.
26975         fsym(neightet, symtet);
26976         if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
26977           printf("  !! !! Asymmetric tetra-tetra bond:\n");
26978           if (tetloop.tet == symtet.tet) {
26979             printf("   (Right tetrahedron, wrong orientation)\n");
26980           }
26981           printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
26982                  pointmark(pb), pointmark(pc), pointmark(pd));
26983           printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
26984                  pointmark(dest(neightet)), pointmark(apex(neightet)),
26985                  pointmark(oppo(neightet)));
26986           horrors++;
26987         }
26988         // Check if they have the same edge (the bond() operation).
26989         if ((org(neightet) != pb) || (dest(neightet) != pa)) {
26990           printf("  !! !! Wrong edge-edge bond:\n");
26991           printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
26992                  pointmark(pb), pointmark(pc), pointmark(pd));
26993           printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
26994                  pointmark(dest(neightet)), pointmark(apex(neightet)),
26995                  pointmark(oppo(neightet)));
26996           horrors++;
26997         }
26998         // Check if they have the same apex.
26999         if (apex(neightet) != pc) {
27000           printf("  !! !! Wrong face-face bond:\n");
27001           printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
27002                  pointmark(pb), pointmark(pc), pointmark(pd));
27003           printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27004                  pointmark(dest(neightet)), pointmark(apex(neightet)),
27005                  pointmark(oppo(neightet)));
27006           horrors++;
27007         }
27008         // Check if they have the same opposite.
27009         if (oppo(neightet) == pd) {
27010           printf("  !! !! Two identical tetra:\n");
27011           printf("    First:  (%d, %d, %d, %d)\n", pointmark(pa),
27012                  pointmark(pb), pointmark(pc), pointmark(pd));
27013           printf("    Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
27014                  pointmark(dest(neightet)), pointmark(apex(neightet)),
27015                  pointmark(oppo(neightet)));
27016           horrors++;
27017         }
27018       }
27019       if (facemarked(tetloop)) {
27020         // This may be a bug. Report it.
27021         printf("  !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
27022                pointmark(pb), pointmark(pc), pointmark(pd));
27023       }
27024     }
27025     // Check the six edges of this tet.
27026     for (i = 0; i < 6; i++) {
27027       tetloop.ver = edge2ver[i];
27028       if (edgemarked(tetloop)) {
27029         // This may be a bug. Report it.
27030         printf("  !! tetedge (%d, %d) %d, %d is marked.\n",
27031                pointmark(org(tetloop)), pointmark(dest(tetloop)),
27032                pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
27033       }
27034     }
27035     tetloop.tet = alltetrahedrontraverse();
27036   }
27037   if (horrors == 0) {
27038     if (!b->quiet) {
27039       printf("  In my studied opinion, the mesh appears to be consistent.\n");
27040     }
27041   } else {
27042     printf("  !! !! !! !! %d %s witnessed.\n", horrors,
27043            horrors > 1 ? "abnormity" : "abnormities");
27044   }
27045 
27046   return horrors;
27047 }
27048 
27049 ///////////////////////////////////////////////////////////////////////////////
27050 //                                                                           //
27051 // checkshells()       Test the boundary mesh for topological consistency.   //
27052 //                                                                           //
27053 ///////////////////////////////////////////////////////////////////////////////
27054 
checkshells()27055 int tetgenmesh::checkshells()
27056 {
27057   triface neightet, symtet;
27058   face shloop, spinsh, nextsh;
27059   face checkseg;
27060   point pa, pb;
27061   int bakcount;
27062   int horrors, i;
27063 
27064   if (!b->quiet) {
27065     printf("  Checking consistency of the mesh boundary...\n");
27066   }
27067   horrors = 0;
27068 
27069   void **bakpathblock = subfaces->pathblock;
27070   void *bakpathitem = subfaces->pathitem;
27071   int bakpathitemsleft = subfaces->pathitemsleft;
27072   int bakalignbytes = subfaces->alignbytes;
27073 
27074   subfaces->traversalinit();
27075   shloop.sh = shellfacetraverse(subfaces);
27076   while (shloop.sh != nullptr) {
27077     shloop.shver = 0;
27078     for (i = 0; i < 3; i++) {
27079       // Check the face ring at this edge.
27080       pa = sorg(shloop);
27081       pb = sdest(shloop);
27082       spinsh = shloop;
27083       spivot(spinsh, nextsh);
27084       bakcount = horrors;
27085       while ((nextsh.sh != nullptr) && (nextsh.sh != shloop.sh)) {
27086         if (nextsh.sh[3] == nullptr) {
27087           printf("  !! !! Wrong subface-subface connection (Dead subface).\n");
27088           printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27089                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27090                  pointmark(sapex(spinsh)));
27091           printf("    Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
27092           horrors++;
27093           break;
27094         }
27095         // check if they have the same edge.
27096         if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
27097               ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
27098            printf("  !! !! Wrong subface-subface connection.\n");
27099            printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27100                   pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27101                   pointmark(sapex(spinsh)));
27102            printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27103                   pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27104                   pointmark(sapex(nextsh)));
27105            horrors++;
27106            break;
27107         }
27108         // Check they should not have the same apex.
27109         if (sapex(nextsh) == sapex(spinsh)) {
27110            printf("  !! !! Existing two duplicated subfaces.\n");
27111            printf("    First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27112                   pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27113                   pointmark(sapex(spinsh)));
27114            printf("    Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
27115                   pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
27116                   pointmark(sapex(nextsh)));
27117            horrors++;
27118            break;
27119         }
27120         spinsh = nextsh;
27121         spivot(spinsh, nextsh);
27122       }
27123       // Check subface-subseg bond.
27124       sspivot(shloop, checkseg);
27125       if (checkseg.sh != nullptr) {
27126         if (checkseg.sh[3] == nullptr) {
27127           printf("  !! !! Wrong subface-subseg connection (Dead subseg).\n");
27128           printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27129                  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27130                  pointmark(sapex(shloop)));
27131           printf("    Sub: x%lx (Dead)\n", (uintptr_t) checkseg.sh);
27132           horrors++;
27133         } else {
27134           if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
27135                 ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
27136             printf("  !! !! Wrong subface-subseg connection.\n");
27137             printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27138                    pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27139                    pointmark(sapex(shloop)));
27140             printf("    Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
27141                    pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
27142             horrors++;
27143           }
27144         }
27145       }
27146       if (horrors > bakcount) break; // An error detected.
27147       senextself(shloop);
27148     }
27149     // Check tet-subface connection.
27150     stpivot(shloop, neightet);
27151     if (neightet.tet != nullptr) {
27152       if (neightet.tet[4] == nullptr) {
27153         printf("  !! !! Wrong sub-to-tet connection (Dead tet)\n");
27154         printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27155                pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27156                pointmark(sapex(shloop)));
27157         printf("    Tet: x%lx (DEAD)\n", (uintptr_t) neightet.tet);
27158         horrors++;
27159       } else {
27160         if (!((sorg(shloop) == org(neightet)) &&
27161               (sdest(shloop) == dest(neightet)))) {
27162           printf("  !! !! Wrong sub-to-tet connection\n");
27163           printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
27164                  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27165                  pointmark(sapex(shloop)));
27166           printf("    Tet: x%lx (%d, %d, %d, %d).\n",
27167                  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27168                  pointmark(dest(neightet)), pointmark(apex(neightet)),
27169                  pointmark(oppo(neightet)));
27170           horrors++;
27171         }
27172         tspivot(neightet, spinsh);
27173         if (!((sorg(spinsh) == org(neightet)) &&
27174               (sdest(spinsh) == dest(neightet)))) {
27175           printf("  !! !! Wrong tet-sub connection.\n");
27176           printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27177                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27178                  pointmark(sapex(spinsh)));
27179           printf("    Tet: x%lx (%d, %d, %d, %d).\n",
27180                  (uintptr_t) neightet.tet, pointmark(org(neightet)),
27181                  pointmark(dest(neightet)), pointmark(apex(neightet)),
27182                  pointmark(oppo(neightet)));
27183           horrors++;
27184         }
27185         fsym(neightet, symtet);
27186         tspivot(symtet, spinsh);
27187         if (spinsh.sh != nullptr) {
27188           if (!((sorg(spinsh) == org(symtet)) &&
27189                 (sdest(spinsh) == dest(symtet)))) {
27190             printf("  !! !! Wrong tet-sub connection.\n");
27191             printf("    Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
27192                    pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27193                    pointmark(sapex(spinsh)));
27194             printf("    Tet: x%lx (%d, %d, %d, %d).\n",
27195                    (uintptr_t) symtet.tet, pointmark(org(symtet)),
27196                    pointmark(dest(symtet)), pointmark(apex(symtet)),
27197                    pointmark(oppo(symtet)));
27198             horrors++;
27199           }
27200         } else {
27201           printf("  Warning: Broken tet-sub-tet connection.\n");
27202         }
27203       }
27204     }
27205     if (sinfected(shloop)) {
27206       // This may be a bug. report it.
27207       printf("  !! A infected subface: (%d, %d, %d).\n",
27208              pointmark(sorg(shloop)), pointmark(sdest(shloop)),
27209              pointmark(sapex(shloop)));
27210     }
27211     if (smarktested(shloop)) {
27212       // This may be a bug. report it.
27213       printf("  !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)),
27214              pointmark(sdest(shloop)), pointmark(sapex(shloop)));
27215     }
27216     shloop.sh = shellfacetraverse(subfaces);
27217   }
27218 
27219   if (horrors == 0) {
27220     if (!b->quiet) {
27221       printf("  Mesh boundaries connected correctly.\n");
27222     }
27223   } else {
27224     printf("  !! !! !! !! %d boundary connection viewed with horror.\n",
27225            horrors);
27226   }
27227 
27228   subfaces->pathblock = bakpathblock;
27229   subfaces->pathitem = bakpathitem;
27230   subfaces->pathitemsleft = bakpathitemsleft;
27231   subfaces->alignbytes = bakalignbytes;
27232 
27233   return horrors;
27234 }
27235 
27236 ///////////////////////////////////////////////////////////////////////////////
27237 //                                                                           //
27238 // checksegments()    Check the connections between tetrahedra and segments. //
27239 //                                                                           //
27240 ///////////////////////////////////////////////////////////////////////////////
27241 
checksegments()27242 int tetgenmesh::checksegments()
27243 {
27244   triface tetloop, neightet, spintet;
27245   shellface *segs;
27246   face neighsh, spinsh, checksh;
27247   face sseg, checkseg;
27248   point pa, pb;
27249   int miscount;
27250   int t1ver;
27251   int horrors, i;
27252 
27253 
27254   if (!b->quiet) {
27255     printf("  Checking tet->seg connections...\n");
27256   }
27257 
27258   horrors = 0;
27259   tetrahedrons->traversalinit();
27260   tetloop.tet = tetrahedrontraverse();
27261   while (tetloop.tet != nullptr) {
27262     // Loop the six edges of the tet.
27263     if (tetloop.tet[8] != nullptr) {
27264       segs = (shellface *) tetloop.tet[8];
27265       for (i = 0; i < 6; i++) {
27266         sdecode(segs[i], sseg);
27267         if (sseg.sh != nullptr) {
27268           // Get the edge of the tet.
27269           tetloop.ver = edge2ver[i];
27270           // Check if they are the same edge.
27271           pa = (point) sseg.sh[3];
27272           pb = (point) sseg.sh[4];
27273           if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
27274                 ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
27275             printf("  !! Wrong tet-seg connection.\n");
27276             printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
27277                    (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
27278                    pointmark(dest(tetloop)), pointmark(apex(tetloop)),
27279                    pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
27280                    pointmark(pa), pointmark(pb));
27281             horrors++;
27282           } else {
27283             // Loop all tets sharing at this edge.
27284             neightet = tetloop;
27285             do {
27286               tsspivot1(neightet, checkseg);
27287               if (checkseg.sh != sseg.sh) {
27288                 printf("  !! Wrong tet->seg connection.\n");
27289                 printf("    Tet: x%lx (%d, %d, %d, %d) - ",
27290                        (uintptr_t) neightet.tet, pointmark(org(neightet)),
27291                        pointmark(dest(neightet)), pointmark(apex(neightet)),
27292                        pointmark(oppo(neightet)));
27293                 if (checkseg.sh != nullptr) {
27294                   printf("Seg x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
27295                          pointmark(sorg(checkseg)),pointmark(sdest(checkseg)));
27296                 } else {
27297                   printf("Seg: nullptr.\n");
27298                 }
27299                 horrors++;
27300               }
27301               fnextself(neightet);
27302             } while (neightet.tet != tetloop.tet);
27303           }
27304           // Check the seg->tet pointer.
27305           sstpivot1(sseg, neightet);
27306           if (neightet.tet == nullptr) {
27307             printf("  !! Wrong seg->tet connection (A nullptr tet).\n");
27308             horrors++;
27309           } else {
27310             if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
27311                 ((org(neightet) == pb) && (dest(neightet) == pa)))) {
27312               printf("  !! Wrong seg->tet connection (Wrong edge).\n");
27313               printf("    Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
27314                      (uintptr_t) neightet.tet, pointmark(org(neightet)),
27315                      pointmark(dest(neightet)), pointmark(apex(neightet)),
27316                      pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
27317                      pointmark(pa), pointmark(pb));
27318               horrors++;
27319             }
27320           }
27321         }
27322       }
27323     }
27324     // Loop the six edge of this tet.
27325     neightet.tet = tetloop.tet;
27326     for (i = 0; i < 6; i++) {
27327       neightet.ver = edge2ver[i];
27328       if (edgemarked(neightet)) {
27329         // A possible bug. Report it.
27330         printf("  !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
27331                pointmark(org(neightet)), pointmark(dest(neightet)),
27332                pointmark(apex(neightet)), pointmark(oppo(neightet)),
27333                (uintptr_t) neightet.tet, neightet.ver);
27334         // Check if all tets at the edge are marked.
27335         spintet = neightet;
27336         while (1) {
27337           fnextself(spintet);
27338           if (!edgemarked(spintet)) {
27339             printf("  !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
27340                    pointmark(org(spintet)), pointmark(dest(spintet)),
27341                    pointmark(apex(spintet)), pointmark(oppo(spintet)),
27342                    (uintptr_t) spintet.tet, spintet.ver);
27343             horrors++;
27344           }
27345           if (spintet.tet == neightet.tet) break;
27346         }
27347       }
27348     }
27349     tetloop.tet = tetrahedrontraverse();
27350   }
27351 
27352   if (!b->quiet) {
27353     printf("  Checking seg->tet connections...\n");
27354   }
27355 
27356   miscount = 0; // Count the number of unrecovered segments.
27357   subsegs->traversalinit();
27358   sseg.shver = 0;
27359   sseg.sh = shellfacetraverse(subsegs);
27360   while (sseg.sh != nullptr) {
27361     pa = sorg(sseg);
27362     pb = sdest(sseg);
27363     spivot(sseg, neighsh);
27364     if (neighsh.sh != nullptr) {
27365       spinsh = neighsh;
27366       while (1) {
27367         // Check seg-subface bond.
27368         if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
27369             ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
27370           // Keep the same rotate direction.
27371           //if (sorg(spinsh) != pa) {
27372           //  sesymself(spinsh);
27373           //  printf("  !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
27374           //         pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27375           //         pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27376           //         spinsh.shver);
27377           //  horrors++;
27378           //}
27379           stpivot(spinsh, spintet);
27380           if (spintet.tet != nullptr) {
27381             // Check if all tets at this segment.
27382             while (1) {
27383               tsspivot1(spintet, checkseg);
27384               if (checkseg.sh == nullptr) {
27385                 printf("  !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
27386                        pointmark(org(spintet)), pointmark(dest(spintet)),
27387                        pointmark(apex(spintet)), pointmark(oppo(spintet)),
27388                        (uintptr_t) spintet.tet, spintet.ver);
27389                 horrors++;
27390               }
27391               if (checkseg.sh != sseg.sh) {
27392                 printf("  !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
27393                        pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
27394                        pointmark(org(spintet)), pointmark(dest(spintet)),
27395                        pointmark(apex(spintet)), pointmark(oppo(spintet)));
27396                 horrors++;
27397               }
27398               fnextself(spintet);
27399               // Stop at the next subface.
27400               tspivot(spintet, checksh);
27401               if (checksh.sh != nullptr) break;
27402             } // while (1)
27403           }
27404         } else {
27405           printf("  !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
27406                  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
27407                  pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
27408                  spinsh.shver);
27409           horrors++;
27410           break;
27411         } // if pa, pb
27412         spivotself(spinsh);
27413         if (spinsh.sh == nullptr) break; // A dangling segment.
27414         if (spinsh.sh == neighsh.sh) break;
27415       } // while (1)
27416     } // if (neighsh.sh != nullptr)
27417     // Count the number of "un-recovered" segments.
27418     sstpivot1(sseg, neightet);
27419     if (neightet.tet == nullptr) {
27420       miscount++;
27421     }
27422     sseg.sh = shellfacetraverse(subsegs);
27423   }
27424 
27425   if (!b->quiet) {
27426     printf("  Checking seg->seg connections...\n");
27427   }
27428 
27429   points->traversalinit();
27430   pa = pointtraverse();
27431   while (pa != nullptr) {
27432     if (pointtype(pa) == FREESEGVERTEX) {
27433       // There should be two subsegments connected at 'pa'.
27434       // Get a subsegment containing 'pa'.
27435       sdecode(point2sh(pa), sseg);
27436       if ((sseg.sh == nullptr) || sseg.sh[3] == nullptr) {
27437         printf("  !! Dead point-to-seg pointer at point %d.\n",
27438                pointmark(pa));
27439         horrors++;
27440       } else {
27441         sseg.shver = 0;
27442         if (sorg(sseg) != pa) {
27443           if (sdest(sseg) != pa) {
27444             printf("  !! Wrong point-to-seg pointer at point %d.\n",
27445                    pointmark(pa));
27446             horrors++;
27447           } else {
27448             // Find the next subsegment at 'pa'.
27449             senext(sseg, checkseg);
27450             if ((checkseg.sh == nullptr) || (checkseg.sh[3] == nullptr)) {
27451               printf("  !! Dead seg-seg connection at point %d.\n",
27452                      pointmark(pa));
27453               horrors++;
27454             } else {
27455               spivotself(checkseg);
27456               checkseg.shver = 0;
27457               if (sorg(checkseg) != pa) {
27458                 printf("  !! Wrong seg-seg connection at point %d.\n",
27459                      pointmark(pa));
27460                 horrors++;
27461               }
27462             }
27463           }
27464         } else {
27465           // Find the previous subsegment at 'pa'.
27466           senext2(sseg, checkseg);
27467           if ((checkseg.sh == nullptr) || (checkseg.sh[3] == nullptr)) {
27468             printf("  !! Dead seg-seg connection at point %d.\n",
27469                    pointmark(pa));
27470             horrors++;
27471           } else {
27472             spivotself(checkseg);
27473             checkseg.shver = 0;
27474             if (sdest(checkseg) != pa) {
27475               printf("  !! Wrong seg-seg connection at point %d.\n",
27476                      pointmark(pa));
27477               horrors++;
27478             }
27479           }
27480         }
27481       }
27482     }
27483     pa = pointtraverse();
27484   }
27485 
27486   if (horrors == 0) {
27487     printf("  Segments are connected properly.\n");
27488   } else {
27489     printf("  !! !! !! !! Found %d missing connections.\n", horrors);
27490   }
27491   if (miscount > 0) {
27492     printf("  !! !! Found %d missing segments.\n", miscount);
27493   }
27494 
27495   return horrors;
27496 }
27497 
27498 ///////////////////////////////////////////////////////////////////////////////
27499 //                                                                           //
27500 // checkdelaunay()    Ensure that the mesh is (constrained) Delaunay.        //
27501 //                                                                           //
27502 ///////////////////////////////////////////////////////////////////////////////
27503 
checkdelaunay()27504 int tetgenmesh::checkdelaunay()
27505 {
27506   triface tetloop;
27507   triface symtet;
27508   face checksh;
27509   point pa, pb, pc, pd, pe;
27510   REAL sign;
27511   int ndcount; // Count the non-locally Delaunay faces.
27512   int horrors;
27513 
27514   if (!b->quiet) {
27515     printf("  Checking Delaunay property of the mesh...\n");
27516   }
27517 
27518   ndcount = 0;
27519   horrors = 0;
27520   tetloop.ver = 0;
27521   // Run through the list of triangles, checking each one.
27522   tetrahedrons->traversalinit();
27523   tetloop.tet = tetrahedrontraverse();
27524   while (tetloop.tet != (tetrahedron *) nullptr) {
27525     // Check all four faces of the tetrahedron.
27526     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27527       fsym(tetloop, symtet);
27528       // Only do test if its adjoining tet is not a hull tet or its pointer
27529       //   is larger (to ensure that each pair isn't tested twice).
27530       if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27531         pa = org(tetloop);
27532         pb = dest(tetloop);
27533         pc = apex(tetloop);
27534         pd = oppo(tetloop);
27535         pe = oppo(symtet);
27536         sign = insphere_s(pa, pb, pc, pd, pe);
27537         if (sign < 0.0) {
27538           ndcount++;
27539           if (checksubfaceflag) {
27540             tspivot(tetloop, checksh);
27541           }
27542           if (checksh.sh == nullptr) {
27543             printf("  !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
27544                    pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
27545                    pointmark(pe));
27546             horrors++;
27547           }
27548         }
27549       }
27550     }
27551     tetloop.tet = tetrahedrontraverse();
27552   }
27553 
27554   if (horrors == 0) {
27555     if (!b->quiet) {
27556       if (ndcount > 0) {
27557         printf("  The mesh is constrained Delaunay.\n");
27558       } else {
27559         printf("  The mesh is Delaunay.\n");
27560       }
27561     }
27562   } else {
27563     printf("  !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
27564   }
27565 
27566   return horrors;
27567 }
27568 
27569 ///////////////////////////////////////////////////////////////////////////////
27570 //                                                                           //
27571 // Check if the current tetrahedralization is (constrained) regular.         //
27572 //                                                                           //
27573 // The parameter 'type' determines which regularity should be checked:       //
27574 //   - 0:  check the Delaunay property.                                      //
27575 //   - 1:  check the Delaunay property with symbolic perturbation.           //
27576 //   - 2:  check the regular property, the weights are stored in p[3].       //
27577 //   - 3:  check the regular property with symbolic perturbation.            //
27578 //                                                                           //
27579 ///////////////////////////////////////////////////////////////////////////////
27580 
checkregular(int type)27581 int tetgenmesh::checkregular(int type)
27582 {
27583   triface tetloop;
27584   triface symtet;
27585   face checksh;
27586   point p[5];
27587   REAL sign;
27588   int ndcount; // Count the non-locally Delaunay faces.
27589   int horrors;
27590 
27591   if (!b->quiet) {
27592     printf("  Checking %s %s property of the mesh...\n",
27593            (type & 2) == 0 ? "Delaunay" : "regular",
27594            (type & 1) == 0 ? " " : "(s)");
27595   }
27596 
27597   // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
27598   //   Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
27599   //     p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
27600   //   The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
27601   //     p[4] lies below the oriented hyperplane passing through
27602   //     p[1], p[0], p[2], p[3].
27603 
27604   ndcount = 0;
27605   horrors = 0;
27606   tetloop.ver = 0;
27607   // Run through the list of triangles, checking each one.
27608   tetrahedrons->traversalinit();
27609   tetloop.tet = tetrahedrontraverse();
27610   while (tetloop.tet != (tetrahedron *) nullptr) {
27611     // Check all four faces of the tetrahedron.
27612     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
27613       fsym(tetloop, symtet);
27614       // Only do test if its adjoining tet is not a hull tet or its pointer
27615       //   is larger (to ensure that each pair isn't tested twice).
27616       if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
27617         p[0] = org(tetloop);   // pa
27618         p[1] = dest(tetloop);  // pb
27619         p[2] = apex(tetloop);  // pc
27620         p[3] = oppo(tetloop);  // pd
27621         p[4] = oppo(symtet);   // pe
27622 
27623         if (type == 0) {
27624           sign = insphere(p[1], p[0], p[2], p[3], p[4]);
27625         } else if (type == 1) {
27626           sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
27627         } else if (type == 2) {
27628           sign = orient4d(p[1],    p[0],    p[2],    p[3],    p[4],
27629                           p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27630         } else { // type == 3
27631           sign = orient4d_s(p[1],    p[0],    p[2],    p[3],    p[4],
27632                             p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
27633         }
27634 
27635         if (sign > 0.0) {
27636           ndcount++;
27637           if (checksubfaceflag) {
27638             tspivot(tetloop, checksh);
27639           }
27640           if (checksh.sh == nullptr) {
27641             printf("  !! Non-locally %s (%d, %d, %d) - %d, %d\n",
27642                    (type & 2) == 0 ? "Delaunay" : "regular",
27643                    pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
27644                    pointmark(p[3]), pointmark(p[4]));
27645             horrors++;
27646           }
27647         }
27648       }
27649     }
27650     tetloop.tet = tetrahedrontraverse();
27651   }
27652 
27653   if (horrors == 0) {
27654     if (!b->quiet) {
27655       if (ndcount > 0) {
27656         printf("  The mesh is constrained %s.\n",
27657                (type & 2) == 0 ? "Delaunay" : "regular");
27658       } else {
27659         printf("  The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
27660       }
27661     }
27662   } else {
27663     printf("  !! !! !! !! Found %d non-%s faces.\n", horrors,
27664            (type & 2) == 0 ? "Delaunay" : "regular");
27665   }
27666 
27667   return horrors;
27668 }
27669 
27670 ///////////////////////////////////////////////////////////////////////////////
27671 //                                                                           //
27672 // checkconforming()    Ensure that the mesh is conforming Delaunay.         //
27673 //                                                                           //
27674 // If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces.   //
27675 // If 'flag' is 3, check both subsegments and subfaces.                      //
27676 //                                                                           //
27677 ///////////////////////////////////////////////////////////////////////////////
27678 
checkconforming(int flag)27679 int tetgenmesh::checkconforming(int flag)
27680 {
27681   triface searchtet, neightet, spintet;
27682   face shloop;
27683   face segloop;
27684   point eorg, edest, eapex, pa, pb, pc;
27685   REAL cent[3], radius, dist, diff, rd, len;
27686   bool enq;
27687   int encsubsegs, encsubfaces;
27688   int t1ver;
27689   int i;
27690 
27691   REAL A[4][4], rhs[4], D;
27692   int indx[4];
27693   REAL elen[3];
27694 
27695   encsubsegs = 0;
27696 
27697   if (flag & 1) {
27698     if (!b->quiet) {
27699       printf("  Checking conforming property of segments...\n");
27700     }
27701     encsubsegs = 0;
27702 
27703     // Run through the list of subsegments, check each one.
27704     subsegs->traversalinit();
27705     segloop.sh = shellfacetraverse(subsegs);
27706     while (segloop.sh != (shellface *) nullptr) {
27707       eorg = (point) segloop.sh[3];
27708       edest = (point) segloop.sh[4];
27709       radius = 0.5 * distance(eorg, edest);
27710       for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
27711 
27712       enq = false;
27713       sstpivot1(segloop, neightet);
27714       if (neightet.tet != nullptr) {
27715         spintet = neightet;
27716         while (1) {
27717           eapex= apex(spintet);
27718           if (eapex != dummypoint) {
27719             dist = distance(eapex, cent);
27720             diff = dist - radius;
27721             if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
27722             if (diff < 0) {
27723               enq = true; break;
27724             }
27725           }
27726           fnextself(spintet);
27727           if (spintet.tet == neightet.tet) break;
27728         }
27729       }
27730       if (enq) {
27731         printf("  !! !! Non-conforming segment: (%d, %d)\n",
27732                pointmark(eorg), pointmark(edest));
27733         encsubsegs++;
27734       }
27735       segloop.sh = shellfacetraverse(subsegs);
27736     }
27737 
27738     if (encsubsegs == 0) {
27739       if (!b->quiet) {
27740         printf("  The segments are conforming Delaunay.\n");
27741       }
27742     } else {
27743       printf("  !! !! %d subsegments are non-conforming.\n", encsubsegs);
27744     }
27745   } // if (flag & 1)
27746 
27747   encsubfaces = 0;
27748 
27749   if (flag & 2) {
27750     if (!b->quiet) {
27751       printf("  Checking conforming property of subfaces...\n");
27752     }
27753 
27754     // Run through the list of subfaces, check each one.
27755     subfaces->traversalinit();
27756     shloop.sh = shellfacetraverse(subfaces);
27757     while (shloop.sh != (shellface *) nullptr) {
27758       pa = (point) shloop.sh[3];
27759       pb = (point) shloop.sh[4];
27760       pc = (point) shloop.sh[5];
27761 
27762       // Compute the coefficient matrix A (3x3).
27763       A[0][0] = pb[0] - pa[0];
27764       A[0][1] = pb[1] - pa[1];
27765       A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
27766       A[1][0] = pc[0] - pa[0];
27767       A[1][1] = pc[1] - pa[1];
27768       A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
27769       cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
27770 
27771       // Compute the right hand side vector b (3x1).
27772       elen[0] = dot(A[0], A[0]);
27773       elen[1] = dot(A[1], A[1]);
27774       rhs[0] = 0.5 * elen[0];
27775       rhs[1] = 0.5 * elen[1];
27776       rhs[2] = 0.0;
27777 
27778       if (lu_decmp(A, 3, indx, &D, 0)) {
27779         lu_solve(A, 3, indx, rhs, 0);
27780         cent[0] = pa[0] + rhs[0];
27781         cent[1] = pa[1] + rhs[1];
27782         cent[2] = pa[2] + rhs[2];
27783         rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
27784 
27785         // Check if this subface is encroached.
27786         for (i = 0; i < 2; i++) {
27787           stpivot(shloop, searchtet);
27788           if (!ishulltet(searchtet)) {
27789             len = distance(oppo(searchtet), cent);
27790             if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
27791             if (len < rd) {
27792               printf("  !! !! Non-conforming subface: (%d, %d, %d)\n",
27793                      pointmark(pa), pointmark(pb), pointmark(pc));
27794               encsubfaces++;
27795               enq = true; break;
27796             }
27797           }
27798           sesymself(shloop);
27799         }
27800       }
27801       shloop.sh = shellfacetraverse(subfaces);
27802     }
27803 
27804     if (encsubfaces == 0) {
27805       if (!b->quiet) {
27806         printf("  The subfaces are conforming Delaunay.\n");
27807       }
27808     } else {
27809       printf("  !! !! %d subfaces are non-conforming.\n", encsubfaces);
27810     }
27811   } // if (flag & 2)
27812 
27813   return encsubsegs + encsubfaces;
27814 }
27815 
27816 ///////////////////////////////////////////////////////////////////////////////
27817 //                                                                           //
27818 // qualitystatistics()    Print statistics about the quality of the mesh.    //
27819 //                                                                           //
27820 ///////////////////////////////////////////////////////////////////////////////
27821 
qualitystatistics()27822 void tetgenmesh::qualitystatistics()
27823 {
27824   triface tetloop, neightet;
27825   point p[4];
27826   char sbuf[128];
27827   REAL radiusratiotable[12];
27828   REAL aspectratiotable[12];
27829   REAL A[4][4], rhs[4], D;
27830   REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
27831   REAL edgelength[6], alldihed[6], faceangle[3];
27832   REAL shortest, longest;
27833   REAL smallestvolume, biggestvolume;
27834   REAL smallestratio, biggestratio;
27835   REAL smallestdiangle, biggestdiangle;
27836   REAL smallestfaangle, biggestfaangle;
27837   REAL total_tet_vol, total_tetprism_vol;
27838   REAL tetvol, minaltitude;
27839   REAL cirradius, minheightinv; // insradius;
27840   REAL shortlen, longlen;
27841   REAL tetaspect, tetradius;
27842   REAL smalldiangle, bigdiangle;
27843   REAL smallfaangle, bigfaangle;
27844   int radiustable[12];
27845   int aspecttable[16];
27846   int dihedangletable[18];
27847   int faceangletable[18];
27848   int indx[4];
27849   int radiusindex;
27850   int aspectindex;
27851   int tendegree;
27852   int i, j;
27853 
27854   printf("Mesh quality statistics:\n\n");
27855 
27856   shortlen = longlen = 0.0;
27857   smalldiangle = bigdiangle = 0.0;
27858   total_tet_vol = 0.0;
27859   total_tetprism_vol = 0.0;
27860 
27861   radiusratiotable[0]  =    0.707;    radiusratiotable[1]  =     1.0;
27862   radiusratiotable[2]  =      1.1;    radiusratiotable[3]  =     1.2;
27863   radiusratiotable[4]  =      1.4;    radiusratiotable[5]  =     1.6;
27864   radiusratiotable[6]  =      1.8;    radiusratiotable[7]  =     2.0;
27865   radiusratiotable[8]  =      2.5;    radiusratiotable[9]  =     3.0;
27866   radiusratiotable[10] =     10.0;    radiusratiotable[11] =     0.0;
27867 
27868   aspectratiotable[0]  =      1.5;    aspectratiotable[1]  =     2.0;
27869   aspectratiotable[2]  =      2.5;    aspectratiotable[3]  =     3.0;
27870   aspectratiotable[4]  =      4.0;    aspectratiotable[5]  =     6.0;
27871   aspectratiotable[6]  =     10.0;    aspectratiotable[7]  =    15.0;
27872   aspectratiotable[8]  =     25.0;    aspectratiotable[9]  =    50.0;
27873   aspectratiotable[10] =    100.0;    aspectratiotable[11] =     0.0;
27874 
27875   for (i = 0; i < 12; i++) radiustable[i] = 0;
27876   for (i = 0; i < 12; i++) aspecttable[i] = 0;
27877   for (i = 0; i < 18; i++) dihedangletable[i] = 0;
27878   for (i = 0; i < 18; i++) faceangletable[i] = 0;
27879 
27880   minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
27881   minaltitude = minaltitude * minaltitude;
27882   shortest = minaltitude;
27883   longest = 0.0;
27884   smallestvolume = minaltitude;
27885   biggestvolume = 0.0;
27886   smallestratio = 1e+16; // minaltitude;
27887   biggestratio = 0.0;
27888   smallestdiangle = smallestfaangle = 180.0;
27889   biggestdiangle = biggestfaangle = 0.0;
27890 
27891 
27892   int attrnum = numelemattrib - 1;
27893 
27894   // Loop all elements, calculate quality parameters for each element.
27895   tetrahedrons->traversalinit();
27896   tetloop.tet = tetrahedrontraverse();
27897   while (tetloop.tet != (tetrahedron *) nullptr) {
27898 
27899     if (b->convex) {
27900       // Skip tets in the exterior.
27901       if (elemattribute(tetloop.tet, attrnum) == -1.0) {
27902         tetloop.tet = tetrahedrontraverse();
27903         continue;
27904       }
27905     }
27906 
27907     // Get four vertices: p0, p1, p2, p3.
27908     for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
27909 
27910     // Get the tet volume.
27911     tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
27912     total_tet_vol += tetvol;
27913     total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
27914 
27915     // Calculate the largest and smallest volume.
27916     if (tetvol < smallestvolume) {
27917       smallestvolume = tetvol;
27918     }
27919     if (tetvol > biggestvolume) {
27920       biggestvolume = tetvol;
27921     }
27922 
27923     // Set the edge vectors: V[0], ..., V[5]
27924     for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
27925     for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
27926     for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
27927     for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
27928     for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
27929     for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
27930 
27931     // Get the squares of the edge lengthes.
27932     for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
27933 
27934     // Calculate the longest and shortest edge length.
27935     for (i = 0; i < 6; i++) {
27936       if (i == 0) {
27937         shortlen = longlen = edgelength[i];
27938       } else {
27939         shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
27940         longlen  = edgelength[i] > longlen  ? edgelength[i] : longlen;
27941       }
27942       if (edgelength[i] > longest) {
27943         longest = edgelength[i];
27944       }
27945       if (edgelength[i] < shortest) {
27946         shortest = edgelength[i];
27947       }
27948     }
27949 
27950     // Set the matrix A = [V[0], V[1], V[2]]^T.
27951     for (j = 0; j < 3; j++) {
27952       for (i = 0; i < 3; i++) A[j][i] = V[j][i];
27953     }
27954 
27955     // Decompose A just once.
27956     if (lu_decmp(A, 3, indx, &D, 0)) {
27957       // Get the three faces normals.
27958       for (j = 0; j < 3; j++) {
27959         for (i = 0; i < 3; i++) rhs[i] = 0.0;
27960         rhs[j] = 1.0;  // Positive means the inside direction
27961         lu_solve(A, 3, indx, rhs, 0);
27962         for (i = 0; i < 3; i++) N[j][i] = rhs[i];
27963       }
27964       // Get the fourth face normal by summing up the first three.
27965       for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
27966       // Get the radius of the circumsphere.
27967       for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
27968       lu_solve(A, 3, indx, rhs, 0);
27969       cirradius = sqrt(dot(rhs, rhs));
27970       // Normalize the face normals.
27971       for (i = 0; i < 4; i++) {
27972         // H[i] is the inverse of height of its corresponding face.
27973         H[i] = sqrt(dot(N[i], N[i]));
27974         for (j = 0; j < 3; j++) N[i][j] /= H[i];
27975       }
27976       // Get the radius of the inscribed sphere.
27977       // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
27978       // Get the biggest H[i] (corresponding to the smallest height).
27979       minheightinv = H[0];
27980       for (i = 1; i < 3; i++) {
27981         if (H[i] > minheightinv) minheightinv = H[i];
27982       }
27983     } else {
27984       // A nearly degenerated tet.
27985       if (tetvol <= 0.0) {
27986         // assert(tetvol != 0.0);
27987         printf("  !! Warning:  A %s tet (%d,%d,%d,%d).\n",
27988                tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
27989                pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
27990         // Skip it.
27991         tetloop.tet = tetrahedrontraverse();
27992         continue;
27993       }
27994       // Calculate the four face normals.
27995       facenormal(p[2], p[1], p[3], N[0], 1, nullptr);
27996       facenormal(p[0], p[2], p[3], N[1], 1, nullptr);
27997       facenormal(p[1], p[0], p[3], N[2], 1, nullptr);
27998       facenormal(p[0], p[1], p[2], N[3], 1, nullptr);
27999       // Normalize the face normals.
28000       for (i = 0; i < 4; i++) {
28001         // H[i] is the twice of the area of the face.
28002         H[i] = sqrt(dot(N[i], N[i]));
28003         for (j = 0; j < 3; j++) N[i][j] /= H[i];
28004       }
28005       // Get the biggest H[i] / tetvol (corresponding to the smallest height).
28006       minheightinv = (H[0] / tetvol);
28007       for (i = 1; i < 3; i++) {
28008         if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
28009       }
28010       // Let the circumradius to be the half of its longest edge length.
28011       cirradius = 0.5 * sqrt(longlen);
28012     }
28013 
28014     // Get the dihedrals (in degree) at each edges.
28015     j = 0;
28016     for (i = 1; i < 4; i++) {
28017       alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
28018       if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28019       else if (alldihed[j] > 1.0) alldihed[j] = 1;
28020       alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28021       j++;
28022     }
28023     for (i = 2; i < 4; i++) {
28024       alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
28025       if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28026       else if (alldihed[j] > 1.0) alldihed[j] = 1;
28027       alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28028       j++;
28029     }
28030     alldihed[j] = -dot(N[2], N[3]); // Edge ab.
28031     if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
28032     else if (alldihed[j] > 1.0) alldihed[j] = 1;
28033     alldihed[j] = acos(alldihed[j]) / PI * 180.0;
28034 
28035     // Calculate the largest and smallest dihedral angles.
28036     for (i = 0; i < 6; i++) {
28037       if (i == 0) {
28038         smalldiangle = bigdiangle = alldihed[i];
28039       } else {
28040         smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
28041         bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
28042       }
28043       if (alldihed[i] < smallestdiangle) {
28044         smallestdiangle = alldihed[i];
28045       }
28046       if (alldihed[i] > biggestdiangle) {
28047         biggestdiangle = alldihed[i];
28048       }
28049       // Accumulate the corresponding number in the dihedral angle histogram.
28050       if (alldihed[i] < 5.0) {
28051         tendegree = 0;
28052       } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
28053         tendegree = 1;
28054       } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
28055         tendegree = 9; // Angles between 80 to 110 degree are in one entry.
28056       } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
28057         tendegree = 16;
28058       } else if (alldihed[i] >= 175.0) {
28059         tendegree = 17;
28060       } else {
28061         tendegree = (int) (alldihed[i] / 10.);
28062         if (alldihed[i] < 80.0) {
28063           tendegree++;  // In the left column.
28064         } else {
28065           tendegree--;  // In the right column.
28066         }
28067       }
28068       dihedangletable[tendegree]++;
28069     }
28070 
28071 
28072 
28073     // Calulate the largest and smallest face angles.
28074     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28075       fsym(tetloop, neightet);
28076       // Only do the calulation once for a face.
28077       if (((point) neightet.tet[7] == dummypoint) ||
28078           (tetloop.tet < neightet.tet)) {
28079         p[0] = org(tetloop);
28080         p[1] = dest(tetloop);
28081         p[2] = apex(tetloop);
28082         faceangle[0] = interiorangle(p[0], p[1], p[2], nullptr);
28083         faceangle[1] = interiorangle(p[1], p[2], p[0], nullptr);
28084         faceangle[2] = PI - (faceangle[0] + faceangle[1]);
28085         // Translate angles into degrees.
28086         for (i = 0; i < 3; i++) {
28087           faceangle[i] = (faceangle[i] * 180.0) / PI;
28088         }
28089         // Calculate the largest and smallest face angles.
28090         for (i = 0; i < 3; i++) {
28091           if (i == 0) {
28092             smallfaangle = bigfaangle = faceangle[i];
28093           } else {
28094             smallfaangle = faceangle[i] < smallfaangle ?
28095               faceangle[i] : smallfaangle;
28096             bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
28097           }
28098           if (faceangle[i] < smallestfaangle) {
28099             smallestfaangle = faceangle[i];
28100           }
28101           if (faceangle[i] > biggestfaangle) {
28102             biggestfaangle = faceangle[i];
28103           }
28104           tendegree = (int) (faceangle[i] / 10.);
28105           faceangletable[tendegree]++;
28106         }
28107       }
28108     }
28109 
28110     // Calculate aspect ratio and radius-edge ratio for this element.
28111     tetradius = cirradius / sqrt(shortlen);
28112     // tetaspect = sqrt(longlen) / (2.0 * insradius);
28113     tetaspect = sqrt(longlen) * minheightinv;
28114     // Remember the largest and smallest aspect ratio.
28115     if (tetaspect < smallestratio) {
28116       smallestratio = tetaspect;
28117     }
28118     if (tetaspect > biggestratio) {
28119       biggestratio = tetaspect;
28120     }
28121     // Accumulate the corresponding number in the aspect ratio histogram.
28122     aspectindex = 0;
28123     while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
28124       aspectindex++;
28125     }
28126     aspecttable[aspectindex]++;
28127     radiusindex = 0;
28128     while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
28129       radiusindex++;
28130     }
28131     radiustable[radiusindex]++;
28132 
28133     tetloop.tet = tetrahedrontraverse();
28134   }
28135 
28136   shortest = sqrt(shortest);
28137   longest = sqrt(longest);
28138   minaltitude = sqrt(minaltitude);
28139 
28140   printf("  Smallest volume: %16.5g   |  Largest volume: %16.5g\n",
28141          smallestvolume, biggestvolume);
28142   printf("  Shortest edge:   %16.5g   |  Longest edge:   %16.5g\n",
28143          shortest, longest);
28144   printf("  Smallest asp.ratio: %13.5g   |  Largest asp.ratio: %13.5g\n",
28145          smallestratio, biggestratio);
28146   sprintf(sbuf, "%.17g", biggestfaangle);
28147   if (strlen(sbuf) > 8) {
28148     sbuf[8] = '\0';
28149   }
28150   printf("  Smallest facangle: %14.5g   |  Largest facangle:       %s\n",
28151          smallestfaangle, sbuf);
28152   sprintf(sbuf, "%.17g", biggestdiangle);
28153   if (strlen(sbuf) > 8) {
28154     sbuf[8] = '\0';
28155   }
28156   printf("  Smallest dihedral: %14.5g   |  Largest dihedral:       %s\n\n",
28157          smallestdiangle, sbuf);
28158 
28159   printf("  Aspect ratio histogram:\n");
28160   printf("         < %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
28161          aspectratiotable[0], aspecttable[0], aspectratiotable[5],
28162          aspectratiotable[6], aspecttable[6]);
28163   for (i = 1; i < 5; i++) {
28164     printf("  %6.6g - %-6.6g    :  %8d      | %6.6g - %-6.6g     :  %8d\n",
28165            aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
28166            aspectratiotable[i + 5], aspectratiotable[i + 6],
28167            aspecttable[i + 6]);
28168   }
28169   printf("  %6.6g - %-6.6g    :  %8d      | %6.6g -            :  %8d\n",
28170          aspectratiotable[4], aspectratiotable[5], aspecttable[5],
28171          aspectratiotable[10], aspecttable[11]);
28172   printf("  (A tetrahedron's aspect ratio is its longest edge length");
28173   printf(" divided by its\n");
28174   printf("    smallest side height)\n\n");
28175 
28176   printf("  Face angle histogram:\n");
28177   for (i = 0; i < 9; i++) {
28178     printf("    %3d - %3d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28179            i * 10, i * 10 + 10, faceangletable[i],
28180            i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
28181   }
28182   if (minfaceang != PI) {
28183     printf("  Minimum input face angle is %g (degree).\n",
28184            minfaceang / PI * 180.0);
28185   }
28186   printf("\n");
28187 
28188   printf("  Dihedral angle histogram:\n");
28189   // Print the three two rows:
28190   printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28191          0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
28192   printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28193          5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
28194   // Print the third to seventh rows.
28195   for (i = 2; i < 7; i++) {
28196     printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28197            (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
28198            (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
28199   }
28200   // Print the last two rows.
28201   printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28202          60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
28203   printf("     %3d - %2d degrees:  %8d      |    %3d - %3d degrees:  %8d\n",
28204          70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
28205   if (minfacetdihed != PI) {
28206     printf("  Minimum input dihedral angle is %g (degree).\n",
28207            minfacetdihed / PI * 180.0);
28208   }
28209   printf("\n");
28210 
28211   printf("\n");
28212 }
28213 
28214 
28215 ///////////////////////////////////////////////////////////////////////////////
28216 //                                                                           //
28217 // memorystatistics()    Report the memory usage.                            //
28218 //                                                                           //
28219 ///////////////////////////////////////////////////////////////////////////////
28220 
memorystatistics()28221 void tetgenmesh::memorystatistics()
28222 {
28223   printf("Memory usage statistics:\n\n");
28224 
28225   // Count the number of blocks of tetrahedra.
28226   int tetblocks = 0;
28227   tetrahedrons->pathblock = tetrahedrons->firstblock;
28228   while (tetrahedrons->pathblock != nullptr) {
28229     tetblocks++;
28230     tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);
28231   }
28232 
28233   // Calculate the total memory (in bytes) used by storing meshes.
28234   unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
28235   totalmeshmemory = points->maxitems * points->itembytes +
28236                     tetrahedrons->maxitems * tetrahedrons->itembytes;
28237   if (b->plc || b->refine) {
28238     totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
28239                         subsegs->maxitems * subsegs->itembytes);
28240     totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
28241                        tet2segpool->maxitems * tet2segpool->itembytes);
28242   }
28243 
28244   unsigned long totalalgomemory = 0l;
28245   totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
28246                     caveoldtetlist->totalmemory +
28247                     flippool->maxitems * flippool->itembytes;
28248   if (b->plc || b->refine) {
28249     totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
28250                         subvertstack->totalmemory +
28251                         caveshlist->totalmemory + caveshbdlist->totalmemory +
28252                         cavesegshlist->totalmemory +
28253                         cavetetshlist->totalmemory +
28254                         cavetetseglist->totalmemory +
28255                         caveencshlist->totalmemory +
28256                         caveencseglist->totalmemory +
28257                         cavetetvertlist->totalmemory +
28258                         unflipqueue->totalmemory);
28259   }
28260 
28261   printf("  Maximum number of tetrahedra:  %ld\n", tetrahedrons->maxitems);
28262   printf("  Maximum number of tet blocks (blocksize = %d):  %d\n",
28263          b->tetrahedraperblock, tetblocks);
28264   /*
28265   if (b->plc || b->refine) {
28266     printf("  Approximate memory for tetrahedral mesh (bytes):  %ld\n",
28267            totalmeshmemory);
28268 
28269     printf("  Approximate memory for extra pointers (bytes):  %ld\n",
28270            totalt2shmemory);
28271   } else {
28272     printf("  Approximate memory for tetrahedralization (bytes):  %ld\n",
28273            totalmeshmemory);
28274   }
28275   printf("  Approximate memory for algorithms (bytes):  %ld\n",
28276          totalalgomemory);
28277   printf("  Approximate memory for working arrays (bytes):  %ld\n",
28278          totalworkmemory);
28279   printf("  Approximate total used memory (bytes):  %ld\n",
28280          totalmeshmemory + totalt2shmemory + totalalgomemory +
28281          totalworkmemory);
28282   */
28283   if (b->plc || b->refine) {
28284     printf("  Approximate memory for tetrahedral mesh (bytes):  ");
28285     printfcomma(totalmeshmemory); printf("\n");
28286 
28287     printf("  Approximate memory for extra pointers (bytes):  ");
28288     printfcomma(totalt2shmemory); printf("\n");
28289   } else {
28290     printf("  Approximate memory for tetrahedralization (bytes):  ");
28291     printfcomma(totalmeshmemory); printf("\n");
28292   }
28293   printf("  Approximate memory for algorithms (bytes):  ");
28294   printfcomma(totalalgomemory); printf("\n");
28295   printf("  Approximate memory for working arrays (bytes):  ");
28296   printfcomma(totalworkmemory); printf("\n");
28297   printf("  Approximate total used memory (bytes):  ");
28298   printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory +
28299               totalworkmemory);
28300   printf("\n");
28301 
28302   printf("\n");
28303 }
28304 
28305 ///////////////////////////////////////////////////////////////////////////////
28306 //                                                                           //
28307 // statistics()    Print all sorts of cool facts.                            //
28308 //                                                                           //
28309 ///////////////////////////////////////////////////////////////////////////////
28310 
statistics()28311 void tetgenmesh::statistics()
28312 {
28313   long tetnumber, facenumber;
28314 
28315   printf("\nStatistics:\n\n");
28316   printf("  Input points: %d\n", in->numberofpoints);
28317   if (b->refine) {
28318     printf("  Input tetrahedra: %d\n", in->numberoftetrahedra);
28319   }
28320   if (b->plc) {
28321     printf("  Input facets: %d\n", in->numberoffacets);
28322     printf("  Input segments: %ld\n", insegments);
28323     printf("  Input holes: %d\n", in->numberofholes);
28324     printf("  Input regions: %d\n", in->numberofregions);
28325   }
28326 
28327   tetnumber = tetrahedrons->items - hullsize;
28328   facenumber = (tetnumber * 4l + hullsize) / 2l;
28329 
28330   if (b->weighted) { // -w option
28331     printf("\n  Mesh points: %ld\n", points->items - nonregularcount);
28332   } else {
28333     printf("\n  Mesh points: %ld\n", points->items);
28334   }
28335   printf("  Mesh tetrahedra: %ld\n", tetnumber);
28336   printf("  Mesh faces: %ld\n", facenumber);
28337   if (meshedges > 0l) {
28338     printf("  Mesh edges: %ld\n", meshedges);
28339   } else {
28340     if (!nonconvex) {
28341       long vsize = points->items - dupverts - unuverts;
28342       if (b->weighted) vsize -= nonregularcount;
28343       meshedges = vsize + facenumber - tetnumber - 1;
28344       printf("  Mesh edges: %ld\n", meshedges);
28345     }
28346   }
28347 
28348   if (b->plc || b->refine) {
28349     printf("  Mesh boundary faces: %ld\n", subfaces->items);
28350     printf("  Mesh boundary edges: %ld\n", subsegs->items);
28351     if (st_segref_count > 0l) {
28352       printf("  Steiner points on boundary edges:  %ld\n", st_segref_count);
28353     }
28354     if (st_facref_count > 0l) {
28355       printf("  Steiner points on boundary faces:  %ld\n", st_facref_count);
28356     }
28357     if (st_volref_count > 0l) {
28358       printf("  Steiner points inside mesh domain: %ld\n", st_volref_count);
28359     }
28360   } else {
28361     printf("  Convex hull faces: %ld\n", hullsize);
28362     if (meshhulledges > 0l) {
28363       printf("  Convex hull edges: %ld\n", meshhulledges);
28364     }
28365   }
28366   if (b->weighted) { // -w option
28367     printf("  Skipped non-regular points: %ld\n", nonregularcount);
28368   }
28369   printf("\n");
28370 
28371 
28372   if (b->verbose > 0) {
28373     if (b->plc || b->refine) { // -p or -r
28374       if (tetrahedrons->items > 0l) {
28375         qualitystatistics();
28376       }
28377     }
28378     if (tetrahedrons->items > 0l) {
28379       memorystatistics();
28380     }
28381   }
28382 }
28383 
28384 ////                                                                       ////
28385 ////                                                                       ////
28386 //// meshstat_cxx /////////////////////////////////////////////////////////////
28387 
28388 //// output_cxx ///////////////////////////////////////////////////////////////
28389 ////                                                                       ////
28390 ////                                                                       ////
28391 
28392 ///////////////////////////////////////////////////////////////////////////////
28393 //                                                                           //
28394 // jettisonnodes()    Jettison unused or duplicated vertices.                //
28395 //                                                                           //
28396 // Unused points are those input points which are outside the mesh domain or //
28397 // have no connection (isolated) to the mesh.  Duplicated points exist for   //
28398 // example if the input PLC is read from a .stl mesh file (marked during the //
28399 // Delaunay tetrahedralization step. This routine remove these points from   //
28400 // points list. All existing points are reindexed.                           //
28401 //                                                                           //
28402 ///////////////////////////////////////////////////////////////////////////////
28403 
jettisonnodes()28404 void tetgenmesh::jettisonnodes()
28405 {
28406   point pointloop;
28407   bool jetflag;
28408   int oldidx, newidx;
28409   int remcount;
28410 
28411   if (!b->quiet) {
28412     printf("Jettisoning redundants points.\n");
28413   }
28414 
28415   points->traversalinit();
28416   pointloop = pointtraverse();
28417   oldidx = newidx = 0; // in->firstnumber;
28418   remcount = 0;
28419   while (pointloop != (point) nullptr) {
28420     jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
28421       (pointtype(pointloop) == UNUSEDVERTEX);
28422     if (jetflag) {
28423       // It is a duplicated or unused point, delete it.
28424       pointdealloc(pointloop);
28425       remcount++;
28426     } else {
28427       // Re-index it.
28428       setpointmark(pointloop, newidx + in->firstnumber);
28429       if (in->pointmarkerlist != (int *) nullptr) {
28430         if (oldidx < in->numberofpoints) {
28431           // Re-index the point marker as well.
28432           in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
28433         }
28434       }
28435       newidx++;
28436     }
28437     oldidx++;
28438     pointloop = pointtraverse();
28439   }
28440   if (b->verbose) {
28441     printf("  %ld duplicated vertices are removed.\n", dupverts);
28442     printf("  %ld unused vertices are removed.\n", unuverts);
28443   }
28444   dupverts = 0l;
28445   unuverts = 0l;
28446 
28447   // The following line ensures that dead items in the pool of nodes cannot
28448   //   be allocated for the new created nodes. This ensures that the input
28449   //   nodes will occur earlier in the output files, and have lower indices.
28450   points->deaditemstack = (void *) nullptr;
28451 }
28452 
28453 ///////////////////////////////////////////////////////////////////////////////
28454 //                                                                           //
28455 // highorder()   Create extra nodes for quadratic subparametric elements.    //
28456 //                                                                           //
28457 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing  //
28458 // high-order nodes of each tetrahedron.  This routine is used only when -o2 //
28459 // switch is used.                                                           //
28460 //                                                                           //
28461 ///////////////////////////////////////////////////////////////////////////////
28462 
highorder()28463 void tetgenmesh::highorder()
28464 {
28465   triface tetloop, worktet, spintet;
28466   point *extralist, *adjextralist;
28467   point torg, tdest, newpoint;
28468   int highorderindex;
28469   int t1ver;
28470   int i, j;
28471 
28472   if (!b->quiet) {
28473     printf("Adding vertices for second-order tetrahedra.\n");
28474   }
28475 
28476   // Initialize the 'highordertable'.
28477   highordertable = new point[tetrahedrons->items * 6];
28478   if (highordertable == (point *) nullptr) {
28479     terminatetetgen(1);
28480   }
28481 
28482   // This will overwrite the slot for element markers.
28483   highorderindex = 11;
28484 
28485   // The following line ensures that dead items in the pool of nodes cannot
28486   //   be allocated for the extra nodes associated with high order elements.
28487   //   This ensures that the primary nodes (at the corners of elements) will
28488   //   occur earlier in the output files, and have lower indices, than the
28489   //   extra nodes.
28490   points->deaditemstack = (void *) nullptr;
28491 
28492   // Assign an entry for each tetrahedron to find its extra nodes. At the
28493   //   mean while, initialize all extra nodes be nullptr.
28494   i = 0;
28495   tetrahedrons->traversalinit();
28496   tetloop.tet = tetrahedrontraverse();
28497   while (tetloop.tet != (tetrahedron *) nullptr) {
28498     tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
28499     for (j = 0; j < 6; j++) {
28500       highordertable[i + j] = (point) nullptr;
28501     }
28502     i += 6;
28503     tetloop.tet = tetrahedrontraverse();
28504   }
28505 
28506   // To create a unique node on each edge. Loop over all tetrahedra, and
28507   //   look at the six edges of each tetrahedron.  If the extra node in
28508   //   the tetrahedron corresponding to this edge is nullptr, create a node
28509   //   for this edge, at the same time, set the new node into the extra
28510   //   node lists of all other tetrahedra sharing this edge.
28511   tetrahedrons->traversalinit();
28512   tetloop.tet = tetrahedrontraverse();
28513   while (tetloop.tet != (tetrahedron *) nullptr) {
28514     // Get the list of extra nodes.
28515     extralist = (point *) tetloop.tet[highorderindex];
28516     worktet.tet = tetloop.tet;
28517     for (i = 0; i < 6; i++) {
28518       if (extralist[i] == (point) nullptr) {
28519         // Go to the ith-edge.
28520         worktet.ver = edge2ver[i];
28521         // Create a new point in the middle of this edge.
28522         torg = org(worktet);
28523         tdest = dest(worktet);
28524         makepoint(&newpoint, FREEVOLVERTEX);
28525         for (j = 0; j < 3 + numpointattrib; j++) {
28526           newpoint[j] = 0.5 * (torg[j] + tdest[j]);
28527         }
28528         // Interpolate its metrics.
28529         for (j = 0; j < in->numberofpointmtrs; j++) {
28530           newpoint[pointmtrindex + j] =
28531             0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
28532         }
28533         // Set this point into all extra node lists at this edge.
28534         spintet = worktet;
28535         while (1) {
28536           if (!ishulltet(spintet)) {
28537             adjextralist = (point *) spintet.tet[highorderindex];
28538             adjextralist[ver2edge[spintet.ver]] = newpoint;
28539           }
28540           fnextself(spintet);
28541           if (spintet.tet == worktet.tet) break;
28542         }
28543       } // if (!extralist[i])
28544     } // i
28545     tetloop.tet = tetrahedrontraverse();
28546   }
28547 }
28548 
28549 ///////////////////////////////////////////////////////////////////////////////
28550 //                                                                           //
28551 // numberedges()    Count the number of edges, save in "meshedges".          //
28552 //                                                                           //
28553 // This routine is called when '-p' or '-r', and '-E' options are used.  The //
28554 // total number of edges depends on the genus of the input surface mesh.     //
28555 //                                                                           //
28556 // NOTE:  This routine must be called after outelements().  So all elements  //
28557 // have been indexed.                                                        //
28558 //                                                                           //
28559 ///////////////////////////////////////////////////////////////////////////////
28560 
numberedges()28561 void tetgenmesh::numberedges()
28562 {
28563   triface worktet, spintet;
28564   int ishulledge;
28565   int t1ver;
28566   int i;
28567 
28568   meshedges = meshhulledges = 0l;
28569 
28570   tetrahedrons->traversalinit();
28571   worktet.tet = tetrahedrontraverse();
28572   while (worktet.tet != nullptr) {
28573     // Count the number of Voronoi faces. Look at the six edges of this
28574     //   tet. Count an edge only if this tet's index is smaller than
28575     //   those of other non-hull tets which share this edge.
28576     for (i = 0; i < 6; i++) {
28577       worktet.ver = edge2ver[i];
28578       ishulledge = 0;
28579       fnext(worktet, spintet);
28580       do {
28581         if (!ishulltet(spintet)) {
28582           if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
28583         } else {
28584           ishulledge = 1;
28585         }
28586         fnextself(spintet);
28587       } while (spintet.tet != worktet.tet);
28588       // Count this edge if no adjacent tets are smaller than this tet.
28589       if (spintet.tet == worktet.tet) {
28590         meshedges++;
28591         if (ishulledge) meshhulledges++;
28592       }
28593     }
28594     worktet.tet = tetrahedrontraverse();
28595   }
28596 }
28597 
28598 ///////////////////////////////////////////////////////////////////////////////
28599 //                                                                           //
28600 // outnodes()    Output the points to a .node file or a tetgenio structure.  //
28601 //                                                                           //
28602 // Note: each point has already been numbered on input (the first index is   //
28603 // 'in->firstnumber').                                                       //
28604 //                                                                           //
28605 ///////////////////////////////////////////////////////////////////////////////
28606 
outnodes(tetgenio * out)28607 void tetgenmesh::outnodes(tetgenio* out)
28608 {
28609   FILE *outfile = nullptr;
28610   char outnodefilename[FILENAMESIZE];
28611   face parentsh;
28612   point pointloop;
28613   int nextras, bmark, marker = 0, weightDT = 0;
28614   int coordindex, attribindex;
28615   int pointnumber, firstindex;
28616   int index, i;
28617 
28618   if (out == (tetgenio *) nullptr) {
28619     strcpy(outnodefilename, b->outfilename);
28620     strcat(outnodefilename, ".node");
28621   }
28622 
28623   if (!b->quiet) {
28624     if (out == (tetgenio *) nullptr) {
28625       printf("Writing %s.\n", outnodefilename);
28626     } else {
28627       printf("Writing nodes.\n");
28628     }
28629   }
28630 
28631   nextras = numpointattrib;
28632   if (b->weighted) { // -w
28633     if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
28634   }
28635 
28636   bmark = !b->nobound && in->pointmarkerlist;
28637 
28638   if (out == (tetgenio *) nullptr) {
28639     outfile = fopen(outnodefilename, "w");
28640     if (outfile == (FILE *) nullptr) {
28641       printf("File I/O Error:  Cannot create file %s.\n", outnodefilename);
28642       terminatetetgen(1);
28643     }
28644     // Number of points, number of dimensions, number of point attributes,
28645     //   and number of boundary markers (zero or one).
28646     fprintf(outfile, "%ld  %d  %d  %d\n", points->items, 3, nextras, bmark);
28647   } else {
28648     // Allocate space for 'pointlist';
28649     out->pointlist = new REAL[points->items * 3];
28650     if (out->pointlist == (REAL *) nullptr) {
28651       printf("Error:  Out of memory.\n");
28652       terminatetetgen(1);
28653     }
28654     // Allocate space for 'pointattributelist' if necessary;
28655     if (nextras > 0) {
28656       out->pointattributelist = new REAL[points->items * nextras];
28657       if (out->pointattributelist == (REAL *) nullptr) {
28658         printf("Error:  Out of memory.\n");
28659         terminatetetgen(1);
28660       }
28661     }
28662     // Allocate space for 'pointmarkerlist' if necessary;
28663     if (bmark) {
28664       out->pointmarkerlist = new int[points->items];
28665       if (out->pointmarkerlist == (int *) nullptr) {
28666         printf("Error:  Out of memory.\n");
28667         terminatetetgen(1);
28668       }
28669     }
28670     if (b->psc) {
28671       out->pointparamlist = new tetgenio::pointparam[points->items];
28672       if (out->pointparamlist == nullptr) {
28673         printf("Error:  Out of memory.\n");
28674         terminatetetgen(1);
28675       }
28676     }
28677     out->numberofpoints = points->items;
28678     out->numberofpointattributes = nextras;
28679     coordindex = 0;
28680     attribindex = 0;
28681   }
28682 
28683   // Determine the first index (0 or 1).
28684   firstindex = b->zeroindex ? 0 : in->firstnumber;
28685 
28686   points->traversalinit();
28687   pointloop = pointtraverse();
28688   pointnumber = firstindex; // in->firstnumber;
28689   index = 0;
28690   while (pointloop != (point) nullptr) {
28691     if (bmark) {
28692       // Default the vertex has a zero marker.
28693       marker = 0;
28694       // Is it an input vertex?
28695       if (index < in->numberofpoints) {
28696         // Input point's marker is directly copied to output.
28697         marker = in->pointmarkerlist[index];
28698       } else {
28699         if ((pointtype(pointloop) == FREESEGVERTEX) ||
28700             (pointtype(pointloop) == FREEFACETVERTEX)) {
28701           sdecode(point2sh(pointloop), parentsh);
28702           if (parentsh.sh != nullptr) {
28703             marker = shellmark(parentsh);
28704             if (pointtype(pointloop) == FREEFACETVERTEX) {
28705               if (in->facetmarkerlist != nullptr) {
28706                 marker = in->facetmarkerlist[marker - 1];
28707               }
28708             }
28709           }
28710         } // if (pointtype(...))
28711       }
28712     }
28713     if (out == (tetgenio *) nullptr) {
28714       // Point number, x, y and z coordinates.
28715       fprintf(outfile, "%4d    %.17g  %.17g  %.17g", pointnumber,
28716               pointloop[0], pointloop[1], pointloop[2]);
28717       for (i = 0; i < nextras; i++) {
28718         // Write an attribute.
28719         if ((i == 0) && weightDT) {
28720           fprintf(outfile, "  %.17g", pointloop[0] * pointloop[0] +
28721              pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2]
28722              - pointloop[3 + i]);
28723         } else {
28724           fprintf(outfile, "  %.17g", pointloop[3 + i]);
28725         }
28726       }
28727       if (bmark) {
28728         // Write the boundary marker.
28729         fprintf(outfile, "    %d", marker);
28730       }
28731       if (b->psc) {
28732         fprintf(outfile, "  %.8g  %.8g  %d", pointgeomuv(pointloop, 0),
28733                 pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
28734         if (pointtype(pointloop) == RIDGEVERTEX) {
28735           fprintf(outfile, "  0");
28736         } else if (pointtype(pointloop) == ACUTEVERTEX) {
28737           fprintf(outfile, "  0");
28738         } else if (pointtype(pointloop) == FREESEGVERTEX) {
28739           fprintf(outfile, "  1");
28740         } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28741           fprintf(outfile, "  2");
28742         } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28743           fprintf(outfile, "  3");
28744         } else {
28745           fprintf(outfile, "  -1"); // Unknown type.
28746         }
28747       }
28748       fprintf(outfile, "\n");
28749     } else {
28750       // X, y, and z coordinates.
28751       out->pointlist[coordindex++] = pointloop[0];
28752       out->pointlist[coordindex++] = pointloop[1];
28753       out->pointlist[coordindex++] = pointloop[2];
28754       // Point attributes.
28755       for (i = 0; i < nextras; i++) {
28756         // Output an attribute.
28757         if ((i == 0) && weightDT) {
28758           out->pointattributelist[attribindex++] =
28759             pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] +
28760             pointloop[2] * pointloop[2] - pointloop[3 + i];
28761         } else {
28762           out->pointattributelist[attribindex++] = pointloop[3 + i];
28763         }
28764       }
28765       if (bmark) {
28766         // Output the boundary marker.
28767         out->pointmarkerlist[index] = marker;
28768       }
28769       if (b->psc) {
28770         out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
28771         out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
28772         out->pointparamlist[index].tag = pointgeomtag(pointloop);
28773         if (pointtype(pointloop) == RIDGEVERTEX) {
28774           out->pointparamlist[index].type = 0;
28775         } else if (pointtype(pointloop) == ACUTEVERTEX) {
28776           out->pointparamlist[index].type = 0;
28777         } else if (pointtype(pointloop) == FREESEGVERTEX) {
28778           out->pointparamlist[index].type = 1;
28779         } else if (pointtype(pointloop) == FREEFACETVERTEX) {
28780           out->pointparamlist[index].type = 2;
28781         } else if (pointtype(pointloop) == FREEVOLVERTEX) {
28782           out->pointparamlist[index].type = 3;
28783         } else {
28784           out->pointparamlist[index].type = -1; // Unknown type.
28785         }
28786       }
28787     }
28788     pointloop = pointtraverse();
28789     pointnumber++;
28790     index++;
28791   }
28792 
28793   if (out == (tetgenio *) nullptr) {
28794     fprintf(outfile, "# Generated by %s\n", b->commandline);
28795     fclose(outfile);
28796   }
28797 }
28798 
28799 ///////////////////////////////////////////////////////////////////////////////
28800 //                                                                           //
28801 // outmetrics()    Output the metric to a file (*.mtr) or a tetgenio obj.    //
28802 //                                                                           //
28803 ///////////////////////////////////////////////////////////////////////////////
28804 
outmetrics(tetgenio * out)28805 void tetgenmesh::outmetrics(tetgenio* out)
28806 {
28807   FILE *outfile = nullptr;
28808   char outmtrfilename[FILENAMESIZE];
28809   point ptloop;
28810   int mtrindex;
28811 
28812   if (out == (tetgenio *) nullptr) {
28813     strcpy(outmtrfilename, b->outfilename);
28814     strcat(outmtrfilename, ".mtr");
28815   }
28816 
28817   if (!b->quiet) {
28818     if (out == (tetgenio *) nullptr) {
28819       printf("Writing %s.\n", outmtrfilename);
28820     } else {
28821       printf("Writing metrics.\n");
28822     }
28823   }
28824 
28825   if (out == (tetgenio *) nullptr) {
28826     outfile = fopen(outmtrfilename, "w");
28827     if (outfile == (FILE *) nullptr) {
28828       printf("File I/O Error:  Cannot create file %s.\n", outmtrfilename);
28829       terminatetetgen(3);
28830     }
28831     // Number of points, number of point metrices,
28832     // fprintf(outfile, "%ld  %d\n", points->items, sizeoftensor + 3);
28833     fprintf(outfile, "%ld  %d\n", points->items, 1);
28834   } else {
28835     // Allocate space for 'pointmtrlist' if necessary;
28836     // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)];
28837     out->pointmtrlist = new REAL[points->items];
28838     if (out->pointmtrlist == (REAL *) nullptr) {
28839       terminatetetgen(1);
28840     }
28841     out->numberofpointmtrs = 1; // (sizeoftensor + 3);
28842     mtrindex = 0;
28843   }
28844 
28845   points->traversalinit();
28846   ptloop = pointtraverse();
28847   while (ptloop != (point) nullptr) {
28848     if (out == (tetgenio *) nullptr) {
28849       // for (i = 0; i < sizeoftensor; i++) {
28850       //   fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]);
28851       // }
28852       fprintf(outfile, "%-16.8e\n", ptloop[pointmtrindex]);
28853     } else {
28854       // for (i = 0; i < sizeoftensor; i++) {
28855       //   out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
28856       // }
28857       out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex];
28858     }
28859     ptloop = pointtraverse();
28860   }
28861 
28862   if (out == (tetgenio *) nullptr) {
28863     fprintf(outfile, "# Generated by %s\n", b->commandline);
28864     fclose(outfile);
28865   }
28866 }
28867 
28868 ///////////////////////////////////////////////////////////////////////////////
28869 //                                                                           //
28870 // outelements()    Output the tetrahedra to an .ele file or a tetgenio      //
28871 //                  structure.                                               //
28872 //                                                                           //
28873 // This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
28874 // firstnumber). The total number of mesh edges is counted in 'meshedges'.   //
28875 //                                                                           //
28876 ///////////////////////////////////////////////////////////////////////////////
28877 
outelements(tetgenio * out)28878 void tetgenmesh::outelements(tetgenio* out)
28879 {
28880   FILE *outfile = nullptr;
28881   char outelefilename[FILENAMESIZE];
28882   tetrahedron* tptr;
28883   point p1, p2, p3, p4;
28884   point *extralist;
28885   REAL *talist = nullptr;
28886   int *tlist = nullptr;
28887   long ntets;
28888   int firstindex, shift;
28889   int pointindex, attribindex;
28890   int highorderindex = 11;
28891   int elementnumber;
28892   int eextras;
28893   int i;
28894 
28895   if (out == (tetgenio *) nullptr) {
28896     strcpy(outelefilename, b->outfilename);
28897     strcat(outelefilename, ".ele");
28898   }
28899 
28900   if (!b->quiet) {
28901     if (out == (tetgenio *) nullptr) {
28902       printf("Writing %s.\n", outelefilename);
28903     } else {
28904       printf("Writing elements.\n");
28905     }
28906   }
28907 
28908   // The number of tets excluding hull tets.
28909   ntets = tetrahedrons->items - hullsize;
28910 
28911   eextras = numelemattrib;
28912   if (out == (tetgenio *) nullptr) {
28913     outfile = fopen(outelefilename, "w");
28914     if (outfile == (FILE *) nullptr) {
28915       printf("File I/O Error:  Cannot create file %s.\n", outelefilename);
28916       terminatetetgen(1);
28917     }
28918     // Number of tetras, points per tetra, attributes per tetra.
28919     fprintf(outfile, "%ld  %d  %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
28920   } else {
28921     // Allocate memory for output tetrahedra.
28922     out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
28923     if (out->tetrahedronlist == (int *) nullptr) {
28924       printf("Error:  Out of memory.\n");
28925       terminatetetgen(1);
28926     }
28927     // Allocate memory for output tetrahedron attributes if necessary.
28928     if (eextras > 0) {
28929       out->tetrahedronattributelist = new REAL[ntets * eextras];
28930       if (out->tetrahedronattributelist == (REAL *) nullptr) {
28931         printf("Error:  Out of memory.\n");
28932         terminatetetgen(1);
28933       }
28934     }
28935     out->numberoftetrahedra = ntets;
28936     out->numberofcorners = b->order == 1 ? 4 : 10;
28937     out->numberoftetrahedronattributes = eextras;
28938     tlist = out->tetrahedronlist;
28939     talist = out->tetrahedronattributelist;
28940     pointindex = 0;
28941     attribindex = 0;
28942   }
28943 
28944   // Determine the first index (0 or 1).
28945   firstindex = b->zeroindex ? 0 : in->firstnumber;
28946   shift = 0; // Default no shiftment.
28947   if ((in->firstnumber == 1) && (firstindex == 0)) {
28948     shift = 1; // Shift the output indices by 1.
28949   }
28950 
28951   tetrahedrons->traversalinit();
28952   tptr = tetrahedrontraverse();
28953   elementnumber = firstindex; // in->firstnumber;
28954   while (tptr != (tetrahedron *) nullptr) {
28955     if (!b->reversetetori) {
28956       p1 = (point) tptr[4];
28957       p2 = (point) tptr[5];
28958     } else {
28959       p1 = (point) tptr[5];
28960       p2 = (point) tptr[4];
28961     }
28962     p3 = (point) tptr[6];
28963     p4 = (point) tptr[7];
28964     if (out == (tetgenio *) nullptr) {
28965       // Tetrahedron number, indices for four points.
28966       fprintf(outfile, "%5d   %5d %5d %5d %5d", elementnumber,
28967               pointmark(p1) - shift, pointmark(p2) - shift,
28968               pointmark(p3) - shift, pointmark(p4) - shift);
28969       if (b->order == 2) {
28970         extralist = (point *) tptr[highorderindex];
28971         // indices for six extra points.
28972         fprintf(outfile, "  %5d %5d %5d %5d %5d %5d",
28973           pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
28974           pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
28975           pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
28976       }
28977       for (i = 0; i < eextras; i++) {
28978         fprintf(outfile, "    %.17g", elemattribute(tptr, i));
28979       }
28980       fprintf(outfile, "\n");
28981     } else {
28982       tlist[pointindex++] = pointmark(p1) - shift;
28983       tlist[pointindex++] = pointmark(p2) - shift;
28984       tlist[pointindex++] = pointmark(p3) - shift;
28985       tlist[pointindex++] = pointmark(p4) - shift;
28986       if (b->order == 2) {
28987         extralist = (point *) tptr[highorderindex];
28988         tlist[pointindex++] = pointmark(extralist[0]) - shift;
28989         tlist[pointindex++] = pointmark(extralist[1]) - shift;
28990         tlist[pointindex++] = pointmark(extralist[2]) - shift;
28991         tlist[pointindex++] = pointmark(extralist[3]) - shift;
28992         tlist[pointindex++] = pointmark(extralist[4]) - shift;
28993         tlist[pointindex++] = pointmark(extralist[5]) - shift;
28994       }
28995       for (i = 0; i < eextras; i++) {
28996         talist[attribindex++] = elemattribute(tptr, i);
28997       }
28998     }
28999     // Remember the index of this element (for counting edges).
29000     setelemindex(tptr, elementnumber);
29001     tptr = tetrahedrontraverse();
29002     elementnumber++;
29003   }
29004 
29005 
29006   if (out == (tetgenio *) nullptr) {
29007     fprintf(outfile, "# Generated by %s\n", b->commandline);
29008     fclose(outfile);
29009   }
29010 }
29011 
29012 ///////////////////////////////////////////////////////////////////////////////
29013 //                                                                           //
29014 // outfaces()    Output all faces to a .face file or a tetgenio object.      //
29015 //                                                                           //
29016 ///////////////////////////////////////////////////////////////////////////////
29017 
outfaces(tetgenio * out)29018 void tetgenmesh::outfaces(tetgenio* out)
29019 {
29020   FILE *outfile = nullptr;
29021   char facefilename[FILENAMESIZE];
29022   triface tface, tsymface;
29023   face checkmark;
29024   point torg, tdest, tapex;
29025   long ntets, faces;
29026   int *elist = nullptr, *emlist = nullptr;
29027   int neigh1 = 0, neigh2 = 0;
29028   int faceid, marker = 0;
29029   int firstindex, shift;
29030   int facenumber;
29031   int index = 0;
29032 
29033   // For -o2 option.
29034   triface workface;
29035   point *extralist, pp[3] = {0,0,0};
29036   int highorderindex = 11;
29037   int o2index = 0, i;
29038 
29039   if (out == (tetgenio *) nullptr) {
29040     strcpy(facefilename, b->outfilename);
29041     strcat(facefilename, ".face");
29042   }
29043 
29044   if (!b->quiet) {
29045     if (out == (tetgenio *) nullptr) {
29046       printf("Writing %s.\n", facefilename);
29047     } else {
29048       printf("Writing faces.\n");
29049     }
29050   }
29051 
29052   ntets = tetrahedrons->items - hullsize;
29053   faces = (ntets * 4l + hullsize) / 2l;
29054 
29055   if (out == (tetgenio *) nullptr) {
29056     outfile = fopen(facefilename, "w");
29057     if (outfile == (FILE *) nullptr) {
29058       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
29059       terminatetetgen(1);
29060     }
29061     fprintf(outfile, "%ld  %d\n", faces, !b->nobound);
29062   } else {
29063     // Allocate memory for 'trifacelist'.
29064     out->trifacelist = new int[faces * 3];
29065     if (out->trifacelist == (int *) nullptr) {
29066       printf("Error:  Out of memory.\n");
29067       terminatetetgen(1);
29068     }
29069     if (b->order == 2) {
29070       out->o2facelist = new int[faces * 3];
29071     }
29072     // Allocate memory for 'trifacemarkerlist' if necessary.
29073     if (!b->nobound) {
29074       out->trifacemarkerlist = new int[faces];
29075       if (out->trifacemarkerlist == (int *) nullptr) {
29076         printf("Error:  Out of memory.\n");
29077         terminatetetgen(1);
29078       }
29079     }
29080     if (b->neighout > 1) {
29081       // '-nn' switch.
29082       out->adjtetlist = new int[faces * 2];
29083       if (out->adjtetlist == (int *) nullptr) {
29084         printf("Error:  Out of memory.\n");
29085         terminatetetgen(1);
29086       }
29087     }
29088     out->numberoftrifaces = faces;
29089     elist = out->trifacelist;
29090     emlist = out->trifacemarkerlist;
29091   }
29092 
29093   // Determine the first index (0 or 1).
29094   firstindex = b->zeroindex ? 0 : in->firstnumber;
29095   shift = 0; // Default no shiftment.
29096   if ((in->firstnumber == 1) && (firstindex == 0)) {
29097     shift = 1; // Shift the output indices by 1.
29098   }
29099 
29100   tetrahedrons->traversalinit();
29101   tface.tet = tetrahedrontraverse();
29102   facenumber = firstindex; // in->firstnumber;
29103   // To loop over the set of faces, loop over all tetrahedra, and look at
29104   //   the four faces of each one. If its adjacent tet is a hull tet,
29105   //   operate on the face, otherwise, operate on the face only if the
29106   //   current tet has a smaller index than its neighbor.
29107   while (tface.tet != (tetrahedron *) nullptr) {
29108     for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
29109       fsym(tface, tsymface);
29110       if (ishulltet(tsymface) ||
29111           (elemindex(tface.tet) < elemindex(tsymface.tet))) {
29112         torg = org(tface);
29113         tdest = dest(tface);
29114         tapex = apex(tface);
29115         if (b->order == 2) { // -o2
29116           // Get the three extra vertices on edges.
29117           extralist = (point *) (tface.tet[highorderindex]);
29118           // The extra vertices are on edges opposite the corners.
29119           enext(tface, workface);
29120           for (i = 0; i < 3; i++) {
29121             pp[i] = extralist[ver2edge[workface.ver]];
29122             enextself(workface);
29123           }
29124         }
29125         if (!b->nobound) {
29126           // Get the boundary marker of this face.
29127           if (b->plc || b->refine) {
29128             // Shell face is used.
29129             tspivot(tface, checkmark);
29130             if (checkmark.sh == nullptr) {
29131               marker = 0;  // It is an inner face. It's marker is 0.
29132             } else {
29133               if (in->facetmarkerlist) {
29134                 // The facet marker is given, get it.
29135                 faceid = shellmark(checkmark) - 1;
29136                 marker = in->facetmarkerlist[faceid];
29137               } else {
29138                 marker = 1; // The default marker for subface is 1.
29139               }
29140             }
29141           } else {
29142             // Shell face is not used, only distinguish outer and inner face.
29143             marker = (int) ishulltet(tsymface);
29144           }
29145         }
29146         if (b->neighout > 1) {
29147           // '-nn' switch. Output adjacent tets indices.
29148           neigh1 = elemindex(tface.tet);
29149           if (!ishulltet(tsymface)) {
29150             neigh2 = elemindex(tsymface.tet);
29151           } else {
29152             neigh2 = -1;
29153           }
29154         }
29155         if (out == (tetgenio *) nullptr) {
29156           // Face number, indices of three vertices.
29157           fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
29158                   pointmark(torg) - shift, pointmark(tdest) - shift,
29159                   pointmark(tapex) - shift);
29160           if (b->order == 2) { // -o2
29161             fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift,
29162                     pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29163           }
29164           if (!b->nobound) {
29165             // Output a boundary marker.
29166             fprintf(outfile, "  %d", marker);
29167           }
29168           if (b->neighout > 1) {
29169             fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
29170           }
29171           fprintf(outfile, "\n");
29172         } else {
29173           // Output indices of three vertices.
29174           elist[index++] = pointmark(torg) - shift;
29175           elist[index++] = pointmark(tdest) - shift;
29176           elist[index++] = pointmark(tapex) - shift;
29177           if (b->order == 2) { // -o2
29178             out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29179             out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29180             out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29181           }
29182           if (!b->nobound) {
29183             emlist[facenumber - in->firstnumber] = marker;
29184           }
29185           if (b->neighout > 1) {
29186             out->adjtetlist[(facenumber - in->firstnumber) * 2]     = neigh1;
29187             out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
29188           }
29189         }
29190         facenumber++;
29191       }
29192     }
29193     tface.tet = tetrahedrontraverse();
29194   }
29195 
29196   if (out == (tetgenio *) nullptr) {
29197     fprintf(outfile, "# Generated by %s\n", b->commandline);
29198     fclose(outfile);
29199   }
29200 }
29201 
29202 ///////////////////////////////////////////////////////////////////////////////
29203 //                                                                           //
29204 // outhullfaces()    Output hull faces to a .face file or a tetgenio object. //
29205 //                                                                           //
29206 // The normal of each face is pointing to the outside of the domain.         //
29207 //                                                                           //
29208 ///////////////////////////////////////////////////////////////////////////////
29209 
outhullfaces(tetgenio * out)29210 void tetgenmesh::outhullfaces(tetgenio* out)
29211 {
29212   FILE *outfile = nullptr;
29213   char facefilename[FILENAMESIZE];
29214   triface hulltet;
29215   point torg, tdest, tapex;
29216   int *elist = nullptr;
29217   int firstindex, shift;
29218   int facenumber;
29219   int index;
29220 
29221   if (out == (tetgenio *) nullptr) {
29222     strcpy(facefilename, b->outfilename);
29223     strcat(facefilename, ".face");
29224   }
29225 
29226   if (!b->quiet) {
29227     if (out == (tetgenio *) nullptr) {
29228       printf("Writing %s.\n", facefilename);
29229     } else {
29230       printf("Writing faces.\n");
29231     }
29232   }
29233 
29234   if (out == (tetgenio *) nullptr) {
29235     outfile = fopen(facefilename, "w");
29236     if (outfile == (FILE *) nullptr) {
29237       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
29238       terminatetetgen(1);
29239     }
29240     fprintf(outfile, "%ld  0\n", hullsize);
29241   } else {
29242     // Allocate memory for 'trifacelist'.
29243     out->trifacelist = new int[hullsize * 3];
29244     if (out->trifacelist == (int *) nullptr) {
29245       printf("Error:  Out of memory.\n");
29246       terminatetetgen(1);
29247     }
29248     out->numberoftrifaces = hullsize;
29249     elist = out->trifacelist;
29250     index = 0;
29251   }
29252 
29253   // Determine the first index (0 or 1).
29254   firstindex = b->zeroindex ? 0 : in->firstnumber;
29255   shift = 0; // Default no shiftment.
29256   if ((in->firstnumber == 1) && (firstindex == 0)) {
29257     shift = 1; // Shift the output indices by 1.
29258   }
29259 
29260   tetrahedrons->traversalinit();
29261   hulltet.tet = alltetrahedrontraverse();
29262   facenumber = firstindex;
29263   while (hulltet.tet != (tetrahedron *) nullptr) {
29264     if (ishulltet(hulltet)) {
29265       torg = (point) hulltet.tet[4];
29266       tdest = (point) hulltet.tet[5];
29267       tapex = (point) hulltet.tet[6];
29268       if (out == (tetgenio *) nullptr) {
29269         // Face number, indices of three vertices.
29270         fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
29271                 pointmark(torg) - shift, pointmark(tdest) - shift,
29272                 pointmark(tapex) - shift);
29273         fprintf(outfile, "\n");
29274       } else {
29275         // Output indices of three vertices.
29276         elist[index++] = pointmark(torg) - shift;
29277         elist[index++] = pointmark(tdest) - shift;
29278         elist[index++] = pointmark(tapex) - shift;
29279       }
29280       facenumber++;
29281     }
29282     hulltet.tet = alltetrahedrontraverse();
29283   }
29284 
29285   if (out == (tetgenio *) nullptr) {
29286     fprintf(outfile, "# Generated by %s\n", b->commandline);
29287     fclose(outfile);
29288   }
29289 }
29290 
29291 ///////////////////////////////////////////////////////////////////////////////
29292 //                                                                           //
29293 // outsubfaces()    Output subfaces (i.e. boundary faces) to a .face file or //
29294 //                  a tetgenio structure.                                    //
29295 //                                                                           //
29296 // The boundary faces are found in 'subfaces'. For listing triangle vertices //
29297 // in the same sense for all triangles in the mesh, the direction determined //
29298 // by right-hand rule is pointer to the inside of the volume.                //
29299 //                                                                           //
29300 ///////////////////////////////////////////////////////////////////////////////
29301 
outsubfaces(tetgenio * out)29302 void tetgenmesh::outsubfaces(tetgenio* out)
29303 {
29304   FILE *outfile = nullptr;
29305   char facefilename[FILENAMESIZE];
29306   int *elist = nullptr;
29307   int *emlist = nullptr;
29308   int index = 0, index1 = 0, index2 = 0;
29309   triface abuttingtet;
29310   face faceloop;
29311   point torg, tdest, tapex;
29312   int faceid = 0, marker = 0;
29313   int firstindex, shift;
29314   int neigh1 = 0, neigh2 = 0;
29315   int facenumber;
29316 
29317   // For -o2 option.
29318   triface workface;
29319   point *extralist, pp[3] = {0,0,0};
29320   int highorderindex = 11;
29321   int o2index = 0, i;
29322 
29323   int t1ver; // used by fsymself()
29324 
29325   if (out == (tetgenio *) nullptr) {
29326     strcpy(facefilename, b->outfilename);
29327     strcat(facefilename, ".face");
29328   }
29329 
29330   if (!b->quiet) {
29331     if (out == (tetgenio *) nullptr) {
29332       printf("Writing %s.\n", facefilename);
29333     } else {
29334       printf("Writing faces.\n");
29335     }
29336   }
29337 
29338   if (out == (tetgenio *) nullptr) {
29339     outfile = fopen(facefilename, "w");
29340     if (outfile == (FILE *) nullptr) {
29341       printf("File I/O Error:  Cannot create file %s.\n", facefilename);
29342       terminatetetgen(3);
29343     }
29344     // Number of subfaces.
29345     fprintf(outfile, "%ld  %d\n", subfaces->items, !b->nobound);
29346   } else {
29347     // Allocate memory for 'trifacelist'.
29348     out->trifacelist = new int[subfaces->items * 3];
29349     if (out->trifacelist == (int *) nullptr) {
29350       terminatetetgen(1);
29351     }
29352     if (b->order == 2) {
29353       out->o2facelist = new int[subfaces->items * 3];
29354     }
29355     if (!b->nobound) {
29356       // Allocate memory for 'trifacemarkerlist'.
29357       out->trifacemarkerlist = new int[subfaces->items];
29358       if (out->trifacemarkerlist == (int *) nullptr) {
29359         terminatetetgen(1);
29360       }
29361     }
29362     if (b->neighout > 1) {
29363       // '-nn' switch.
29364       out->adjtetlist = new int[subfaces->items * 2];
29365       if (out->adjtetlist == (int *) nullptr) {
29366         terminatetetgen(1);
29367       }
29368     }
29369     out->numberoftrifaces = subfaces->items;
29370     elist = out->trifacelist;
29371     emlist = out->trifacemarkerlist;
29372   }
29373 
29374   // Determine the first index (0 or 1).
29375   firstindex = b->zeroindex ? 0 : in->firstnumber;
29376   shift = 0; // Default no shiftment.
29377   if ((in->firstnumber == 1) && (firstindex == 0)) {
29378     shift = 1; // Shift the output indices by 1.
29379   }
29380 
29381   subfaces->traversalinit();
29382   faceloop.sh = shellfacetraverse(subfaces);
29383   facenumber = firstindex; // in->firstnumber;
29384   while (faceloop.sh != (shellface *) nullptr) {
29385     stpivot(faceloop, abuttingtet);
29386     // If there is a tetrahedron containing this subface, orient it so
29387     //   that the normal of this face points to inside of the volume by
29388     //   right-hand rule.
29389     if (abuttingtet.tet != nullptr) {
29390       if (ishulltet(abuttingtet)) {
29391         fsymself(abuttingtet);
29392         assert(!ishulltet(abuttingtet));
29393       }
29394     }
29395     if (abuttingtet.tet != nullptr) {
29396       torg = org(abuttingtet);
29397       tdest = dest(abuttingtet);
29398       tapex = apex(abuttingtet);
29399       if (b->order == 2) { // -o2
29400         // Get the three extra vertices on edges.
29401         extralist = (point *) (abuttingtet.tet[highorderindex]);
29402         workface = abuttingtet;
29403         for (i = 0; i < 3; i++) {
29404           pp[i] = extralist[ver2edge[workface.ver]];
29405           enextself(workface);
29406         }
29407       }
29408     } else {
29409       // This may happen when only a surface mesh be generated.
29410       torg = sorg(faceloop);
29411       tdest = sdest(faceloop);
29412       tapex = sapex(faceloop);
29413       if (b->order == 2) { // -o2
29414         // There is no extra node list available.
29415         pp[0] = torg;
29416         pp[1] = tdest;
29417         pp[2] = tapex;
29418       }
29419     }
29420     if (!b->nobound) {
29421       if (in->facetmarkerlist) {
29422         faceid = shellmark(faceloop) - 1;
29423         marker = in->facetmarkerlist[faceid];
29424       } else {
29425         marker = 1; // Default marker for a subface is 1.
29426       }
29427     }
29428     if (b->neighout > 1) {
29429       // '-nn' switch. Output adjacent tets indices.
29430       neigh1 = -1;
29431       neigh2 = -1;
29432       stpivot(faceloop, abuttingtet);
29433       if (abuttingtet.tet != nullptr) {
29434         neigh1 = elemindex(abuttingtet.tet);
29435         fsymself(abuttingtet);
29436         if (!ishulltet(abuttingtet)) {
29437           neigh2 = elemindex(abuttingtet.tet);
29438         }
29439       }
29440     }
29441     if (out == (tetgenio *) nullptr) {
29442       fprintf(outfile, "%5d   %4d  %4d  %4d", facenumber,
29443               pointmark(torg) - shift, pointmark(tdest) - shift,
29444               pointmark(tapex) - shift);
29445       if (b->order == 2) { // -o2
29446         fprintf(outfile, "  %4d  %4d  %4d", pointmark(pp[0]) - shift,
29447                 pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
29448       }
29449       if (!b->nobound) {
29450         fprintf(outfile, "    %d", marker);
29451       }
29452       if (b->neighout > 1) {
29453         fprintf(outfile, "    %5d  %5d", neigh1, neigh2);
29454       }
29455       fprintf(outfile, "\n");
29456     } else {
29457       // Output three vertices of this face;
29458       elist[index++] = pointmark(torg) - shift;
29459       elist[index++] = pointmark(tdest) - shift;
29460       elist[index++] = pointmark(tapex) - shift;
29461       if (b->order == 2) { // -o2
29462         out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
29463         out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
29464         out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
29465       }
29466       if (!b->nobound) {
29467         emlist[index1++] = marker;
29468       }
29469       if (b->neighout > 1) {
29470         out->adjtetlist[index2++] = neigh1;
29471         out->adjtetlist[index2++] = neigh2;
29472       }
29473     }
29474     facenumber++;
29475     faceloop.sh = shellfacetraverse(subfaces);
29476   }
29477 
29478   if (out == (tetgenio *) nullptr) {
29479     fprintf(outfile, "# Generated by %s\n", b->commandline);
29480     fclose(outfile);
29481   }
29482 }
29483 
29484 ///////////////////////////////////////////////////////////////////////////////
29485 //                                                                           //
29486 // outedges()    Output all edges to a .edge file or a tetgenio object.      //
29487 //                                                                           //
29488 // Note: This routine must be called after outelements(),  so that the total //
29489 // number of edges 'meshedges' has been counted.                             //
29490 //                                                                           //
29491 ///////////////////////////////////////////////////////////////////////////////
29492 
outedges(tetgenio * out)29493 void tetgenmesh::outedges(tetgenio* out)
29494 {
29495   FILE *outfile = nullptr;
29496   char edgefilename[FILENAMESIZE];
29497   triface tetloop, worktet, spintet;
29498   face checkseg;
29499   point torg, tdest;
29500   int *elist = nullptr, *emlist = nullptr;
29501   int ishulledge;
29502   int firstindex, shift;
29503   int edgenumber, marker;
29504   int index = 0, index1 = 0, index2 = 0;
29505   int t1ver;
29506   int i;
29507 
29508   // For -o2 option.
29509   point *extralist, pp = nullptr;
29510   int highorderindex = 11;
29511   int o2index = 0;
29512 
29513   if (out == (tetgenio *) nullptr) {
29514     strcpy(edgefilename, b->outfilename);
29515     strcat(edgefilename, ".edge");
29516   }
29517 
29518   if (!b->quiet) {
29519     if (out == (tetgenio *) nullptr) {
29520       printf("Writing %s.\n", edgefilename);
29521     } else {
29522       printf("Writing edges.\n");
29523     }
29524   }
29525 
29526   if (meshedges == 0l) {
29527     if (nonconvex) {
29528       numberedges();  // Count the edges.
29529     } else {
29530       // Use Euler's characteristic to get the numbe of edges.
29531       // It states V - E + F - C = 1, hence E = V + F - C - 1.
29532       long tsize = tetrahedrons->items - hullsize;
29533       long fsize = (tsize * 4l + hullsize) / 2l;
29534       long vsize = points->items - dupverts - unuverts;
29535       if (b->weighted) vsize -= nonregularcount;
29536       meshedges = vsize + fsize - tsize - 1;
29537     }
29538   }
29539 
29540   if (out == (tetgenio *) nullptr) {
29541     outfile = fopen(edgefilename, "w");
29542     if (outfile == (FILE *) nullptr) {
29543       printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
29544       terminatetetgen(1);
29545     }
29546     // Write the number of edges, boundary markers (0 or 1).
29547     fprintf(outfile, "%ld  %d\n", meshedges, !b->nobound);
29548   } else {
29549     // Allocate memory for 'edgelist'.
29550     out->edgelist = new int[meshedges * 2];
29551     if (out->edgelist == (int *) nullptr) {
29552       printf("Error:  Out of memory.\n");
29553       terminatetetgen(1);
29554     }
29555     if (b->order == 2) { // -o2 switch
29556       out->o2edgelist = new int[meshedges];
29557     }
29558     if (!b->nobound) {
29559       out->edgemarkerlist = new int[meshedges];
29560     }
29561     if (b->neighout > 1) { // '-nn' switch.
29562       out->edgeadjtetlist = new int[meshedges];
29563     }
29564     out->numberofedges = meshedges;
29565     elist = out->edgelist;
29566     emlist = out->edgemarkerlist;
29567   }
29568 
29569   // Determine the first index (0 or 1).
29570   firstindex = b->zeroindex ? 0 : in->firstnumber;
29571   shift = 0; // Default no shiftment.
29572   if ((in->firstnumber == 1) && (firstindex == 0)) {
29573     shift = 1; // Shift (reduce) the output indices by 1.
29574   }
29575 
29576   tetrahedrons->traversalinit();
29577   tetloop.tet = tetrahedrontraverse();
29578   edgenumber = firstindex; // in->firstnumber;
29579   while (tetloop.tet != (tetrahedron *) nullptr) {
29580     // Count the number of Voronoi faces.
29581     worktet.tet = tetloop.tet;
29582     for (i = 0; i < 6; i++) {
29583       worktet.ver = edge2ver[i];
29584       ishulledge = 0;
29585       fnext(worktet, spintet);
29586       do {
29587         if (!ishulltet(spintet)) {
29588           if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
29589         } else {
29590           ishulledge = 1;
29591         }
29592         fnextself(spintet);
29593       } while (spintet.tet != worktet.tet);
29594       // Count this edge if no adjacent tets are smaller than this tet.
29595       if (spintet.tet == worktet.tet) {
29596         torg = org(worktet);
29597         tdest = dest(worktet);
29598         if (b->order == 2) { // -o2
29599           // Get the extra vertex on this edge.
29600           extralist = (point *) worktet.tet[highorderindex];
29601           pp = extralist[ver2edge[worktet.ver]];
29602         }
29603         if (out == (tetgenio *) nullptr) {
29604           fprintf(outfile, "%5d   %4d  %4d", edgenumber,
29605                   pointmark(torg) - shift, pointmark(tdest) - shift);
29606           if (b->order == 2) { // -o2
29607             fprintf(outfile, "  %4d", pointmark(pp) - shift);
29608           }
29609         } else {
29610           // Output three vertices of this face;
29611           elist[index++] = pointmark(torg) - shift;
29612           elist[index++] = pointmark(tdest) - shift;
29613           if (b->order == 2) { // -o2
29614             out->o2edgelist[o2index++] = pointmark(pp) - shift;
29615           }
29616         }
29617         if (!b->nobound) {
29618           if (b->plc || b->refine) {
29619             // Check if the edge is a segment.
29620             tsspivot1(worktet, checkseg);
29621             if (checkseg.sh != nullptr) {
29622               marker = shellmark(checkseg);
29623               if (marker == 0) {  // Does it have no marker?
29624                 marker = 1;  // Set the default marker for this segment.
29625               }
29626             } else {
29627               marker = 0;  // It's not a segment.
29628             }
29629           } else {
29630             // Mark it if it is a hull edge.
29631             marker = ishulledge ? 1 : 0;
29632           }
29633           if (out == (tetgenio *) nullptr) {
29634             fprintf(outfile, "  %d", marker);
29635           } else {
29636             emlist[index1++] = marker;
29637           }
29638         }
29639         if (b->neighout > 1) { // '-nn' switch.
29640           if (out == (tetgenio *) nullptr) {
29641             fprintf(outfile, "  %d", elemindex(tetloop.tet));
29642           } else {
29643             out->edgeadjtetlist[index2++] = elemindex(tetloop.tet);
29644           }
29645         }
29646         if (out == (tetgenio *) nullptr) {
29647           fprintf(outfile, "\n");
29648         }
29649         edgenumber++;
29650       }
29651     }
29652     tetloop.tet = tetrahedrontraverse();
29653   }
29654 
29655   if (out == (tetgenio *) nullptr) {
29656     fprintf(outfile, "# Generated by %s\n", b->commandline);
29657     fclose(outfile);
29658   }
29659 }
29660 
29661 ///////////////////////////////////////////////////////////////////////////////
29662 //                                                                           //
29663 // outsubsegments()    Output segments to a .edge file or a structure.       //
29664 //                                                                           //
29665 ///////////////////////////////////////////////////////////////////////////////
29666 
outsubsegments(tetgenio * out)29667 void tetgenmesh::outsubsegments(tetgenio* out)
29668 {
29669   FILE *outfile = nullptr;
29670   char edgefilename[FILENAMESIZE];
29671   int *elist = nullptr;
29672   int index, i;
29673   face edgeloop;
29674   point torg, tdest;
29675   int firstindex, shift;
29676   int marker;
29677   int edgenumber;
29678 
29679   // For -o2 option.
29680   triface workface, spintet;
29681   point *extralist, pp = nullptr;
29682   int highorderindex = 11;
29683   int o2index = 0;
29684 
29685   // For -nn option.
29686   int neigh = -1;
29687   int index2 = 0;
29688 
29689   int t1ver; // used by fsymself()
29690 
29691   if (out == (tetgenio *) nullptr) {
29692     strcpy(edgefilename, b->outfilename);
29693     strcat(edgefilename, ".edge");
29694   }
29695 
29696   if (!b->quiet) {
29697     if (out == (tetgenio *) nullptr) {
29698       printf("Writing %s.\n", edgefilename);
29699     } else {
29700       printf("Writing edges.\n");
29701     }
29702   }
29703 
29704   if (out == (tetgenio *) nullptr) {
29705     outfile = fopen(edgefilename, "w");
29706     if (outfile == (FILE *) nullptr) {
29707       printf("File I/O Error:  Cannot create file %s.\n", edgefilename);
29708       terminatetetgen(3);
29709     }
29710     // Number of subsegments.
29711     fprintf(outfile, "%ld  1\n", subsegs->items);
29712   } else {
29713     // Allocate memory for 'edgelist'.
29714     out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
29715     if (out->edgelist == (int *) nullptr) {
29716       terminatetetgen(1);
29717     }
29718     if (b->order == 2) {
29719       out->o2edgelist = new int[subsegs->items];
29720     }
29721     out->edgemarkerlist = new int[subsegs->items];
29722     if (out->edgemarkerlist == (int *) nullptr) {
29723       terminatetetgen(1);
29724     }
29725     if (b->neighout > 1) {
29726       out->edgeadjtetlist = new int[subsegs->items];
29727     }
29728     out->numberofedges = subsegs->items;
29729     elist = out->edgelist;
29730   }
29731 
29732   // Determine the first index (0 or 1).
29733   firstindex = b->zeroindex ? 0 : in->firstnumber;
29734   shift = 0; // Default no shiftment.
29735   if ((in->firstnumber == 1) && (firstindex == 0)) {
29736     shift = 1; // Shift the output indices by 1.
29737   }
29738   index = 0;
29739   i = 0;
29740 
29741   subsegs->traversalinit();
29742   edgeloop.sh = shellfacetraverse(subsegs);
29743   edgenumber = firstindex; // in->firstnumber;
29744   while (edgeloop.sh != (shellface *) nullptr) {
29745     torg = sorg(edgeloop);
29746     tdest = sdest(edgeloop);
29747     if ((b->order == 2) || (b->neighout > 1)) {
29748       sstpivot1(edgeloop, workface);
29749       if (workface.tet != nullptr) {
29750         // We must find a non-hull tet.
29751         if (ishulltet(workface)) {
29752           spintet = workface;
29753           while (1) {
29754             fnextself(spintet);
29755             if (!ishulltet(spintet)) break;
29756             if (spintet.tet == workface.tet) break;
29757           }
29758           assert(!ishulltet(spintet));
29759           workface = spintet;
29760         }
29761       }
29762     }
29763     if (b->order == 2) { // -o2
29764       // Get the extra vertex on this edge.
29765       if (workface.tet != nullptr) {
29766         extralist = (point *) workface.tet[highorderindex];
29767         pp = extralist[ver2edge[workface.ver]];
29768       } else {
29769         pp = torg; // There is no extra node available.
29770       }
29771     }
29772     if (b->neighout > 1) { // -nn
29773       if (workface.tet != nullptr) {
29774         neigh = elemindex(workface.tet);
29775       } else {
29776         neigh = -1;
29777       }
29778     }
29779     marker = shellmark(edgeloop);
29780     if (marker == 0) {
29781       marker = 1; // Default marker of a boundary edge is 1.
29782     }
29783     if (out == (tetgenio *) nullptr) {
29784       fprintf(outfile, "%5d   %4d  %4d", edgenumber,
29785               pointmark(torg) - shift, pointmark(tdest) - shift);
29786       if (b->order == 2) { // -o2
29787         fprintf(outfile, "  %4d", pointmark(pp) - shift);
29788       }
29789       fprintf(outfile, "  %d", marker);
29790       if (b->neighout > 1) { // -nn
29791         fprintf(outfile, "  %4d", neigh);
29792       }
29793       fprintf(outfile, "\n");
29794     } else {
29795       // Output three vertices of this face;
29796       elist[index++] = pointmark(torg) - shift;
29797       elist[index++] = pointmark(tdest) - shift;
29798       if (b->order == 2) { // -o2
29799         out->o2edgelist[o2index++] = pointmark(pp) - shift;
29800       }
29801       out->edgemarkerlist[i++] = marker;
29802       if (b->neighout > 1) { // -nn
29803         out->edgeadjtetlist[index2++] = neigh;
29804       }
29805     }
29806     edgenumber++;
29807     edgeloop.sh = shellfacetraverse(subsegs);
29808   }
29809 
29810   if (out == (tetgenio *) nullptr) {
29811     fprintf(outfile, "# Generated by %s\n", b->commandline);
29812     fclose(outfile);
29813   }
29814 }
29815 
29816 ///////////////////////////////////////////////////////////////////////////////
29817 //                                                                           //
29818 // outneighbors()    Output tet neighbors to a .neigh file or a structure.   //
29819 //                                                                           //
29820 ///////////////////////////////////////////////////////////////////////////////
29821 
outneighbors(tetgenio * out)29822 void tetgenmesh::outneighbors(tetgenio* out)
29823 {
29824   FILE *outfile = nullptr;
29825   char neighborfilename[FILENAMESIZE];
29826   int *nlist = nullptr;
29827   int index = 0;
29828   triface tetloop, tetsym;
29829   int neighbori[4];
29830   int firstindex;
29831   int elementnumber;
29832   long ntets;
29833 
29834   if (out == (tetgenio *) nullptr) {
29835     strcpy(neighborfilename, b->outfilename);
29836     strcat(neighborfilename, ".neigh");
29837   }
29838 
29839   if (!b->quiet) {
29840     if (out == (tetgenio *) nullptr) {
29841       printf("Writing %s.\n", neighborfilename);
29842     } else {
29843       printf("Writing neighbors.\n");
29844     }
29845   }
29846 
29847   ntets = tetrahedrons->items - hullsize;
29848 
29849   if (out == (tetgenio *) nullptr) {
29850     outfile = fopen(neighborfilename, "w");
29851     if (outfile == (FILE *) nullptr) {
29852       printf("File I/O Error:  Cannot create file %s.\n", neighborfilename);
29853       terminatetetgen(1);
29854     }
29855     // Number of tetrahedra, four faces per tetrahedron.
29856     fprintf(outfile, "%ld  %d\n", ntets, 4);
29857   } else {
29858     // Allocate memory for 'neighborlist'.
29859     out->neighborlist = new int[ntets * 4];
29860     if (out->neighborlist == (int *) nullptr) {
29861       printf("Error:  Out of memory.\n");
29862       terminatetetgen(1);
29863     }
29864     nlist = out->neighborlist;
29865   }
29866 
29867   // Determine the first index (0 or 1).
29868   firstindex = b->zeroindex ? 0 : in->firstnumber;
29869 
29870   tetrahedrons->traversalinit();
29871   tetloop.tet = tetrahedrontraverse();
29872   elementnumber = firstindex; // in->firstnumber;
29873   while (tetloop.tet != (tetrahedron *) nullptr) {
29874     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
29875       fsym(tetloop, tetsym);
29876       if (!ishulltet(tetsym)) {
29877         neighbori[tetloop.ver] = elemindex(tetsym.tet);
29878       } else {
29879         neighbori[tetloop.ver] = -1;
29880       }
29881     }
29882     if (out == (tetgenio *) nullptr) {
29883       // Tetrahedra number, neighboring tetrahedron numbers.
29884       fprintf(outfile, "%4d    %4d  %4d  %4d  %4d\n", elementnumber,
29885               neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
29886     } else {
29887       nlist[index++] = neighbori[0];
29888       nlist[index++] = neighbori[1];
29889       nlist[index++] = neighbori[2];
29890       nlist[index++] = neighbori[3];
29891     }
29892     tetloop.tet = tetrahedrontraverse();
29893     elementnumber++;
29894   }
29895 
29896   if (out == (tetgenio *) nullptr) {
29897     fprintf(outfile, "# Generated by %s\n", b->commandline);
29898     fclose(outfile);
29899   }
29900 }
29901 
29902 ///////////////////////////////////////////////////////////////////////////////
29903 //                                                                           //
29904 // outvoronoi()    Output the Voronoi diagram to .v.node, .v.edge, v.face,   //
29905 //                 and .v.cell.                                              //
29906 //                                                                           //
29907 // The Voronoi diagram is the geometric dual of the Delaunay triangulation.  //
29908 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra.  Each  //
29909 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
29910 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
29911 // A Voronoi face is the convex hull of all Voronoi vertices around a common //
29912 // Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a //
29913 // ridge, it is unbounded.  Each Voronoi cell is the convex hull of all Vor- //
29914 // onoi vertices around a common Delaunay vertex. It is a polytope for any   //
29915 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay    //
29916 // vertex belonging to the convex hull.                                      //
29917 //                                                                           //
29918 // aunay tetrahedralization - the power diagram - of the weighted point set. //
29919 // Note that the vertices of the power disgram are the centers of the ortho- //
29920 // spheres of the tetrahedra.                                                //
29921 //                                                                           //
29922 // NOTE: This routine is only used when the input is only a set of point.    //
29923 //                                                                           //
29924 // Comment: Special thanks to Victor Liu for finding and fixing few bugs.    //
29925 //                                                                           //
29926 ///////////////////////////////////////////////////////////////////////////////
29927 
outvoronoi(tetgenio * out)29928 void tetgenmesh::outvoronoi(tetgenio* out)
29929 {
29930   FILE *outfile = nullptr;
29931   char outfilename[FILENAMESIZE];
29932   tetgenio::voroedge *vedge = nullptr;
29933   tetgenio::vorofacet *vfacet = nullptr;
29934   arraypool *tetlist, *ptlist;
29935   triface tetloop, worktet, spintet, firsttet;
29936   point pt[4], ploop, neipt;
29937   REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
29938   long ntets, faces, edges;
29939   int *indexarray, *fidxs, *eidxs;
29940   int arraysize, *vertarray = nullptr;
29941   int vpointcount, vedgecount, vfacecount, tcount;
29942   int ishullvert, ishullface;
29943   int index, shift, end1, end2;
29944   int i, j;
29945 
29946   int t1ver; // used by fsymself()
29947 
29948   // Output Voronoi vertices to .v.node file.
29949   if (out == (tetgenio *) nullptr) {
29950     strcpy(outfilename, b->outfilename);
29951     strcat(outfilename, ".v.node");
29952   }
29953 
29954   if (!b->quiet) {
29955     if (out == (tetgenio *) nullptr) {
29956       printf("Writing %s.\n", outfilename);
29957     } else {
29958       printf("Writing Voronoi vertices.\n");
29959     }
29960   }
29961 
29962   // Determine the first index (0 or 1).
29963   shift = (b->zeroindex ? 0 : in->firstnumber);
29964 
29965   // Each face and edge of the tetrahedral mesh will be indexed for indexing
29966   //   the Voronoi edges and facets. Indices of faces and edges are saved in
29967   //   each tetrahedron (including hull tets).
29968 
29969   // Allocate the total space once.
29970   indexarray = new int[tetrahedrons->items * 10];
29971 
29972   // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
29973   //   for element markers, flags.
29974   i = 0;
29975   tetrahedrons->traversalinit();
29976   tetloop.tet = alltetrahedrontraverse();
29977   while (tetloop.tet != nullptr) {
29978     tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
29979     i++;
29980     tetloop.tet = alltetrahedrontraverse();
29981   }
29982 
29983   // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
29984   ntets = tetrahedrons->items - hullsize;
29985   // The number of Delaunay faces (Voronoi edges).
29986   faces = (4l * ntets + hullsize) / 2l;
29987   // The number of Delaunay edges (Voronoi faces).
29988   long vsize = points->items - dupverts - unuverts;
29989   if (b->weighted) vsize -= nonregularcount;
29990   edges = vsize + faces - ntets - 1;
29991 
29992   if (out == (tetgenio *) nullptr) {
29993     outfile = fopen(outfilename, "w");
29994     if (outfile == (FILE *) nullptr) {
29995       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
29996       terminatetetgen(3);
29997     }
29998     // Number of voronoi points, 3 dim, no attributes, no marker.
29999     fprintf(outfile, "%ld  3  0  0\n", ntets);
30000   } else {
30001     // Allocate space for 'vpointlist'.
30002     out->numberofvpoints = (int) ntets;
30003     out->vpointlist = new REAL[out->numberofvpoints * 3];
30004     if (out->vpointlist == (REAL *) nullptr) {
30005       terminatetetgen(1);
30006     }
30007   }
30008 
30009   // Output Voronoi vertices (the circumcenters of tetrahedra).
30010   tetrahedrons->traversalinit();
30011   tetloop.tet = tetrahedrontraverse();
30012   vpointcount = 0; // The (internal) v-index always starts from 0.
30013   index = 0;
30014   while (tetloop.tet != (tetrahedron *) nullptr) {
30015     for (i = 0; i < 4; i++) {
30016       pt[i] = (point) tetloop.tet[4 + i];
30017       setpoint2tet(pt[i], encode(tetloop));
30018     }
30019     if (b->weighted) {
30020       orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3],
30021                   pt[3][3], ccent, nullptr);
30022     } else {
30023       circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, nullptr);
30024     }
30025     if (out == (tetgenio *) nullptr) {
30026       fprintf(outfile, "%4d  %16.8e %16.8e %16.8e\n", vpointcount + shift,
30027               ccent[0], ccent[1], ccent[2]);
30028     } else {
30029       out->vpointlist[index++] = ccent[0];
30030       out->vpointlist[index++] = ccent[1];
30031       out->vpointlist[index++] = ccent[2];
30032     }
30033     setelemindex(tetloop.tet, vpointcount);
30034     vpointcount++;
30035     tetloop.tet = tetrahedrontraverse();
30036   }
30037 
30038   if (out == (tetgenio *) nullptr) {
30039     fprintf(outfile, "# Generated by %s\n", b->commandline);
30040     fclose(outfile);
30041   }
30042 
30043   // Output Voronoi edges to .v.edge file.
30044   if (out == (tetgenio *) nullptr) {
30045     strcpy(outfilename, b->outfilename);
30046     strcat(outfilename, ".v.edge");
30047   }
30048 
30049   if (!b->quiet) {
30050     if (out == (tetgenio *) nullptr) {
30051       printf("Writing %s.\n", outfilename);
30052     } else {
30053       printf("Writing Voronoi edges.\n");
30054     }
30055   }
30056 
30057   if (out == (tetgenio *) nullptr) {
30058     outfile = fopen(outfilename, "w");
30059     if (outfile == (FILE *) nullptr) {
30060       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
30061       terminatetetgen(3);
30062     }
30063     // Number of Voronoi edges, no marker.
30064     fprintf(outfile, "%ld  0\n", faces);
30065   } else {
30066     // Allocate space for 'vpointlist'.
30067     out->numberofvedges = (int) faces;
30068     out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
30069   }
30070 
30071   // Output the Voronoi edges.
30072   tetrahedrons->traversalinit();
30073   tetloop.tet = tetrahedrontraverse();
30074   vedgecount = 0; // D-Face (V-edge) index (from zero).
30075   index = 0; // The Delaunay-face index.
30076   while (tetloop.tet != (tetrahedron *) nullptr) {
30077     // Count the number of Voronoi edges. Look at the four faces of each
30078     //   tetrahedron. Count the face if the tetrahedron's index is
30079     //   smaller than its neighbor's or the neighbor is outside.
30080     end1 = elemindex(tetloop.tet);
30081     for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
30082       fsym(tetloop, worktet);
30083       if (ishulltet(worktet) ||
30084           (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
30085         // Found a Voronoi edge. Operate on it.
30086         if (out == (tetgenio *) nullptr) {
30087           fprintf(outfile, "%4d  %4d", vedgecount + shift, end1 + shift);
30088         } else {
30089           vedge = &(out->vedgelist[index++]);
30090           vedge->v1 = end1 + shift;
30091         }
30092         if (!ishulltet(worktet)) {
30093           end2 = elemindex(worktet.tet);
30094         } else {
30095           end2 = -1;
30096         }
30097         // Note that end2 may be -1 (worktet.tet is outside).
30098         if (end2 == -1) {
30099           // Calculate the out normal of this hull face.
30100           pt[0] = dest(worktet);
30101           pt[1] = org(worktet);
30102           pt[2] = apex(worktet);
30103           for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
30104           for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
30105           cross(vec1, vec2, infvec);
30106           // Normalize it.
30107           L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
30108                    + infvec[2] * infvec[2]);
30109           if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
30110           if (out == (tetgenio *) nullptr) {
30111             fprintf(outfile, " -1");
30112             fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
30113           } else {
30114             vedge->v2 = -1;
30115             vedge->vnormal[0] = infvec[0];
30116             vedge->vnormal[1] = infvec[1];
30117             vedge->vnormal[2] = infvec[2];
30118           }
30119         } else {
30120           if (out == (tetgenio *) nullptr) {
30121             fprintf(outfile, " %4d\n", end2 + shift);
30122           } else {
30123             vedge->v2 = end2 + shift;
30124             vedge->vnormal[0] = 0.0;
30125             vedge->vnormal[1] = 0.0;
30126             vedge->vnormal[2] = 0.0;
30127           }
30128         }
30129         // Save the V-edge index in this tet and its neighbor.
30130         fidxs = (int *) (tetloop.tet[11]);
30131         fidxs[tetloop.ver] = vedgecount;
30132         fidxs = (int *) (worktet.tet[11]);
30133         fidxs[worktet.ver & 3] = vedgecount;
30134         vedgecount++;
30135       }
30136     } // tetloop.ver
30137     tetloop.tet = tetrahedrontraverse();
30138   }
30139 
30140   if (out == (tetgenio *) nullptr) {
30141     fprintf(outfile, "# Generated by %s\n", b->commandline);
30142     fclose(outfile);
30143   }
30144 
30145   // Output Voronoi faces to .v.face file.
30146   if (out == (tetgenio *) nullptr) {
30147     strcpy(outfilename, b->outfilename);
30148     strcat(outfilename, ".v.face");
30149   }
30150 
30151   if (!b->quiet) {
30152     if (out == (tetgenio *) nullptr) {
30153       printf("Writing %s.\n", outfilename);
30154     } else {
30155       printf("Writing Voronoi faces.\n");
30156     }
30157   }
30158 
30159   if (out == (tetgenio *) nullptr) {
30160     outfile = fopen(outfilename, "w");
30161     if (outfile == (FILE *) nullptr) {
30162       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
30163       terminatetetgen(3);
30164     }
30165     // Number of Voronoi faces.
30166     fprintf(outfile, "%ld  0\n", edges);
30167   } else {
30168     out->numberofvfacets = edges;
30169     out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
30170     if (out->vfacetlist == (tetgenio::vorofacet *) nullptr) {
30171       terminatetetgen(1);
30172     }
30173   }
30174 
30175   // Output the Voronoi facets.
30176   tetrahedrons->traversalinit();
30177   tetloop.tet = tetrahedrontraverse();
30178   vfacecount = 0; // D-edge (V-facet) index (from zero).
30179   while (tetloop.tet != (tetrahedron *) nullptr) {
30180     // Count the number of Voronoi faces. Look at the six edges of each
30181     //   tetrahedron. Count the edge only if the tetrahedron's index is
30182     //   smaller than those of all other tetrahedra that share the edge.
30183     worktet.tet = tetloop.tet;
30184     for (i = 0; i < 6; i++) {
30185       worktet.ver = edge2ver[i];
30186       // Count the number of faces at this edge. If the edge is a hull edge,
30187       //   the face containing dummypoint is also counted.
30188       //ishulledge = 0; // Is it a hull edge.
30189       tcount = 0;
30190       firsttet = worktet;
30191       spintet = worktet;
30192       while (1) {
30193         tcount++;
30194         fnextself(spintet);
30195         if (spintet.tet == worktet.tet) break;
30196         if (!ishulltet(spintet)) {
30197           if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
30198         } else {
30199           //ishulledge = 1;
30200           if (apex(spintet) == dummypoint) {
30201             // We make this V-edge appear in the end of the edge list.
30202             fnext(spintet, firsttet);
30203           }
30204         }
30205       } // while (1)
30206       if (spintet.tet == worktet.tet) {
30207         // Found a Voronoi facet. Operate on it.
30208         pt[0] = org(worktet);
30209         pt[1] = dest(worktet);
30210         end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
30211         end2 = pointmark(pt[1]) - in->firstnumber;
30212         if (out == (tetgenio *) nullptr) {
30213           fprintf(outfile, "%4d  %4d %4d  %-2d ", vfacecount + shift,
30214                   end1 + shift, end2 + shift, tcount);
30215         } else {
30216           vfacet = &(out->vfacetlist[vfacecount]);
30217           vfacet->c1 = end1 + shift;
30218           vfacet->c2 = end2 + shift;
30219           vfacet->elist = new int[tcount + 1];
30220           vfacet->elist[0] = tcount;
30221           index = 1;
30222         }
30223         // Output V-edges of this V-facet.
30224         spintet = firsttet; //worktet;
30225         while (1) {
30226           fidxs = (int *) (spintet.tet[11]);
30227           if (apex(spintet) != dummypoint) {
30228             vedgecount = fidxs[spintet.ver & 3];
30229             ishullface = 0;
30230           } else {
30231             ishullface = 1; // It's not a real face.
30232           }
30233           if (out == (tetgenio *) nullptr) {
30234             fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1);
30235           } else {
30236             vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
30237           }
30238           // Save the V-facet index in this tet at this edge.
30239           eidxs = &(fidxs[4]);
30240           eidxs[ver2edge[spintet.ver]] = vfacecount;
30241           // Go to the next face.
30242           fnextself(spintet);
30243           if (spintet.tet == firsttet.tet) break;
30244         } // while (1)
30245         if (out == (tetgenio *) nullptr) {
30246           fprintf(outfile, "\n");
30247         }
30248         vfacecount++;
30249       } // if (spintet.tet == worktet.tet)
30250     } // if (i = 0; i < 6; i++)
30251     tetloop.tet = tetrahedrontraverse();
30252   }
30253 
30254   if (out == (tetgenio *) nullptr) {
30255     fprintf(outfile, "# Generated by %s\n", b->commandline);
30256     fclose(outfile);
30257   }
30258 
30259   // Output Voronoi cells to .v.cell file.
30260   if (out == (tetgenio *) nullptr) {
30261     strcpy(outfilename, b->outfilename);
30262     strcat(outfilename, ".v.cell");
30263   }
30264 
30265   if (!b->quiet) {
30266     if (out == (tetgenio *) nullptr) {
30267       printf("Writing %s.\n", outfilename);
30268     } else {
30269       printf("Writing Voronoi cells.\n");
30270     }
30271   }
30272 
30273   if (out == (tetgenio *) nullptr) {
30274     outfile = fopen(outfilename, "w");
30275     if (outfile == (FILE *) nullptr) {
30276       printf("File I/O Error:  Cannot create file %s.\n", outfilename);
30277       terminatetetgen(3);
30278     }
30279     // Number of Voronoi cells.
30280     fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
30281   } else {
30282     out->numberofvcells = points->items - unuverts - dupverts;
30283     out->vcelllist = new int*[out->numberofvcells];
30284     if (out->vcelllist == (int **) nullptr) {
30285       terminatetetgen(1);
30286     }
30287   }
30288 
30289   // Output Voronoi cells.
30290   tetlist = cavetetlist;
30291   ptlist = cavetetvertlist;
30292   points->traversalinit();
30293   ploop = pointtraverse();
30294   vpointcount = 0;
30295   while (ploop != (point) nullptr) {
30296     if ((pointtype(ploop) != UNUSEDVERTEX) &&
30297         (pointtype(ploop) != DUPLICATEDVERTEX) &&
30298         (pointtype(ploop) != NREGULARVERTEX)) {
30299       getvertexstar(1, ploop, tetlist, ptlist, nullptr);
30300       // Mark all vertices. Check if it is a hull vertex.
30301       ishullvert = 0;
30302       for (i = 0; i < ptlist->objects; i++) {
30303         neipt = * (point *) fastlookup(ptlist, i);
30304         if (neipt != dummypoint) {
30305           pinfect(neipt);
30306         } else {
30307           ishullvert = 1;
30308         }
30309       }
30310       tcount = (int) ptlist->objects;
30311       if (out == (tetgenio *) nullptr) {
30312         fprintf(outfile, "%4d  %-2d ", vpointcount + shift, tcount);
30313       } else {
30314         arraysize = tcount;
30315         vertarray = new int[arraysize + 1];
30316         out->vcelllist[vpointcount] = vertarray;
30317         vertarray[0] = tcount;
30318         index = 1;
30319       }
30320       // List Voronoi facets bounding this cell.
30321       for (i = 0; i < tetlist->objects; i++) {
30322         worktet = * (triface *) fastlookup(tetlist, i);
30323         // Let 'worktet' be [a,b,c,d] where d = ploop.
30324         for (j = 0; j < 3; j++) {
30325           neipt = org(worktet); // neipt is a, or b, or c
30326           // Skip the dummypoint.
30327           if (neipt != dummypoint) {
30328             if (pinfected(neipt)) {
30329               // It's not processed yet.
30330               puninfect(neipt);
30331               // Go to the DT edge [a,d], or [b,d], or [c,d].
30332               esym(worktet, spintet);
30333               enextself(spintet);
30334               // Get the V-face dual to this edge.
30335               eidxs = (int *) spintet.tet[11];
30336               vfacecount = eidxs[4 + ver2edge[spintet.ver]];
30337               if (out == (tetgenio *) nullptr) {
30338                 fprintf(outfile, " %d", vfacecount + shift);
30339               } else {
30340                 vertarray[index++] = vfacecount + shift;
30341               }
30342             }
30343           }
30344           enextself(worktet);
30345         } // j
30346       } // i
30347       if (ishullvert) {
30348         // Add a hull facet (-1) to the facet list.
30349         if (out == (tetgenio *) nullptr) {
30350           fprintf(outfile, " -1");
30351         } else {
30352           vertarray[index++] = -1;
30353         }
30354       }
30355       if (out == (tetgenio *) nullptr) {
30356         fprintf(outfile, "\n");
30357       }
30358       tetlist->restart();
30359       ptlist->restart();
30360       vpointcount++;
30361     }
30362     ploop = pointtraverse();
30363   }
30364 
30365   // Delete the space for face/edge indices.
30366   delete [] indexarray;
30367 
30368   if (out == (tetgenio *) nullptr) {
30369     fprintf(outfile, "# Generated by %s\n", b->commandline);
30370     fclose(outfile);
30371   }
30372 }
30373 
30374 ///////////////////////////////////////////////////////////////////////////////
30375 //                                                                           //
30376 // outsmesh()    Write surface mesh to a .smesh file, which can be read and  //
30377 //               tetrahedralized by TetGen.                                  //
30378 //                                                                           //
30379 // You can specify a filename (without suffix) in 'smfilename'. If you don't //
30380 // supply a filename (let smfilename be nullptr), the default name stored in    //
30381 // 'tetgenbehavior' will be used.                                            //
30382 //                                                                           //
30383 ///////////////////////////////////////////////////////////////////////////////
30384 
outsmesh(char * smfilename)30385 void tetgenmesh::outsmesh(char* smfilename)
30386 {
30387   FILE *outfile;
30388   char nodfilename[FILENAMESIZE];
30389   char smefilename[FILENAMESIZE];
30390   face faceloop;
30391   point p1, p2, p3;
30392   int firstindex, shift;
30393   int bmark;
30394   int faceid, marker;
30395   int i;
30396 
30397   if (smfilename != (char *) nullptr && smfilename[0] != '\0') {
30398     strcpy(smefilename, smfilename);
30399   } else if (b->outfilename[0] != '\0') {
30400     strcpy(smefilename, b->outfilename);
30401   } else {
30402     strcpy(smefilename, "unnamed");
30403   }
30404   strcpy(nodfilename, smefilename);
30405   strcat(smefilename, ".smesh");
30406   strcat(nodfilename, ".node");
30407 
30408   if (!b->quiet) {
30409     printf("Writing %s.\n", smefilename);
30410   }
30411   outfile = fopen(smefilename, "w");
30412   if (outfile == (FILE *) nullptr) {
30413     printf("File I/O Error:  Cannot create file %s.\n", smefilename);
30414     return;
30415   }
30416 
30417   // Determine the first index (0 or 1).
30418   firstindex = b->zeroindex ? 0 : in->firstnumber;
30419   shift = 0; // Default no shiftment.
30420   if ((in->firstnumber == 1) && (firstindex == 0)) {
30421     shift = 1; // Shift the output indices by 1.
30422   }
30423 
30424   fprintf(outfile, "# %s.  TetGen's input file.\n", smefilename);
30425   fprintf(outfile, "\n# part 1: node list.\n");
30426   fprintf(outfile, "0  3  0  0  # nodes are found in %s.\n", nodfilename);
30427 
30428   marker = 0; // avoid compile warning.
30429   bmark = !b->nobound && in->facetmarkerlist;
30430 
30431   fprintf(outfile, "\n# part 2: facet list.\n");
30432   // Number of facets, boundary marker.
30433   fprintf(outfile, "%ld  %d\n", subfaces->items, bmark);
30434 
30435   subfaces->traversalinit();
30436   faceloop.sh = shellfacetraverse(subfaces);
30437   while (faceloop.sh != (shellface *) nullptr) {
30438     p1 = sorg(faceloop);
30439     p2 = sdest(faceloop);
30440     p3 = sapex(faceloop);
30441     if (bmark) {
30442       faceid = shellmark(faceloop) - 1;
30443       if (faceid >= 0) {
30444         marker = in->facetmarkerlist[faceid];
30445       } else {
30446         marker = 0; // This subface must be added manually later.
30447       }
30448     }
30449     fprintf(outfile, "3    %4d  %4d  %4d", pointmark(p1) - shift,
30450             pointmark(p2) - shift, pointmark(p3) - shift);
30451     if (bmark) {
30452       fprintf(outfile, "    %d", marker);
30453     }
30454     fprintf(outfile, "\n");
30455     faceloop.sh = shellfacetraverse(subfaces);
30456   }
30457 
30458   // Copy input holelist.
30459   fprintf(outfile, "\n# part 3: hole list.\n");
30460   fprintf(outfile, "%d\n", in->numberofholes);
30461   for (i = 0; i < in->numberofholes; i++) {
30462     fprintf(outfile, "%d  %g  %g  %g\n", i + in->firstnumber,
30463             in->holelist[i * 3], in->holelist[i * 3 + 1],
30464             in->holelist[i * 3 + 2]);
30465   }
30466 
30467   // Copy input regionlist.
30468   fprintf(outfile, "\n# part 4: region list.\n");
30469   fprintf(outfile, "%d\n", in->numberofregions);
30470   for (i = 0; i < in->numberofregions; i++) {
30471     fprintf(outfile, "%d  %g  %g  %g  %d  %g\n", i + in->firstnumber,
30472             in->regionlist[i * 5], in->regionlist[i * 5 + 1],
30473             in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
30474             in->regionlist[i * 5 + 4]);
30475   }
30476 
30477   fprintf(outfile, "# Generated by %s\n", b->commandline);
30478   fclose(outfile);
30479 }
30480 
30481 ///////////////////////////////////////////////////////////////////////////////
30482 //                                                                           //
30483 // outmesh2medit()    Write mesh to a .mesh file, which can be read and      //
30484 //                    rendered by Medit (a free mesh viewer from INRIA).     //
30485 //                                                                           //
30486 // You can specify a filename (without suffix) in 'mfilename'.  If you don't //
30487 // supply a filename (let mfilename be nullptr), the default name stored in     //
30488 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
30489 //                                                                           //
30490 ///////////////////////////////////////////////////////////////////////////////
30491 
outmesh2medit(char * mfilename)30492 void tetgenmesh::outmesh2medit(char* mfilename)
30493 {
30494   FILE *outfile;
30495   char mefilename[FILENAMESIZE];
30496   tetrahedron* tetptr;
30497   triface tface, tsymface;
30498   face segloop, checkmark;
30499   point ptloop, p1, p2, p3, p4;
30500   long ntets, faces;
30501   int pointnumber;
30502   int faceid, marker;
30503   int i;
30504 
30505   if (mfilename != (char *) nullptr && mfilename[0] != '\0') {
30506     strcpy(mefilename, mfilename);
30507   } else if (b->outfilename[0] != '\0') {
30508     strcpy(mefilename, b->outfilename);
30509   } else {
30510     strcpy(mefilename, "unnamed");
30511   }
30512   strcat(mefilename, ".mesh");
30513 
30514   if (!b->quiet) {
30515     printf("Writing %s.\n", mefilename);
30516   }
30517   outfile = fopen(mefilename, "w");
30518   if (outfile == (FILE *) nullptr) {
30519     printf("File I/O Error:  Cannot create file %s.\n", mefilename);
30520     return;
30521   }
30522 
30523   fprintf(outfile, "MeshVersionFormatted 1\n");
30524   fprintf(outfile, "\n");
30525   fprintf(outfile, "Dimension\n");
30526   fprintf(outfile, "3\n");
30527   fprintf(outfile, "\n");
30528 
30529   fprintf(outfile, "\n# Set of mesh vertices\n");
30530   fprintf(outfile, "Vertices\n");
30531   fprintf(outfile, "%ld\n", points->items);
30532 
30533   points->traversalinit();
30534   ptloop = pointtraverse();
30535   pointnumber = 1;                        // Medit need start number form 1.
30536   while (ptloop != (point) nullptr) {
30537     // Point coordinates.
30538     fprintf(outfile, "%.17g  %.17g  %.17g", ptloop[0], ptloop[1], ptloop[2]);
30539     if (in->numberofpointattributes > 0) {
30540       // Write an attribute, ignore others if more than one.
30541       fprintf(outfile, "  %.17g\n", ptloop[3]);
30542     } else {
30543       fprintf(outfile, "    0\n");
30544     }
30545     setpointmark(ptloop, pointnumber);
30546     ptloop = pointtraverse();
30547     pointnumber++;
30548   }
30549 
30550   // Compute the number of faces.
30551   ntets = tetrahedrons->items - hullsize;
30552   faces = (ntets * 4l + hullsize) / 2l;
30553 
30554   fprintf(outfile, "\n# Set of Triangles\n");
30555   fprintf(outfile, "Triangles\n");
30556   fprintf(outfile, "%ld\n", faces);
30557 
30558   tetrahedrons->traversalinit();
30559   tface.tet = tetrahedrontraverse();
30560   while (tface.tet != (tetrahedron *) nullptr) {
30561     for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
30562       fsym(tface, tsymface);
30563       if (ishulltet(tsymface) ||
30564           (elemindex(tface.tet) < elemindex(tsymface.tet))) {
30565         p1 = org (tface);
30566         p2 = dest(tface);
30567         p3 = apex(tface);
30568         fprintf(outfile, "%5d  %5d  %5d",
30569                 pointmark(p1), pointmark(p2), pointmark(p3));
30570         // Check if it is a subface.
30571         tspivot(tface, checkmark);
30572         if (checkmark.sh == nullptr) {
30573           marker = 0;  // It is an inner face. It's marker is 0.
30574         } else {
30575           if (in->facetmarkerlist) {
30576             // The facet marker is given, get it.
30577             faceid = shellmark(checkmark) - 1;
30578             marker = in->facetmarkerlist[faceid];
30579           } else {
30580             marker = 1; // The default marker for subface is 1.
30581           }
30582         }
30583         fprintf(outfile, "    %d\n", marker);
30584       }
30585     }
30586     tface.tet = tetrahedrontraverse();
30587   }
30588 
30589   fprintf(outfile, "\n# Set of Tetrahedra\n");
30590   fprintf(outfile, "Tetrahedra\n");
30591   fprintf(outfile, "%ld\n", ntets);
30592 
30593   tetrahedrons->traversalinit();
30594   tetptr = tetrahedrontraverse();
30595   while (tetptr != (tetrahedron *) nullptr) {
30596     if (!b->reversetetori) {
30597       p1 = (point) tetptr[4];
30598       p2 = (point) tetptr[5];
30599     } else {
30600       p1 = (point) tetptr[5];
30601       p2 = (point) tetptr[4];
30602     }
30603     p3 = (point) tetptr[6];
30604     p4 = (point) tetptr[7];
30605     fprintf(outfile, "%5d  %5d  %5d  %5d",
30606             pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
30607     if (numelemattrib > 0) {
30608       fprintf(outfile, "  %.17g", elemattribute(tetptr, 0));
30609     } else {
30610       fprintf(outfile, "  0");
30611     }
30612     fprintf(outfile, "\n");
30613     tetptr = tetrahedrontraverse();
30614   }
30615 
30616   fprintf(outfile, "\nCorners\n");
30617   fprintf(outfile, "%d\n", in->numberofpoints);
30618 
30619   for (i = 0; i < in->numberofpoints; i++) {
30620     fprintf(outfile, "%4d\n", i + 1);
30621   }
30622 
30623   if (b->plc || b->refine) {
30624     fprintf(outfile, "\nEdges\n");
30625     fprintf(outfile, "%ld\n", subsegs->items);
30626 
30627     subsegs->traversalinit();
30628     segloop.sh = shellfacetraverse(subsegs);
30629     while (segloop.sh != (shellface *) nullptr) {
30630       p1 = sorg(segloop);
30631       p2 = sdest(segloop);
30632       fprintf(outfile, "%5d  %5d", pointmark(p1), pointmark(p2));
30633       marker = shellmark(segloop);
30634       fprintf(outfile, "    %d\n", marker);
30635       segloop.sh = shellfacetraverse(subsegs);
30636     }
30637   }
30638 
30639   fprintf(outfile, "\nEnd\n");
30640   fclose(outfile);
30641 }
30642 
30643 
30644 
30645 ///////////////////////////////////////////////////////////////////////////////
30646 //                                                                           //
30647 // outmesh2vtk()    Save mesh to file in VTK Legacy format.                  //
30648 //                                                                           //
30649 // This function was contributed by Bryn Llyod from ETH, 2007.               //
30650 //                                                                           //
30651 ///////////////////////////////////////////////////////////////////////////////
30652 
outmesh2vtk(char * ofilename)30653 void tetgenmesh::outmesh2vtk(char* ofilename)
30654 {
30655   FILE *outfile;
30656   char vtkfilename[FILENAMESIZE];
30657   point pointloop, p1, p2, p3, p4;
30658   tetrahedron* tptr;
30659   double x, y, z;
30660   int n1, n2, n3, n4;
30661   int nnodes = 4;
30662   int celltype = 10;
30663 
30664   int NEL = tetrahedrons->items - hullsize;
30665   int NN = points->items;
30666 
30667   if (ofilename != (char *) nullptr && ofilename[0] != '\0') {
30668     strcpy(vtkfilename, ofilename);
30669   } else if (b->outfilename[0] != '\0') {
30670     strcpy(vtkfilename, b->outfilename);
30671   } else {
30672     strcpy(vtkfilename, "unnamed");
30673   }
30674   strcat(vtkfilename, ".vtk");
30675 
30676   if (!b->quiet) {
30677     printf("Writing %s.\n", vtkfilename);
30678   }
30679   outfile = fopen(vtkfilename, "w");
30680   if (outfile == (FILE *) nullptr) {
30681     printf("File I/O Error:  Cannot create file %s.\n", vtkfilename);
30682     return;
30683   }
30684 
30685   //always write big endian
30686   //bool ImALittleEndian = !testIsBigEndian();
30687 
30688   fprintf(outfile, "# vtk DataFile Version 2.0\n");
30689   fprintf(outfile, "Unstructured Grid\n");
30690   fprintf(outfile, "ASCII\n"); // BINARY
30691   fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
30692   fprintf(outfile, "POINTS %d double\n", NN);
30693 
30694   points->traversalinit();
30695   pointloop = pointtraverse();
30696   for(int id=0; id<NN && pointloop != (point) nullptr; id++){
30697     x = pointloop[0];
30698     y = pointloop[1];
30699     z = pointloop[2];
30700     fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
30701     pointloop = pointtraverse();
30702   }
30703   fprintf(outfile, "\n");
30704 
30705   fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
30706   //NEL rows, each has 1 type id + 4 node id's
30707 
30708   tetrahedrons->traversalinit();
30709   tptr = tetrahedrontraverse();
30710   //elementnumber = firstindex; // in->firstnumber;
30711   if (b->order == 2) {
30712     printf("  Write VTK not implemented for order 2 elements \n");
30713     return;
30714   }
30715   while (tptr != (tetrahedron *) nullptr) {
30716     if (!b->reversetetori) {
30717       p1 = (point) tptr[4];
30718       p2 = (point) tptr[5];
30719     } else {
30720       p1 = (point) tptr[5];
30721       p2 = (point) tptr[4];
30722     }
30723     p3 = (point) tptr[6];
30724     p4 = (point) tptr[7];
30725     n1 = pointmark(p1) - in->firstnumber;
30726     n2 = pointmark(p2) - in->firstnumber;
30727     n3 = pointmark(p3) - in->firstnumber;
30728     n4 = pointmark(p4) - in->firstnumber;
30729     fprintf(outfile, "%d  %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
30730     tptr = tetrahedrontraverse();
30731   }
30732   fprintf(outfile, "\n");
30733 
30734   fprintf(outfile, "CELL_TYPES %d\n", NEL);
30735   for(int tid=0; tid<NEL; tid++){
30736     fprintf(outfile, "%d\n", celltype);
30737   }
30738   fprintf(outfile, "\n");
30739 
30740   fclose(outfile);
30741 }
30742 
30743 ////                                                                       ////
30744 ////                                                                       ////
30745 //// output_cxx ///////////////////////////////////////////////////////////////
30746 
30747 //// main_cxx /////////////////////////////////////////////////////////////////
30748 ////                                                                       ////
30749 ////                                                                       ////
30750 
30751 ///////////////////////////////////////////////////////////////////////////////
30752 //                                                                           //
30753 // tetrahedralize()    The interface for users using TetGen library to       //
30754 //                     generate tetrahedral meshes with all features.        //
30755 //                                                                           //
30756 // The sequence is roughly as follows.  Many of these steps can be skipped,  //
30757 // depending on the command line switches.                                   //
30758 //                                                                           //
30759 // - Initialize constants and parse the command line.                        //
30760 // - Read the vertices from a file and either                                //
30761 //   - tetrahedralize them (no -r), or                                       //
30762 //   - read an old mesh from files and reconstruct it (-r).                  //
30763 // - Insert the boundary segments and facets (-p or -Y).                     //
30764 // - Read the holes (-p), regional attributes (-pA), and regional volume     //
30765 //   constraints (-pa).  Carve the holes and concavities, and spread the     //
30766 //   regional attributes and volume constraints.                             //
30767 // - Enforce the constraints on minimum quality bound (-q) and maximum       //
30768 //   volume (-a), and a mesh size function (-m).                             //
30769 // - Optimize the mesh wrt. specified quality measures (-O and -o).          //
30770 // - Write the output files and print the statistics.                        //
30771 // - Check the consistency of the mesh (-C).                                 //
30772 //                                                                           //
30773 ///////////////////////////////////////////////////////////////////////////////
30774 
tetrahedralize(tetgenbehavior * b,tetgenio * in,tetgenio * out,tetgenio * addin,tetgenio * bgmin)30775 void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
30776                     tetgenio *addin, tetgenio *bgmin)
30777 {
30778   tetgenmesh m;
30779   clock_t tv[10], ts[5]; // Timing informations (defined in time.h)
30780   REAL cps = (REAL) CLOCKS_PER_SEC;
30781 
30782   tv[0] = clock();
30783 
30784   m.b = b;
30785   m.in = in;
30786   m.addin = addin;
30787 
30788   if ((b->metric) && (bgmin->numberofpoints > 0)) {
30789     m.bgm = new tetgenmesh(); // Create an empty background mesh.
30790     m.bgm->b = b;
30791     m.bgm->in = bgmin;
30792   }
30793 
30794   m.initializepools();
30795   m.transfernodes();
30796 
30797 
30798   exactinit() ; // [bruno]
30799 /*
30800   exactinit(b->verbose, b->noexact, b->nostaticfilter,
30801             m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
30802 */
30803 
30804   tv[1] = clock();
30805 
30806   if (b->refine) {
30807     m.reconstructmesh();
30808   } else { // b->plc
30809     m.incrementaldelaunay(ts[0]);
30810   }
30811 
30812   tv[2] = clock();
30813 
30814   if (!b->quiet) {
30815     if (b->refine) {
30816       printf("Mesh reconstruction seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30817     } else {
30818       printf("Delaunay seconds:  %g\n", ((REAL)(tv[2]-tv[1])) / cps);
30819       if (b->verbose) {
30820         printf("  Point sorting seconds:  %g\n", ((REAL)(ts[0]-tv[1])) / cps);
30821       }
30822     }
30823   }
30824 
30825   if (b->plc) { // -p
30826     m.meshsurface();
30827 
30828     ts[0] = clock();
30829 
30830     if (!b->quiet) {
30831       printf("Surface mesh seconds:  %g\n", ((REAL)(ts[0]-tv[2])) / cps);
30832     }
30833 
30834     if (b->diagnose) { // -d
30835       m.detectinterfaces();
30836 
30837       ts[1] = clock();
30838 
30839       if (!b->quiet) {
30840         printf("Self-intersection seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30841       }
30842 
30843       // Only output when self-intersecting faces exist.
30844       if (m.subfaces->items > 0l) {
30845         m.outnodes(out);
30846         m.outsubfaces(out);
30847       }
30848 
30849       return;
30850     }
30851   }
30852 
30853   tv[3] = clock();
30854 
30855   if ((b->metric) && (m.bgm != nullptr)) { // -m
30856     m.bgm->initializepools();
30857     m.bgm->transfernodes();
30858     m.bgm->reconstructmesh();
30859 
30860     ts[0] = clock();
30861 
30862     if (!b->quiet) {
30863       printf("Background mesh reconstruct seconds:  %g\n",
30864              ((REAL)(ts[0] - tv[3])) / cps);
30865     }
30866 
30867     if (b->metric) { // -m
30868       m.interpolatemeshsize();
30869 
30870       ts[1] = clock();
30871 
30872       if (!b->quiet) {
30873         printf("Size interpolating seconds:  %g\n",((REAL)(ts[1]-ts[0])) / cps);
30874       }
30875     }
30876   }
30877 
30878   tv[4] = clock();
30879 
30880   if (b->plc) { // -p
30881     if (b->nobisect) { // -Y
30882       m.recoverboundary(ts[0]);
30883     } else {
30884       m.constraineddelaunay(ts[0]);
30885     }
30886 
30887     ts[1] = clock();
30888 
30889     if (!b->quiet) {
30890       printf("Boundary recovery seconds:  %g\n", ((REAL)(ts[1]-tv[4])) / cps);
30891       if (b->verbose) {
30892         printf("  Segment recovery seconds:  %g\n",((REAL)(ts[0]-tv[4]))/ cps);
30893         printf("  Facet recovery seconds:  %g\n", ((REAL)(ts[1]-ts[0])) / cps);
30894       }
30895     }
30896 
30897     m.carveholes();
30898 
30899     ts[2] = clock();
30900 
30901     if (!b->quiet) {
30902       printf("Exterior tets removal seconds:  %g\n",
30903              ((REAL)(ts[2]-ts[1])) / cps);
30904     }
30905 
30906     if (b->nobisect) { // -Y
30907       if (m.subvertstack->objects > 0l) {
30908         m.suppresssteinerpoints();
30909 
30910         ts[3] = clock();
30911 
30912         if (!b->quiet) {
30913           printf("Steiner suppression seconds:  %g\n",((REAL)(ts[3]-ts[2]))/cps);
30914         }
30915       } else {
30916         ts[3] = clock();
30917       }
30918 
30919       m.recoverdelaunay();
30920 
30921       ts[4] = clock();
30922 
30923       if (!b->quiet) {
30924         printf("Delaunay recovery seconds:  %g\n", ((REAL)(ts[4]-ts[3]))/cps);
30925       }
30926     }
30927   }
30928 
30929   tv[5] = clock();
30930 
30931   if ((b->plc || b->refine) && b->insertaddpoints) { // -i
30932     if ((addin != nullptr) && (addin->numberofpoints > 0)) {
30933       m.insertconstrainedpoints(addin);
30934     }
30935   }
30936 
30937   tv[6] = clock();
30938 
30939   if (!b->quiet) {
30940     if ((b->plc || b->refine) && b->insertaddpoints) {
30941       if ((addin != nullptr) && (addin->numberofpoints > 0)) {
30942         printf("Constrained points seconds:  %g\n", ((REAL)(tv[6]-tv[5]))/cps);
30943       }
30944     }
30945   }
30946 
30947 
30948   if (b->quality) {
30949       m.delaunayrefinement();
30950   }
30951 
30952   tv[7] = clock();
30953 
30954   if (!b->quiet) {
30955     if (b->quality) {
30956       printf("Refinement seconds:  %g\n", ((REAL)(tv[7] - tv[6])) / cps);
30957     }
30958   }
30959 
30960   if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) {
30961     m.optimizemesh();
30962   }
30963 
30964   tv[8] = clock();
30965 
30966   if (!b->quiet) {
30967     if ((b->plc || b->refine) && (b->optlevel > 0) && !b->conforming) {
30968       printf("Optimization seconds:  %g\n", ((REAL)(tv[8] - tv[7])) / cps);
30969     }
30970   }
30971 
30972   if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
30973       || (b->refine && (in->numberofcorners == 10)))) {
30974     m.jettisonnodes();
30975   }
30976 
30977   if ((b->order == 2) && !b->convex) {
30978     m.highorder();
30979   }
30980 
30981   if (!b->quiet) {
30982     printf("\n");
30983   }
30984 
30985   if (out != (tetgenio *) nullptr) {
30986     out->firstnumber = in->firstnumber;
30987     out->mesh_dim = in->mesh_dim;
30988   }
30989 
30990   if (b->nonodewritten || b->noiterationnum) {
30991     if (!b->quiet) {
30992       printf("NOT writing a .node file.\n");
30993     }
30994   } else {
30995     m.outnodes(out);
30996   }
30997 
30998   if (b->noelewritten) {
30999     if (!b->quiet) {
31000       printf("NOT writing an .ele file.\n");
31001     }
31002   } else {
31003     if (m.tetrahedrons->items > 0l) {
31004       m.outelements(out);
31005     }
31006   }
31007 
31008   if (b->nofacewritten) {
31009     if (!b->quiet) {
31010       printf("NOT writing an .face file.\n");
31011     }
31012   } else {
31013     if (b->facesout) {
31014       if (m.tetrahedrons->items > 0l) {
31015         m.outfaces(out);  // Output all faces.
31016       }
31017     } else {
31018       if (b->plc || b->refine) {
31019         if (m.subfaces->items > 0l) {
31020           m.outsubfaces(out); // Output boundary faces.
31021         }
31022       } else {
31023         if (m.tetrahedrons->items > 0l) {
31024           m.outhullfaces(out); // Output convex hull faces.
31025         }
31026       }
31027     }
31028   }
31029 
31030 
31031   if (b->nofacewritten) {
31032     if (!b->quiet) {
31033       printf("NOT writing an .edge file.\n");
31034     }
31035   } else {
31036     if (b->edgesout) { // -e
31037       m.outedges(out); // output all mesh edges.
31038     } else {
31039       if (b->plc || b->refine) {
31040         m.outsubsegments(out); // output subsegments.
31041       }
31042     }
31043   }
31044 
31045   if ((b->plc || b->refine) && b->metric) { // -m
31046     m.outmetrics(out);
31047   }
31048 
31049   if (!out && b->plc &&
31050       ((b->object == tetgenbehavior::OFF) ||
31051        (b->object == tetgenbehavior::PLY) ||
31052        (b->object == tetgenbehavior::STL))) {
31053     m.outsmesh(b->outfilename);
31054   }
31055 
31056   if (!out && b->meditview) {
31057     m.outmesh2medit(b->outfilename);
31058   }
31059 
31060 
31061   if (!out && b->vtkview) {
31062     m.outmesh2vtk(b->outfilename);
31063   }
31064 
31065   if (b->neighout) {
31066     m.outneighbors(out);
31067   }
31068 
31069   if ((!(b->plc || b->refine)) && b->voroout) {
31070     m.outvoronoi(out);
31071   }
31072 
31073 
31074   tv[9] = clock();
31075 
31076   if (!b->quiet) {
31077     printf("\nOutput seconds:  %g\n", ((REAL)(tv[9] - tv[8])) / cps);
31078     printf("Total running seconds:  %g\n", ((REAL)(tv[9] - tv[0])) / cps);
31079   }
31080 
31081   if (b->docheck) {
31082     m.checkmesh(0);
31083     if (b->plc || b->refine) {
31084       m.checkshells();
31085       m.checksegments();
31086     }
31087     if (b->docheck > 1) {
31088       m.checkdelaunay();
31089     }
31090   }
31091 
31092   if (!b->quiet) {
31093     m.statistics();
31094   }
31095 }
31096 
31097 #ifndef TETLIBRARY
31098 
31099 ///////////////////////////////////////////////////////////////////////////////
31100 //                                                                           //
31101 // main()    The entrance for running TetGen from command line.              //
31102 //                                                                           //
31103 ///////////////////////////////////////////////////////////////////////////////
31104 
main(int argc,char * argv[])31105 int main(int argc, char *argv[])
31106 
31107 #else // with TETLIBRARY
31108 
31109 ///////////////////////////////////////////////////////////////////////////////
31110 //                                                                           //
31111 // tetrahedralize()    The entrance for calling TetGen from another program. //
31112 //                                                                           //
31113 ///////////////////////////////////////////////////////////////////////////////
31114 
31115 void tetrahedralize(char *switches, tetgenio *in, tetgenio *out,
31116                     tetgenio *addin, tetgenio *bgmin)
31117 
31118 #endif // not TETLIBRARY
31119 
31120 {
31121   tetgenbehavior b;
31122 
31123 #ifndef TETLIBRARY
31124 
31125   tetgenio in, addin, bgmin;
31126 
31127   if (!b.parse_commandline(argc, argv)) {
31128     terminatetetgen(10);
31129   }
31130 
31131   // Read input files.
31132   if (b.refine) { // -r
31133     if (!in.load_tetmesh(b.infilename, (int) b.object)) {
31134       terminatetetgen(10);
31135     }
31136   } else { // -p
31137     if (!in.load_plc(b.infilename, (int) b.object)) {
31138       terminatetetgen(10);
31139     }
31140   }
31141   if (b.insertaddpoints) { // -i
31142     // Try to read a .a.node file.
31143     addin.load_node(b.addinfilename);
31144   }
31145   if (b.metric) { // -m
31146     // Try to read a background mesh in files .b.node, .b.ele.
31147     bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
31148   }
31149 
31150   tetrahedralize(&b, &in, nullptr, &addin, &bgmin);
31151 
31152   return 0;
31153 
31154 #else // with TETLIBRARY
31155 
31156   if (!b.parse_commandline(switches)) {
31157     terminatetetgen(10);
31158   }
31159   tetrahedralize(&b, in, out, addin, bgmin);
31160 
31161 #endif // not TETLIBRARY
31162 }
31163 
31164 ////                                                                       ////
31165 ////                                                                       ////
31166 //// main_cxx /////////////////////////////////////////////////////////////////
31167 
31168 } // [Bruno] namespace GEO_3rdParty
31169